From 17f1c61c9e3e3b0a9a2ab075f1b966eae706de67 Mon Sep 17 00:00:00 2001 From: Torsten Wierschin Date: Tue, 14 Jul 2026 12:07:36 +0200 Subject: [PATCH] Adds q2 repos to migrate --- CMakeLists.txt | 289 +++ TetraIF/CMakeLists.txt | 9 + TetraIF/CoPrtCnv/CMakeLists.txt | 30 + TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp | 82 + TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp | 60 + TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp | 240 ++ TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp | 32 + TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp | 52 + TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp | 52 + TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp | 1793 +++++++++++++ TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp | 604 +++++ .../CoPrtCnv/CoPrtCnvTelegramConverter.hpp | 57 + .../CoPrtCnvTelegramConverterNewIcd.cpp | 2131 ++++++++++++++++ TetraIF/CoPrtCnv/tetra_telegram_ids.h | 116 + TetraIF/LogView/CMakeLists.txt | 104 + TetraIF/LogView/Console/CMakeLists.txt | 17 + TetraIF/LogView/Console/main.cpp | 201 ++ TetraIF/LogView/IntegerCalculator.cpp | 497 ++++ TetraIF/LogView/IntegerCalculator.hpp | 143 ++ TetraIF/LogView/LogViewBooleanEdit.cpp | 36 + TetraIF/LogView/LogViewBooleanEdit.hpp | 19 + TetraIF/LogView/LogViewDateTimeEdit.cpp | 86 + TetraIF/LogView/LogViewDateTimeEdit.hpp | 40 + TetraIF/LogView/LogViewEnumEdit.cpp | 105 + TetraIF/LogView/LogViewEnumEdit.hpp | 43 + TetraIF/LogView/LogViewField.cpp | 275 ++ TetraIF/LogView/LogViewField.hpp | 142 ++ TetraIF/LogView/LogViewGui.cpp | 1013 ++++++++ TetraIF/LogView/LogViewGui.hpp | 189 ++ TetraIF/LogView/LogViewInjectionThread.cpp | 143 ++ TetraIF/LogView/LogViewInjectionThread.hpp | 79 + TetraIF/LogView/LogViewMain.cpp | 57 + TetraIF/LogView/LogViewModels.cpp | 548 ++++ TetraIF/LogView/LogViewModels.hpp | 109 + TetraIF/LogView/LogViewOptionDialog.cpp | 182 ++ TetraIF/LogView/LogViewOptionDialog.hpp | 77 + TetraIF/LogView/LogViewResources.qrc | 18 + TetraIF/LogView/LogViewSpinBox.cpp | 59 + TetraIF/LogView/LogViewSpinBox.hpp | 45 + TetraIF/LogView/LogViewTabWidget.cpp | 139 + TetraIF/LogView/LogViewTabWidget.hpp | 49 + TetraIF/LogView/LogViewTableWidget.cpp | 311 +++ TetraIF/LogView/LogViewTableWidget.hpp | 46 + TetraIF/LogView/LogViewTelegram.cpp | 1768 +++++++++++++ TetraIF/LogView/LogViewTelegram.hpp | 372 +++ TetraIF/LogView/LogViewTelegramDialog.cpp | 497 ++++ TetraIF/LogView/LogViewTelegramDialog.hpp | 77 + TetraIF/LogView/LogViewTelegramEdit.cpp | 586 +++++ TetraIF/LogView/LogViewTelegramEdit.hpp | 121 + TetraIF/LogView/LogViewTelegramEditModel.cpp | 163 ++ TetraIF/LogView/LogViewTelegramEditModel.hpp | 44 + .../LogViewTelegramSelectionDialog.cpp | 62 + .../LogViewTelegramSelectionDialog.hpp | 46 + .../LogView/LogViewTetraTelegramsParser.cpp | 516 ++++ .../LogView/LogViewTetraTelegramsParser.hpp | 89 + TetraIF/LogView/LogViewTextEdit.cpp | 96 + TetraIF/LogView/LogViewTextEdit.hpp | 40 + TetraIF/LogView/LogViewValueEdit.cpp | 135 + TetraIF/LogView/LogViewValueEdit.hpp | 44 + TetraIF/LogView/LogViewWidget.cpp | 230 ++ TetraIF/LogView/LogViewWidget.hpp | 84 + TetraIF/LogView/LogViewXdrElement.cpp | 61 + TetraIF/LogView/LogViewXdrElement.hpp | 62 + TetraIF/LogView/LogViewXdrParser.cpp | 1016 ++++++++ TetraIF/LogView/LogViewXdrParser.hpp | 183 ++ TetraIF/LogView/LogViewXdrStandardType.cpp | 84 + TetraIF/LogView/LogViewXdrStandardType.hpp | 117 + TetraIF/LogView/LogViewXdrStruct.cpp | 105 + TetraIF/LogView/LogViewXdrStruct.hpp | 60 + TetraIF/LogView/LogViewXdrType.cpp | 106 + TetraIF/LogView/LogViewXdrType.hpp | 72 + TetraIF/LogView/LogViewXdrValue.cpp | 40 + TetraIF/LogView/LogViewXdrValue.hpp | 34 + TetraIF/LogView/LogView_log4cxx.props | 17 + TetraIF/LogView/image/C2P.png | Bin 0 -> 287 bytes TetraIF/LogView/image/Central.png | Bin 0 -> 191 bytes TetraIF/LogView/image/GreenDarkLamp.png | Bin 0 -> 586 bytes TetraIF/LogView/image/GreenLamp.png | Bin 0 -> 534 bytes TetraIF/LogView/image/P2C.png | Bin 0 -> 275 bytes TetraIF/LogView/image/P2T.png | Bin 0 -> 288 bytes TetraIF/LogView/image/P2W.png | Bin 0 -> 188 bytes TetraIF/LogView/image/RedLamp.png | Bin 0 -> 801 bytes TetraIF/LogView/image/ShowSend.png | Bin 0 -> 382 bytes TetraIF/LogView/image/T2P.png | Bin 0 -> 278 bytes TetraIF/LogView/image/TNE.png | Bin 0 -> 253 bytes TetraIF/LogView/image/Tetra.png | Bin 0 -> 307 bytes TetraIF/LogView/image/W2P.png | Bin 0 -> 186 bytes TetraIF/LogView/image/Wls.png | Bin 0 -> 191 bytes TetraIF/LogView/image/YellowDarkLamp.png | Bin 0 -> 586 bytes TetraIF/LogView/image/YellowLamp.png | Bin 0 -> 543 bytes TetraIF/LogView/logger.cpp | 32 + TetraIF/LogView/logger.h | 17 + TetraIF/LogView/zsksxd_tetraForLogView.cpp | 1 + TetraIF/LogView/zsksxd_tetraForLogView.x | 1834 +++++++++++++ .../LogView/zsksxd_tetraForLogView_guez.cpp | 1 + TetraIF/LogView/zsksxd_tetraForLogView_guez.x | 1839 +++++++++++++ TetraIF/PrtCnv/AppComponent.cpp | 88 + TetraIF/PrtCnv/AppComponent.hpp | 45 + TetraIF/PrtCnv/CMakeLists.txt | 78 + TetraIF/PrtCnv/IAppComponent.hpp | 59 + TetraIF/PrtCnv/LastTest/CMakeLists.txt | 21 + TetraIF/PrtCnv/LastTest/main.cpp | 62 + TetraIF/PrtCnv/LastTest/tetra_if.cpp | 503 ++++ TetraIF/PrtCnv/LastTest/tetra_if.h | 61 + .../PrtCnv/LastTestAuswertung/CMakeLists.txt | 25 + .../LastTestAuswertung/LastTestAuswertung.pro | 16 + TetraIF/PrtCnv/LastTestAuswertung/main.cpp | 10 + .../PrtCnv/LastTestAuswertung/mainwindow.cpp | 428 ++++ .../PrtCnv/LastTestAuswertung/mainwindow.h | 69 + .../PrtCnv/LastTestAuswertung/mainwindow.ui | 123 + TetraIF/PrtCnv/PrtCnv.dat.tts | 90 + TetraIF/PrtCnv/PrtCnvApplication.cpp | 410 +++ TetraIF/PrtCnv/PrtCnvApplication.hpp | 180 ++ TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp | 1709 +++++++++++++ TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp | 359 +++ TetraIF/PrtCnv/PrtCnvCentralThread.cpp | 842 ++++++ TetraIF/PrtCnv/PrtCnvCentralThread.hpp | 238 ++ TetraIF/PrtCnv/PrtCnvDbThread.cpp | 1647 ++++++++++++ TetraIF/PrtCnv/PrtCnvDbThread.hpp | 371 +++ TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp | 127 + TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp | 66 + TetraIF/PrtCnv/PrtCnvInjectionThread.cpp | 182 ++ TetraIF/PrtCnv/PrtCnvInjectionThread.hpp | 101 + TetraIF/PrtCnv/PrtCnvMain.cpp | 124 + TetraIF/PrtCnv/PrtCnvMember.cpp | 98 + TetraIF/PrtCnv/PrtCnvMember.hpp | 84 + TetraIF/PrtCnv/PrtCnvRadioThread.cpp | 2267 +++++++++++++++++ TetraIF/PrtCnv/PrtCnvRadioThread.hpp | 419 +++ TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp | 208 ++ TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp | 82 + TetraIF/PrtCnv/PrtCnvSocketThread.cpp | 382 +++ TetraIF/PrtCnv/PrtCnvSocketThread.hpp | 190 ++ .../PrtCnv/PrtCnvStoredCentralTelegram.hpp | 39 + TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp | 32 + TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp | 23 + TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp | 182 ++ TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp | 87 + TetraIF/PrtCnv/PrtCnvThread.cpp | 74 + TetraIF/PrtCnv/PrtCnvThread.hpp | 71 + TetraIF/PrtCnv/PrtCnvThreadStarter.cpp | 125 + TetraIF/PrtCnv/PrtCnvThreadStarter.hpp | 68 + TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt | 29 + .../log4cxx_tetratestserver.props | 81 + TetraIF/PrtCnv/TetraTestServer/main.cpp | 188 ++ TetraIF/PrtCnv/TetraTestServer/server.cpp | 38 + TetraIF/PrtCnv/TetraTestServer/server.h | 54 + TetraIF/PrtCnv/TetraTestServer/tts.txt | 111 + TetraIF/PrtCnv/TetraTestServer/worker.cpp | 645 +++++ TetraIF/PrtCnv/TetraTestServer/worker.h | 128 + TetraIF/PrtCnv/log4cxx_prtcnv.props | 49 + TetraIF/PrtCnv/logger.cpp | 30 + TetraIF/PrtCnv/logger.h | 18 + Z/src/CMakeLists.txt | 17 + Z/src/NGLLogger/CMakeLists.txt | 50 + Z/src/NGLLogger/INGLLogger.h | 306 +++ Z/src/NGLLogger/MurmurHash2.cpp | 77 + Z/src/NGLLogger/MurmurHash2.h | 9 + Z/src/NGLLogger/NGLLogger.cpp | 446 ++++ Z/src/NGLLogger/NGLLogger.h | 94 + Z/src/NGLLogger/NGLLoggerBootstrap.cpp | 30 + Z/src/NGLLogger/NGLLoggerBootstrap.h | 59 + Z/src/NGLLogger/NGLLogger_export.h | 22 + Z/src/NGLLogger/log4cxx.props | 42 + Z/src/NGLLogger/test_ngllogger.cpp | 34 + Z/src/QtSingleApplication/CMakeLists.txt | 51 + Z/src/QtSingleApplication/QtLockedFile | 1 + Z/src/QtSingleApplication/QtSingleApplication | 1 + .../QtSingleCoreApplication | 1 + Z/src/QtSingleApplication/qtlocalpeer.cpp | 167 ++ Z/src/QtSingleApplication/qtlocalpeer.h | 40 + Z/src/QtSingleApplication/qtlockedfile.cpp | 68 + Z/src/QtSingleApplication/qtlockedfile.h | 61 + .../QtSingleApplication/qtlockedfile_unix.cpp | 78 + .../QtSingleApplication/qtlockedfile_win.cpp | 174 ++ .../qtsingleapplication.cpp | 104 + .../QtSingleApplication/qtsingleapplication.h | 56 + .../qtsinglecoreapplication.cpp | 60 + .../qtsinglecoreapplication.h | 46 + Z/src/WMS_Interface/CMakeLists.txt | 35 + Z/src/WMS_Interface/IECC2WMS.h | 20 + Z/src/WMS_Interface/IWMS2ECC.h | 137 + Z/src/WMS_Interface/json_keys.h | 52 + .../wms_ecc_equipRequirements.cpp | 71 + .../WMS_Interface/wms_ecc_equipRequirements.h | 30 + .../WMS_Interface/wms_ecc_equipmenttypes.cpp | 132 + Z/src/WMS_Interface/wms_ecc_equipmenttypes.h | 37 + Z/src/WMS_Interface/wms_ecc_exercises.cpp | 135 + Z/src/WMS_Interface/wms_ecc_exercises.h | 41 + Z/src/WMS_Interface/wms_ecc_ibase.h | 15 + Z/src/WMS_Interface/wms_ecc_playerInfo.cpp | 176 ++ Z/src/WMS_Interface/wms_ecc_playerInfo.h | 40 + Z/src/WMS_Interface/wms_ecc_registration.cpp | 89 + Z/src/WMS_Interface/wms_ecc_registration.h | 55 + Z/src/WMS_Interface/wms_ecc_unregister.cpp | 50 + Z/src/WMS_Interface/wms_ecc_unregister.h | 32 + Z/src/nglapplication/CMakeLists.txt | 134 + Z/src/nglapplication/ngl_qt_msg_handler.inc | 64 + Z/src/nglapplication/ngl_signal_handler.inc | 41 + Z/src/nglapplication/nglapplication.cpp | 31 + Z/src/nglapplication/nglapplication.h | 36 + Z/src/nglapplication/nglcoreapplication.cpp | 17 + Z/src/nglapplication/nglcoreapplication.h | 31 + Z/src/nglapplication/nglguiapplication.cpp | 17 + Z/src/nglapplication/nglguiapplication.h | 33 + Z/src/nglapplication/nglloggerhandler.cpp | 91 + Z/src/nglapplication/nglloggerhandler.h | 67 + Z/src/nglapplication/nglsingleapplication.cpp | 32 + Z/src/nglapplication/nglsingleapplication.h | 36 + .../nglsinglecoreapplication.cpp | 17 + .../nglapplication/nglsinglecoreapplication.h | 31 + Z/src/nglcompression/CMakeLists.txt | 47 + .../nglcompression/nglcomp_bzip2iodevice.cpp | 360 +++ Z/src/nglcompression/nglcomp_bzip2iodevice.h | 42 + Z/src/nglcompression/nglcomp_compress.cpp | 566 ++++ Z/src/nglcompression/nglcomp_compress.h | 140 + Z/src/nglcompression/nglcomp_export.h | 17 + Z/src/nglcompression/nglcomp_tarfilter.cpp | 525 ++++ Z/src/nglcompression/nglcomp_tarfilter.h | 82 + Z/src/nglcompression/nglcomp_test.cpp | 175 ++ Z/src/nglcompression/nglcomp_test.h | 36 + Z/src/ngldb/CMakeLists.txt | 45 + Z/src/ngldb/db_service_handler.h | 58 + Z/src/ngldb/dbcommon.h | 41 + Z/src/ngldb/dbconnection.cpp | 68 + Z/src/ngldb/dbconnection.h | 24 + Z/src/ngldb/dbtransaction.cpp | 82 + Z/src/ngldb/dbtransaction.h | 48 + Z/src/ngldb/ngldb_export.h | 17 + Z/src/ngldb/ngldb_logger.cpp | 24 + Z/src/ngldb/ngldb_logger.h | 31 + Z/src/ngldb/nsqlquery.cpp | 457 ++++ Z/src/ngldb/nsqlquery.h | 222 ++ Z/src/ngldb/sql_query_janitor.cpp | 24 + Z/src/ngldb/sql_query_janitor.h | 22 + Z/src/nglsettings/CMakeLists.txt | 32 + Z/src/nglsettings/nglsettings_connections.cpp | 175 ++ Z/src/nglsettings/nglsettings_connections.h | 59 + Z/src/nglsettings/nglsettings_export.h | 17 + Z/src/nglsettings/nglsettings_settings.cpp | 320 +++ Z/src/nglsettings/nglsettings_settings.h | 142 ++ Z/src/ngltools/CMakeLists.txt | 34 + Z/src/ngltools/ngltools_bitset.h | 100 + Z/src/ngltools/ngltools_convert.cpp | 91 + Z/src/ngltools/ngltools_convert.h | 23 + Z/src/ngltools/ngltools_dtg.cpp | 372 +++ Z/src/ngltools/ngltools_dtg.h | 87 + Z/src/ngltools/ngltools_export.h | 19 + Z/src/ngltools/ngltools_filesystem.cpp | 289 +++ Z/src/ngltools/ngltools_filesystem.h | 38 + Z/src/ngltools/ngltools_helpevent.cpp | 19 + Z/src/ngltools/ngltools_helpevent.h | 34 + Z/src/ngltranslator/CMakeLists.txt | 22 + Z/src/ngltranslator/ngltranslator.cpp | 222 ++ Z/src/ngltranslator/ngltranslator.h | 40 + Z/src/ngltranslator/ngltranslator_export.h | 19 + Z/src/ngltranslator/ngltranslator_p.h | 34 + Z/src/nglwidgets/CMakeLists.txt | 52 + Z/src/nglwidgets/icons/16x16/LICENSE | 24 + .../icons/16x16/application-pdf.png | Bin 0 -> 688 bytes Z/src/nglwidgets/icons/16x16/arrow-left.png | Bin 0 -> 512 bytes Z/src/nglwidgets/icons/16x16/arrow-right.png | Bin 0 -> 527 bytes .../icons/16x16/audio-x-generic.png | Bin 0 -> 643 bytes Z/src/nglwidgets/icons/16x16/bg.gif | Bin 0 -> 958 bytes Z/src/nglwidgets/icons/16x16/camera-photo.png | Bin 0 -> 372 bytes Z/src/nglwidgets/icons/16x16/configure.png | Bin 0 -> 717 bytes Z/src/nglwidgets/icons/16x16/dialog-close.png | Bin 0 -> 813 bytes .../icons/16x16/dialog-ok-apply.png | Bin 0 -> 597 bytes Z/src/nglwidgets/icons/16x16/dialog-ok.png | Bin 0 -> 601 bytes Z/src/nglwidgets/icons/16x16/dirs.png | Bin 0 -> 1049 bytes .../nglwidgets/icons/16x16/document-edit.png | Bin 0 -> 726 bytes .../icons/16x16/document-import.png | Bin 0 -> 609 bytes Z/src/nglwidgets/icons/16x16/document-new.png | Bin 0 -> 579 bytes .../icons/16x16/document-open-data.png | Bin 0 -> 611 bytes .../nglwidgets/icons/16x16/document-open.png | Bin 0 -> 531 bytes .../icons/16x16/document-preview.png | Bin 0 -> 808 bytes .../nglwidgets/icons/16x16/document-print.png | Bin 0 -> 619 bytes .../icons/16x16/document-properties.png | Bin 0 -> 668 bytes .../icons/16x16/document-save-all.png | Bin 0 -> 635 bytes .../icons/16x16/document-save-as.png | Bin 0 -> 839 bytes .../nglwidgets/icons/16x16/document-save.png | Bin 0 -> 563 bytes Z/src/nglwidgets/icons/16x16/download.png | Bin 0 -> 901 bytes .../icons/16x16/draw-bezier-curves.png | Bin 0 -> 540 bytes Z/src/nglwidgets/icons/16x16/draw-ellipse.png | Bin 0 -> 587 bytes Z/src/nglwidgets/icons/16x16/draw-line.png | Bin 0 -> 352 bytes Z/src/nglwidgets/icons/16x16/draw-polygon.png | Bin 0 -> 679 bytes .../nglwidgets/icons/16x16/draw-polyline.png | Bin 0 -> 529 bytes .../nglwidgets/icons/16x16/draw-rectangle.png | Bin 0 -> 360 bytes Z/src/nglwidgets/icons/16x16/draw-text.png | Bin 0 -> 465 bytes .../16x16/edit-clear-locationbar-rtl.png | Bin 0 -> 644 bytes Z/src/nglwidgets/icons/16x16/edit-copy.png | Bin 0 -> 485 bytes Z/src/nglwidgets/icons/16x16/edit-cut.png | Bin 0 -> 368 bytes Z/src/nglwidgets/icons/16x16/edit-delete.png | Bin 0 -> 641 bytes Z/src/nglwidgets/icons/16x16/edit-paste.png | Bin 0 -> 529 bytes Z/src/nglwidgets/icons/16x16/edit-redo.png | Bin 0 -> 813 bytes Z/src/nglwidgets/icons/16x16/edit-rename.png | Bin 0 -> 245 bytes Z/src/nglwidgets/icons/16x16/edit-select.png | Bin 0 -> 368 bytes Z/src/nglwidgets/icons/16x16/edit-undo.png | Bin 0 -> 866 bytes Z/src/nglwidgets/icons/16x16/fill-color.png | Bin 0 -> 985 bytes .../icons/16x16/format-justify-center.png | Bin 0 -> 272 bytes .../icons/16x16/format-justify-fill.png | Bin 0 -> 230 bytes .../icons/16x16/format-justify-left.png | Bin 0 -> 264 bytes .../icons/16x16/format-justify-right.png | Bin 0 -> 266 bytes .../icons/16x16/format-stroke-color.png | Bin 0 -> 822 bytes .../icons/16x16/format-text-bold.png | Bin 0 -> 463 bytes .../icons/16x16/format-text-italic.png | Bin 0 -> 332 bytes .../icons/16x16/format-text-underline.png | Bin 0 -> 392 bytes Z/src/nglwidgets/icons/16x16/freu.gif | Bin 0 -> 375 bytes Z/src/nglwidgets/icons/16x16/go-down.png | Bin 0 -> 623 bytes Z/src/nglwidgets/icons/16x16/go-home.png | Bin 0 -> 935 bytes Z/src/nglwidgets/icons/16x16/go-next.png | Bin 0 -> 721 bytes Z/src/nglwidgets/icons/16x16/go-previous.png | Bin 0 -> 634 bytes Z/src/nglwidgets/icons/16x16/go-up.png | Bin 0 -> 672 bytes Z/src/nglwidgets/icons/16x16/help-about.png | Bin 0 -> 734 bytes .../nglwidgets/icons/16x16/help-contents.png | Bin 0 -> 684 bytes .../icons/16x16/image-x-generic.png | Bin 0 -> 680 bytes .../nglwidgets/icons/16x16/internet-mail.png | Bin 0 -> 755 bytes Z/src/nglwidgets/icons/16x16/led-blue-on.png | Bin 0 -> 763 bytes Z/src/nglwidgets/icons/16x16/led-gray-on.png | Bin 0 -> 695 bytes Z/src/nglwidgets/icons/16x16/led-green-on.png | Bin 0 -> 815 bytes Z/src/nglwidgets/icons/16x16/led-red-on.png | Bin 0 -> 737 bytes .../nglwidgets/icons/16x16/led-yellow-on.png | Bin 0 -> 934 bytes .../nglwidgets/icons/16x16/list-add-user.png | Bin 0 -> 690 bytes Z/src/nglwidgets/icons/16x16/list-add.png | Bin 0 -> 564 bytes .../icons/16x16/list-remove-user.png | Bin 0 -> 707 bytes Z/src/nglwidgets/icons/16x16/list-remove.png | Bin 0 -> 332 bytes .../nglwidgets/icons/16x16/mail-mark-read.png | Bin 0 -> 680 bytes .../icons/16x16/mail-mark-unread.png | Bin 0 -> 472 bytes .../icons/16x16/mail-message-new.png | Bin 0 -> 967 bytes Z/src/nglwidgets/icons/16x16/mail-send.png | Bin 0 -> 1179 bytes Z/src/nglwidgets/icons/16x16/media-eject.png | Bin 0 -> 502 bytes Z/src/nglwidgets/icons/16x16/media-flash.png | Bin 0 -> 740 bytes .../icons/16x16/media-play-faster.png | Bin 0 -> 909 bytes .../icons/16x16/media-play-normal.png | Bin 0 -> 918 bytes .../icons/16x16/media-play-slower.png | Bin 0 -> 962 bytes .../icons/16x16/media-playback-pause.png | Bin 0 -> 484 bytes .../icons/16x16/media-playback-start.png | Bin 0 -> 501 bytes .../icons/16x16/media-playback-stop.png | Bin 0 -> 499 bytes Z/src/nglwidgets/icons/16x16/media-record.png | Bin 0 -> 735 bytes .../icons/16x16/media-seek-backward.png | Bin 0 -> 505 bytes .../icons/16x16/media-seek-forward.png | Bin 0 -> 506 bytes .../icons/16x16/media-skip-backward.png | Bin 0 -> 511 bytes .../icons/16x16/media-skip-forward.png | Bin 0 -> 506 bytes Z/src/nglwidgets/icons/16x16/oO.gif | Bin 0 -> 1623 bytes Z/src/nglwidgets/icons/16x16/object-group.png | Bin 0 -> 320 bytes .../nglwidgets/icons/16x16/object-ungroup.png | Bin 0 -> 348 bytes Z/src/nglwidgets/icons/16x16/ooo-calc.png | Bin 0 -> 986 bytes Z/src/nglwidgets/icons/16x16/ooo-impress.png | Bin 0 -> 651 bytes Z/src/nglwidgets/icons/16x16/ooo-writer.png | Bin 0 -> 796 bytes .../nglwidgets/icons/16x16/player_status.png | Bin 0 -> 196 bytes .../icons/16x16/preferences-desktop-font.png | Bin 0 -> 708 bytes .../16x16/preferences-web-browser-cache.png | Bin 0 -> 835 bytes Z/src/nglwidgets/icons/16x16/printer.png | Bin 0 -> 630 bytes Z/src/nglwidgets/icons/16x16/process-stop.png | Bin 0 -> 722 bytes Z/src/nglwidgets/icons/16x16/rde.ico | Bin 0 -> 30166 bytes Z/src/nglwidgets/icons/16x16/rde_16x16.png | Bin 0 -> 430 bytes Z/src/nglwidgets/icons/16x16/system-help.png | Bin 0 -> 897 bytes Z/src/nglwidgets/icons/16x16/text-plain.png | Bin 0 -> 609 bytes .../nglwidgets/icons/16x16/transform-move.png | Bin 0 -> 875 bytes .../icons/16x16/transform-rotate.png | Bin 0 -> 558 bytes .../icons/16x16/transform-scale.png | Bin 0 -> 509 bytes Z/src/nglwidgets/icons/16x16/traurig.gif | Bin 0 -> 1591 bytes .../icons/16x16/video-x-generic.png | Bin 0 -> 721 bytes .../icons/16x16/view-fullscreen.png | Bin 0 -> 624 bytes .../icons/16x16/view-statistics.png | Bin 0 -> 495 bytes Z/src/nglwidgets/icons/16x16/weinend.gif | Bin 0 -> 202 bytes .../icons/16x16/x-office-address-book.png | Bin 0 -> 561 bytes .../nglwidgets/icons/16x16/yellow-off-16.png | Bin 0 -> 779 bytes Z/src/nglwidgets/icons/16x16/yellow-on-16.png | Bin 0 -> 937 bytes Z/src/nglwidgets/icons/16x16/zoom-in.png | Bin 0 -> 791 bytes Z/src/nglwidgets/icons/16x16/zoom-out.png | Bin 0 -> 786 bytes Z/src/nglwidgets/icons/16x16/zunge.gif | Bin 0 -> 377 bytes Z/src/nglwidgets/icons/16x16/zwinker.gif | Bin 0 -> 170 bytes .../icons/22x22/dialogbuttonbox.png | Bin 0 -> 1003 bytes Z/src/nglwidgets/icons/22x22/edit-redo.png | Bin 0 -> 1245 bytes .../icons/22x22/format-justify-center.png | Bin 0 -> 313 bytes .../icons/22x22/format-justify-fill.png | Bin 0 -> 261 bytes .../icons/22x22/format-justify-left.png | Bin 0 -> 314 bytes .../icons/22x22/format-justify-right.png | Bin 0 -> 313 bytes .../icons/22x22/format-stroke-color.png | Bin 0 -> 1230 bytes .../icons/22x22/format-text-bold.png | Bin 0 -> 667 bytes .../icons/22x22/format-text-italic.png | Bin 0 -> 630 bytes .../icons/22x22/format-text-underline.png | Bin 0 -> 537 bytes Z/src/nglwidgets/icons/22x22/kdialog.png | Bin 0 -> 1045 bytes Z/src/nglwidgets/icons/22x22/klineedit.png | Bin 0 -> 1163 bytes Z/src/nglwidgets/icons/22x22/layer.png | Bin 0 -> 570 bytes Z/src/nglwidgets/icons/22x22/lkm_einsatz.png | Bin 0 -> 165 bytes Z/src/nglwidgets/icons/22x22/pushbutton.png | Bin 0 -> 408 bytes Z/src/nglwidgets/icons/22x22/scricon.png | Bin 0 -> 291 bytes Z/src/nglwidgets/icons/32x32/database.png | Bin 0 -> 1484 bytes .../icons/32x32/hand_grenade_locations.png | Bin 0 -> 949 bytes Z/src/nglwidgets/icons/32x32/hideshow.png | Bin 0 -> 3187 bytes Z/src/nglwidgets/icons/32x32/marker-end.png | Bin 0 -> 508 bytes Z/src/nglwidgets/icons/32x32/marker-start.png | Bin 0 -> 446 bytes Z/src/nglwidgets/icons/32x32/media-eject.png | Bin 0 -> 1197 bytes .../icons/32x32/media-play-backward.png | Bin 0 -> 1138 bytes .../icons/32x32/media-play-faster.png | Bin 0 -> 2335 bytes .../icons/32x32/media-play-faster.svg | 0 .../icons/32x32/media-play-normal.png | Bin 0 -> 2267 bytes .../icons/32x32/media-play-normal.svg | 0 .../icons/32x32/media-play-slower.png | Bin 0 -> 2298 bytes .../icons/32x32/media-play-slower.svg | 0 .../icons/32x32/media-play-slower.svg.png | Bin 0 -> 2414 bytes .../icons/32x32/media-playback-pause.png | Bin 0 -> 1145 bytes .../32x32/media-playback-start-single.png | Bin 0 -> 1205 bytes .../icons/32x32/media-playback-start.png | Bin 0 -> 1177 bytes .../icons/32x32/media-playback-stop.png | Bin 0 -> 1165 bytes Z/src/nglwidgets/icons/32x32/media-record.png | Bin 0 -> 1843 bytes .../icons/32x32/media-seek-backward.png | Bin 0 -> 1207 bytes .../icons/32x32/media-seek-forward.png | Bin 0 -> 1220 bytes .../icons/32x32/media-skip-backward.png | Bin 0 -> 1211 bytes .../icons/32x32/media-skip-forward.png | Bin 0 -> 1209 bytes .../icons/32x32/media-vcr-nopause.png | Bin 0 -> 251 bytes .../icons/32x32/media-vcr-normal.png | Bin 0 -> 503 bytes .../icons/32x32/media-vcr-repeat.png | Bin 0 -> 815 bytes .../icons/32x32/media-vcr-withpause.png | Bin 0 -> 388 bytes .../icons/32x32/service_message.png | Bin 0 -> 3209 bytes Z/src/nglwidgets/icons/32x32/showhide.png | Bin 0 -> 3079 bytes Z/src/nglwidgets/icons/32x32/wireless.png | Bin 0 -> 3651 bytes Z/src/nglwidgets/icons/LICENSE | 24 + Z/src/nglwidgets/icons/png/add.png | Bin 0 -> 1312 bytes Z/src/nglwidgets/icons/png/add_disabled.png | Bin 0 -> 1173 bytes .../icons/png/add_tactical_sign_act.png | Bin 0 -> 1906 bytes .../png/add_tactical_sign_act_disabled.png | Bin 0 -> 1514 bytes Z/src/nglwidgets/icons/png/add_text_act.png | Bin 0 -> 1385 bytes .../icons/png/add_text_act_disabled.png | Bin 0 -> 1270 bytes Z/src/nglwidgets/icons/png/address_book.png | Bin 0 -> 575 bytes .../nglwidgets/icons/png/big_letters_act.png | Bin 0 -> 1610 bytes .../icons/png/big_letters_act_disabled.png | Bin 0 -> 1363 bytes .../icons/png/camera_arrow_down.png | Bin 0 -> 771 bytes .../icons/png/camera_arrow_left.png | Bin 0 -> 791 bytes .../icons/png/camera_arrow_right.png | Bin 0 -> 786 bytes .../nglwidgets/icons/png/camera_arrow_up.png | Bin 0 -> 756 bytes .../icons/png/center_object_in_map_act.png | Bin 0 -> 1588 bytes .../png/center_object_in_map_act_disabled.png | Bin 0 -> 1412 bytes Z/src/nglwidgets/icons/png/clear_plan_act.png | Bin 0 -> 2189 bytes .../icons/png/clear_plan_act_disabled.png | Bin 0 -> 1573 bytes Z/src/nglwidgets/icons/png/copy_exercise.png | Bin 0 -> 1589 bytes .../icons/png/copy_exercise_disabled.png | Bin 0 -> 1224 bytes Z/src/nglwidgets/icons/png/delete.png | Bin 0 -> 2507 bytes .../nglwidgets/icons/png/delete_disabled.png | Bin 0 -> 1539 bytes .../nglwidgets/icons/png/delete_exercise.png | Bin 0 -> 2115 bytes .../icons/png/delete_exercise_disabled.png | Bin 0 -> 1568 bytes .../icons/png/delete_graphic_eass.png | Bin 0 -> 1594 bytes .../png/delete_graphic_eass_disabled.png | Bin 0 -> 1359 bytes Z/src/nglwidgets/icons/png/deleteall.png | Bin 0 -> 935 bytes Z/src/nglwidgets/icons/png/download.png | Bin 0 -> 637 bytes .../nglwidgets/icons/png/draw_ellipse_act.png | Bin 0 -> 2040 bytes .../icons/png/draw_ellipse_act_disabled.png | Bin 0 -> 1766 bytes Z/src/nglwidgets/icons/png/draw_line.png | Bin 0 -> 560 bytes .../icons/png/draw_line_disabled.png | Bin 0 -> 591 bytes .../nglwidgets/icons/png/draw_polygon_act.png | Bin 0 -> 1805 bytes .../icons/png/draw_polygon_act_disabled.png | Bin 0 -> 1589 bytes .../icons/png/draw_rectangle_act.png | Bin 0 -> 1723 bytes .../icons/png/draw_rectangle_act_disabled.png | Bin 0 -> 1362 bytes Z/src/nglwidgets/icons/png/draw_spline.png | Bin 0 -> 1749 bytes .../icons/png/draw_spline_disabled.png | Bin 0 -> 1378 bytes Z/src/nglwidgets/icons/png/eass_line.png | Bin 0 -> 1553 bytes .../icons/png/eass_line_disabled.png | Bin 0 -> 1616 bytes Z/src/nglwidgets/icons/png/eass_polygon.png | Bin 0 -> 1707 bytes .../icons/png/eass_polygon_disabled.png | Bin 0 -> 1681 bytes .../nglwidgets/icons/png/edit_element_act.png | Bin 0 -> 1676 bytes .../icons/png/edit_element_act_disabled.png | Bin 0 -> 1499 bytes .../icons/png/edith_graphic_eass.png | Bin 0 -> 1549 bytes .../icons/png/edith_graphic_eass_disabled.png | Bin 0 -> 1237 bytes Z/src/nglwidgets/icons/png/fast_playback.png | Bin 0 -> 1826 bytes .../icons/png/fast_playback_backward.png | Bin 0 -> 1102 bytes .../png/fast_playback_backward_disabled.png | Bin 0 -> 602 bytes .../icons/png/fast_playback_disabled.png | Bin 0 -> 1340 bytes .../nglwidgets/icons/png/fill_colour_act.png | Bin 0 -> 1303 bytes .../icons/png/fill_colour_act_disabled.png | Bin 0 -> 1139 bytes Z/src/nglwidgets/icons/png/folder_open.png | Bin 0 -> 681 bytes .../icons/png/kosy_audio_control_act.png | Bin 0 -> 1958 bytes .../png/kosy_audio_control_act_disabled.png | Bin 0 -> 1756 bytes .../icons/png/kosy_radio_error_act.png | Bin 0 -> 2473 bytes .../png/kosy_radio_error_act_disabled.png | Bin 0 -> 2160 bytes .../icons/png/kosy_remote_control_act.png | Bin 0 -> 2730 bytes .../png/kosy_remote_control_act_disabled.png | Bin 0 -> 1805 bytes Z/src/nglwidgets/icons/png/line_color.png | Bin 0 -> 822 bytes Z/src/nglwidgets/icons/png/marker_left.png | Bin 0 -> 1911 bytes .../icons/png/marker_left_disabled.png | Bin 0 -> 1317 bytes Z/src/nglwidgets/icons/png/marker_right.png | Bin 0 -> 1926 bytes .../icons/png/marker_right_disabled.png | Bin 0 -> 1329 bytes Z/src/nglwidgets/icons/png/messages_new.png | Bin 0 -> 1061 bytes Z/src/nglwidgets/icons/png/missionmarch.png | Bin 0 -> 1431 bytes .../icons/png/missionmarch_disabled.png | Bin 0 -> 1206 bytes .../icons/png/normal_letters_act.png | Bin 0 -> 1485 bytes .../icons/png/normal_letters_act_disabled.png | Bin 0 -> 1274 bytes Z/src/nglwidgets/icons/png/ok.png | Bin 0 -> 1825 bytes Z/src/nglwidgets/icons/png/ok_disabled.png | Bin 0 -> 1448 bytes Z/src/nglwidgets/icons/png/paste_exercise.png | Bin 0 -> 1793 bytes .../icons/png/paste_exercise_disabled.png | Bin 0 -> 1305 bytes Z/src/nglwidgets/icons/png/pause_playback.png | Bin 0 -> 1187 bytes .../icons/png/pause_playback_disabled.png | Bin 0 -> 1090 bytes Z/src/nglwidgets/icons/png/polygonmap.png | Bin 0 -> 1527 bytes .../icons/png/polygonmap_disabled.png | Bin 0 -> 1532 bytes Z/src/nglwidgets/icons/png/position_map.png | Bin 0 -> 2361 bytes .../icons/png/position_map_disabled.png | Bin 0 -> 1681 bytes Z/src/nglwidgets/icons/png/preview.png | Bin 0 -> 1201 bytes Z/src/nglwidgets/icons/png/printer.png | Bin 0 -> 667 bytes Z/src/nglwidgets/icons/png/redo.png | Bin 0 -> 2040 bytes Z/src/nglwidgets/icons/png/redo_disabled.png | Bin 0 -> 1537 bytes Z/src/nglwidgets/icons/png/remove.png | Bin 0 -> 1134 bytes .../nglwidgets/icons/png/remove_disabled.png | Bin 0 -> 1080 bytes .../nglwidgets/icons/png/rename_exercise.png | Bin 0 -> 1921 bytes .../icons/png/rename_exercise_disabled.png | Bin 0 -> 1539 bytes Z/src/nglwidgets/icons/png/save.png | Bin 0 -> 595 bytes Z/src/nglwidgets/icons/png/save_as.png | Bin 0 -> 938 bytes Z/src/nglwidgets/icons/png/settings.png | Bin 0 -> 2200 bytes .../icons/png/settings_disabled.png | Bin 0 -> 1597 bytes Z/src/nglwidgets/icons/png/start_playback.png | Bin 0 -> 1558 bytes .../icons/png/start_playback_disabled.png | Bin 0 -> 1287 bytes Z/src/nglwidgets/icons/png/stop.png | Bin 0 -> 1720 bytes Z/src/nglwidgets/icons/png/stop_disabled.png | Bin 0 -> 1702 bytes Z/src/nglwidgets/icons/png/stop_playback.png | Bin 0 -> 1135 bytes .../icons/png/stop_playback_disabled.png | Bin 0 -> 1066 bytes Z/src/nglwidgets/icons/png/thick_line_act.png | Bin 0 -> 1079 bytes .../icons/png/thick_line_act_disabled.png | Bin 0 -> 1059 bytes Z/src/nglwidgets/icons/png/turn_left.png | Bin 0 -> 2057 bytes .../icons/png/turn_left_disabled.png | Bin 0 -> 1585 bytes Z/src/nglwidgets/icons/png/undo_act.png | Bin 0 -> 2034 bytes .../icons/png/undo_act_disabled.png | Bin 0 -> 1536 bytes Z/src/nglwidgets/icons/png/zoom_in.png | Bin 0 -> 1330 bytes .../nglwidgets/icons/png/zoom_in_disabled.png | Bin 0 -> 1268 bytes Z/src/nglwidgets/icons/png/zoom_out.png | Bin 0 -> 1495 bytes .../icons/png/zoom_out_disabled.png | Bin 0 -> 1275 bytes Z/src/nglwidgets/icons/svg/3d_viewer.svg | 407 +++ .../nglwidgets/icons/svg/3d_viewer_config.svg | 497 ++++ .../icons/svg/3d_viewer_config_disabled.svg | 169 ++ .../icons/svg/3d_viewer_disabled.svg | 78 + Z/src/nglwidgets/icons/svg/about.svg | 428 ++++ Z/src/nglwidgets/icons/svg/about_disabled.svg | 100 + .../icons/svg/ac_adapter_plugged_in.svg | 398 +++ Z/src/nglwidgets/icons/svg/access_rights.svg | 423 +++ .../icons/svg/access_rights_disabled.svg | 95 + Z/src/nglwidgets/icons/svg/aircraft_sim.svg | 399 +++ Z/src/nglwidgets/icons/svg/announcement.svg | 428 ++++ .../icons/svg/announcement_disabled.svg | 101 + .../icons/svg/announcement_menu.svg | 419 +++ .../icons/svg/announcement_menu_disabled.svg | 91 + .../nglwidgets/icons/svg/application-exit.svg | 376 +++ Z/src/nglwidgets/icons/svg/arrow_back.svg | 392 +++ .../icons/svg/arrow_back_disabled.svg | 62 + .../icons/svg/artillery_firings.svg | 459 ++++ .../icons/svg/artillery_firings_disabled.svg | 134 + .../icons/svg/audio-volume-high.svg | 397 +++ .../nglwidgets/icons/svg/audio-volume-low.svg | 381 +++ .../icons/svg/audio-volume-medium.svg | 390 +++ .../icons/svg/audio-volume-muted.svg | 384 +++ Z/src/nglwidgets/icons/svg/battery_mode.svg | 368 +++ Z/src/nglwidgets/icons/svg/camera_control.svg | 428 ++++ .../icons/svg/camera_control_disabled.svg | 102 + .../nglwidgets/icons/svg/change_password.svg | 466 ++++ .../icons/svg/change_password_disabled.svg | 140 + Z/src/nglwidgets/icons/svg/chat.svg | 408 +++ Z/src/nglwidgets/icons/svg/chat_disabled.svg | 82 + .../nglwidgets/icons/svg/chemical_agents.svg | 458 ++++ .../icons/svg/chemical_agents_disabled.svg | 132 + .../icons/svg/config_gobal_alarms.svg | 508 ++++ .../svg/config_gobal_alarms_disabled.svg | 180 ++ .../nglwidgets/icons/svg/configure_arrow.svg | 451 ++++ .../icons/svg/configure_buildings.svg | 472 ++++ .../svg/configure_buildings_disabled.svg | 143 ++ .../icons/svg/configure_line_of_sight.svg | 509 ++++ .../svg/configure_line_of_sight_disabled.svg | 184 ++ .../icons/svg/configure_symbol_attributes.svg | 464 ++++ .../configure_symbol_attributes_disabled.svg | 144 ++ .../icons/svg/configure_tunnels.svg | 498 ++++ .../icons/svg/configure_tunnels_disabled.svg | 173 ++ .../icons/svg/create_distance_measure.svg | 470 ++++ .../svg/create_distance_measure_disabled.svg | 142 ++ .../icons/svg/create_evaluation_topic.svg | 416 +++ .../icons/svg/create_image_topic.svg | 403 +++ .../icons/svg/create_lecture_topic.svg | 470 ++++ .../nglwidgets/icons/svg/create_pdf_topic.svg | 438 ++++ .../nglwidgets/icons/svg/create_snapshot.svg | 467 ++++ .../icons/svg/create_snapshot_disabled.svg | 147 ++ .../icons/svg/create_terrain_profile.svg | 433 ++++ .../svg/create_terrain_profile_disabled.svg | 106 + Z/src/nglwidgets/icons/svg/create_thp.svg | 430 ++++ .../icons/svg/create_thp_disabled.svg | 105 + Z/src/nglwidgets/icons/svg/danger_areas.svg | 434 ++++ .../icons/svg/debug-execute-from-cursor.svg | 416 +++ .../icons/svg/debug-execute-to-cursor.svg | 417 +++ .../icons/svg/default_operator_rights.svg | 461 ++++ .../svg/default_operator_rights_disabled.svg | 132 + .../icons/svg/define_border_lines.svg | 499 ++++ .../svg/define_border_lines_disabled.svg | 172 ++ .../icons/svg/define_force_templates.svg | 467 ++++ .../svg/define_force_templates_disabled.svg | 140 + .../icons/svg/define_movement_simulation.svg | 500 ++++ .../define_movement_simulation_disabled.svg | 181 ++ .../icons/svg/define_player_types.svg | 536 ++++ .../svg/define_player_types_disabled.svg | 213 ++ .../icons/svg/define_position_system.svg | 427 ++++ .../svg/define_position_system_disabled.svg | 99 + .../icons/svg/define_presentation.svg | 400 +++ .../svg/define_presentation_disabled.svg | 72 + .../icons/svg/define_tactical_symbols.svg | 434 ++++ .../svg/define_tactical_symbols_disabled.svg | 103 + Z/src/nglwidgets/icons/svg/define_teams.svg | 450 ++++ .../icons/svg/define_teams_disabled.svg | 120 + .../icons/svg/define_training_cycles.svg | 466 ++++ .../svg/define_training_cycles_disabled.svg | 130 + Z/src/nglwidgets/icons/svg/delete_thp.svg | 424 +++ .../icons/svg/delete_thp_disabled.svg | 95 + Z/src/nglwidgets/icons/svg/dialog-close.svg | 386 +++ .../nglwidgets/icons/svg/dialog-ok-apply.svg | 377 +++ Z/src/nglwidgets/icons/svg/dialog-ok.svg | 377 +++ .../icons/svg/display_oc_evaluations.svg | 403 +++ .../svg/display_oc_evaluations_disabled.svg | 74 + .../nglwidgets/icons/svg/display_reports.svg | 423 +++ .../icons/svg/display_reports_disabled.svg | 96 + Z/src/nglwidgets/icons/svg/document-edit.svg | 386 +++ Z/src/nglwidgets/icons/svg/document-new.svg | 383 +++ .../icons/svg/document-open-data.svg | 409 +++ Z/src/nglwidgets/icons/svg/document-open.svg | 376 +++ .../icons/svg/document-properties.svg | 407 +++ Z/src/nglwidgets/icons/svg/documents.svg | 417 +++ .../icons/svg/documents_disabled.svg | 88 + Z/src/nglwidgets/icons/svg/download.svg | 380 +++ .../icons/svg/draw-bezier-curves.svg | 397 +++ Z/src/nglwidgets/icons/svg/edit-cut.svg | 400 +++ .../icons/svg/edit_evaluation_marker.svg | 468 ++++ .../svg/edit_evaluation_marker_disabled.svg | 144 ++ .../svg/electronical_warfare_measures.svg | 488 ++++ ...electronical_warfare_measures_disabled.svg | 154 ++ Z/src/nglwidgets/icons/svg/evaluate.svg | 454 ++++ .../icons/svg/evaluate_disabled.svg | 129 + .../icons/svg/evaluation_elements.svg | 441 ++++ .../svg/evaluation_elements_disabled.svg | 115 + .../icons/svg/execute_presentation.svg | 406 +++ .../svg/execute_presentation_disabled.svg | 78 + Z/src/nglwidgets/icons/svg/exercise_force.svg | 429 ++++ .../icons/svg/exercise_force_disabled.svg | 103 + .../nglwidgets/icons/svg/exercise_purpose.svg | 449 ++++ .../icons/svg/exercise_purpose_disabled.svg | 126 + .../nglwidgets/icons/svg/export_documents.svg | 409 +++ .../icons/svg/export_documents_disabled.svg | 80 + Z/src/nglwidgets/icons/svg/fill_pattern.svg | 403 +++ .../nglwidgets/icons/svg/filter_barriers.svg | 498 ++++ .../icons/svg/filter_barriers_disabled.svg | 178 ++ .../icons/svg/filter_border_lines.svg | 475 ++++ .../svg/filter_border_lines_disabled.svg | 151 ++ .../icons/svg/filter_collapse_expand.svg | 434 ++++ .../svg/filter_collapse_expand_disabled.svg | 112 + .../icons/svg/filter_effect_simulation.svg | 494 ++++ .../svg/filter_effect_simulation_disabled.svg | 170 ++ Z/src/nglwidgets/icons/svg/filter_firings.svg | 478 ++++ .../icons/svg/filter_firings_disabled.svg | 154 ++ .../icons/svg/filter_line_of_sight.svg | 444 ++++ .../svg/filter_line_of_sight_disabled.svg | 115 + .../icons/svg/filter_map_settings.svg | 407 +++ .../svg/filter_map_settings_disabled.svg | 81 + .../icons/svg/filter_map_settings_load.svg | 419 +++ .../svg/filter_map_settings_load_disabled.svg | 93 + .../icons/svg/filter_maps_settings_save.svg | 420 +++ .../filter_maps_settings_save_disabled.svg | 97 + .../icons/svg/filter_nbc_agents.svg | 528 ++++ .../icons/svg/filter_nbc_agents_disabled.svg | 204 ++ .../nglwidgets/icons/svg/filter_nc_agents.svg | 484 ++++ .../icons/svg/filter_nc_agents_disabled.svg | 159 ++ Z/src/nglwidgets/icons/svg/filter_player.svg | 452 ++++ .../icons/svg/filter_player_disabled.svg | 129 + Z/src/nglwidgets/icons/svg/filter_teams.svg | 471 ++++ .../icons/svg/filter_teams_disabled.svg | 148 ++ .../icons/svg/fixed_video_announcement.svg | 450 ++++ .../svg/fixed_video_announcement_disabled.svg | 125 + .../icons/svg/force_composition.svg | 468 ++++ .../icons/svg/force_composition_disabled.svg | 140 + .../icons/svg/force_organization.svg | 504 ++++ .../icons/svg/force_organization_disabled.svg | 179 ++ .../icons/svg/force_player_configuration.svg | 486 ++++ .../force_player_configuration_disabled.svg | 160 ++ Z/src/nglwidgets/icons/svg/freq_plan.svg | 450 ++++ .../icons/svg/function_key_toolbar.svg | 463 ++++ .../svg/function_key_toolbar_disabled.svg | 140 + Z/src/nglwidgets/icons/svg/getpos.svg | 394 +++ .../icons/svg/global_alarms_history.svg | 450 ++++ .../svg/global_alarms_history_disabled.svg | 122 + .../icons/svg/global_exercise_settings.svg | 480 ++++ .../svg/global_exercise_settings_disabled.svg | 158 ++ Z/src/nglwidgets/icons/svg/go-home.svg | 386 +++ .../icons/svg/hand_grenade_locations.svg | 465 ++++ Z/src/nglwidgets/icons/svg/help_index.svg | 451 ++++ .../icons/svg/help_index_disabled.svg | 122 + .../nglwidgets/icons/svg/import_buildings.svg | 423 +++ .../icons/svg/import_buildings_disabled.svg | 94 + .../nglwidgets/icons/svg/import_documents.svg | 422 +++ .../icons/svg/import_documents_disabled.svg | 94 + Z/src/nglwidgets/icons/svg/import_images.svg | 417 +++ .../icons/svg/import_images_disabled.svg | 90 + Z/src/nglwidgets/icons/svg/import_msdl.svg | 400 +++ .../icons/svg/import_pdf_document.svg | 457 ++++ .../svg/import_pdf_document_disabled.svg | 132 + Z/src/nglwidgets/icons/svg/import_video.svg | 478 ++++ .../icons/svg/import_video_disabled.svg | 153 ++ Z/src/nglwidgets/icons/svg/insert_script.svg | 414 +++ Z/src/nglwidgets/icons/svg/karte.svg | 410 +++ Z/src/nglwidgets/icons/svg/layer.svg | 410 +++ Z/src/nglwidgets/icons/svg/line_styles.svg | 383 +++ Z/src/nglwidgets/icons/svg/list-add-user.svg | 400 +++ .../nglwidgets/icons/svg/list-remove-user.svg | 393 +++ Z/src/nglwidgets/icons/svg/load.svg | 392 +++ Z/src/nglwidgets/icons/svg/load_disabled.svg | 67 + .../icons/svg/load_global_filter.svg | 456 ++++ .../icons/svg/load_global_filter_disabled.svg | 136 + Z/src/nglwidgets/icons/svg/logout.svg | 413 +++ .../nglwidgets/icons/svg/logout_disabled.svg | 85 + .../nglwidgets/icons/svg/map_context_menu.svg | 487 ++++ .../icons/svg/map_context_menu_disabled.svg | 143 ++ Z/src/nglwidgets/icons/svg/map_settings.svg | 484 ++++ .../icons/svg/map_settings_disabled.svg | 161 ++ Z/src/nglwidgets/icons/svg/marke.svg | 413 +++ Z/src/nglwidgets/icons/svg/marker-end.svg | 373 +++ Z/src/nglwidgets/icons/svg/marker-start.svg | 373 +++ Z/src/nglwidgets/icons/svg/media-flash.svg | 375 +++ .../icons/svg/media-play-backward.svg | 365 +++ .../icons/svg/media-play-slower.svg | 372 +++ Z/src/nglwidgets/icons/svg/media-record.svg | 373 +++ .../icons/svg/media-seek-backward.svg | 376 +++ .../icons/svg/media-seek-forward.svg | 375 +++ .../icons/svg/media-skip-backward.svg | 379 +++ .../icons/svg/media-skip-forward.svg | 379 +++ .../icons/svg/media-vcr-nopause.svg | 370 +++ .../nglwidgets/icons/svg/media-vcr-normal.svg | 369 +++ .../icons/svg/media-vcr-withpause.svg | 390 +++ Z/src/nglwidgets/icons/svg/messages.svg | 391 +++ .../icons/svg/messages_disabled.svg | 65 + .../icons/svg/metereological_data.svg | 417 +++ .../svg/metereological_data_disabled.svg | 91 + Z/src/nglwidgets/icons/svg/mgrs_grid.svg | 504 ++++ .../icons/svg/mgrs_grid_disabled.svg | 178 ++ .../icons/svg/mine_barrier_corridor.svg | 485 ++++ .../svg/mine_barrier_corridor_disabled.svg | 161 ++ Z/src/nglwidgets/icons/svg/mine_barriers.svg | 490 ++++ .../icons/svg/mine_barriers_disabled.svg | 169 ++ Z/src/nglwidgets/icons/svg/mini_map.svg | 514 ++++ .../icons/svg/mini_map_disabled.svg | 191 ++ Z/src/nglwidgets/icons/svg/mlvs_control.svg | 436 ++++ Z/src/nglwidgets/icons/svg/mobile_video.svg | 409 +++ .../icons/svg/mobile_video_disabled.svg | 82 + .../svg/mortar_ammunition_administration.svg | 440 ++++ ...tar_ammunition_administration_disabled.svg | 111 + .../icons/svg/mortar_ammunition_firings.svg | 474 ++++ .../mortar_ammunition_firings_disabled.svg | 145 ++ .../nglwidgets/icons/svg/network-wireless.svg | 392 +++ Z/src/nglwidgets/icons/svg/new_documents.svg | 885 +++++++ .../icons/svg/new_mail_indicator.svg | 405 +++ Z/src/nglwidgets/icons/svg/nuclear_agents.svg | 422 +++ Z/src/nglwidgets/icons/svg/object-group.svg | 386 +++ Z/src/nglwidgets/icons/svg/object-ungroup.svg | 405 +++ .../icons/svg/objects_define_areas.svg | 464 ++++ .../svg/objects_define_areas_disabled.svg | 139 + .../icons/svg/oc_aar_preparation.svg | 421 +++ .../icons/svg/oc_aar_preparation_disabled.svg | 94 + Z/src/nglwidgets/icons/svg/oc_composition.svg | 479 ++++ .../icons/svg/oc_composition_disabled.svg | 154 ++ .../icons/svg/oc_evaluation_schemes.svg | 457 ++++ .../svg/oc_evaluation_schemes_disabled.svg | 135 + .../icons/svg/oc_player_configuration.svg | 488 ++++ .../svg/oc_player_configuration_disabled.svg | 163 ++ .../icons/svg/operator_administration.svg | 458 ++++ .../svg/operator_administration_disabled.svg | 129 + .../icons/svg/organize_documents.svg | 420 +++ .../icons/svg/organize_documents_disabled.svg | 95 + .../nglwidgets/icons/svg/organize_library.svg | 467 ++++ .../icons/svg/organize_library_disabled.svg | 151 ++ Z/src/nglwidgets/icons/svg/overlay_plans.svg | 442 ++++ .../icons/svg/overlay_plans_disabled.svg | 115 + Z/src/nglwidgets/icons/svg/overlays.svg | 402 +++ Z/src/nglwidgets/icons/svg/phase_def.svg | 501 ++++ .../icons/svg/pi_force_collapse.svg | 394 +++ .../nglwidgets/icons/svg/pi_force_expand.svg | 394 +++ Z/src/nglwidgets/icons/svg/pi_force_left.svg | 386 +++ Z/src/nglwidgets/icons/svg/pi_force_right.svg | 387 +++ Z/src/nglwidgets/icons/svg/pi_markup_3d.svg | 407 +++ .../nglwidgets/icons/svg/pi_movementtrack.svg | 389 +++ Z/src/nglwidgets/icons/svg/pi_nbc.svg | 406 +++ .../icons/svg/pi_set_player_mode.svg | 401 +++ Z/src/nglwidgets/icons/svg/pi_show_bite.svg | 393 +++ .../nglwidgets/icons/svg/pi_show_building.svg | 472 ++++ .../icons/svg/pi_tact_status_history.svg | 396 +++ .../icons/svg/pi_type_weaponrange.svg | 752 ++++++ .../icons/svg/planned_training_cycles.svg | 404 +++ Z/src/nglwidgets/icons/svg/plans.svg | 410 +++ Z/src/nglwidgets/icons/svg/plans_disabled.svg | 81 + Z/src/nglwidgets/icons/svg/playback_audio.svg | 426 ++++ .../icons/svg/playback_audio_disabled.svg | 100 + .../icons/svg/playback_situation.svg | 413 +++ .../icons/svg/playback_situation_disabled.svg | 87 + Z/src/nglwidgets/icons/svg/playback_video.svg | 427 ++++ .../icons/svg/playback_video_disabled.svg | 101 + .../nglwidgets/icons/svg/player_equipment.svg | 675 +++++ .../icons/svg/player_equipment_check.svg | 425 +++ .../svg/player_equipment_check_disabled.svg | 96 + Z/src/nglwidgets/icons/svg/player_mode.svg | 647 +++++ .../svg/preferences-web-browser-cache.svg | 458 ++++ Z/src/nglwidgets/icons/svg/prepare_thp.svg | 452 ++++ .../icons/svg/prepare_thp_disabled.svg | 125 + Z/src/nglwidgets/icons/svg/presets.svg | 476 ++++ .../nglwidgets/icons/svg/presets_disabled.svg | 153 ++ .../icons/svg/primary_map_position.svg | 407 +++ .../svg/primary_map_position_disabled.svg | 81 + .../icons/svg/primary_map_toolbar.svg | 448 ++++ .../svg/primary_map_toolbar_disabled.svg | 125 + Z/src/nglwidgets/icons/svg/proj_audio.svg | 403 +++ Z/src/nglwidgets/icons/svg/projection.svg | 379 +++ Z/src/nglwidgets/icons/svg/raster.svg | 390 +++ .../nglwidgets/icons/svg/raster_disabled.svg | 68 + .../icons/svg/report_ammunition_left.svg | 431 ++++ .../svg/report_ammunition_left_disabled.svg | 107 + .../icons/svg/report_ammunition_resupply.svg | 502 ++++ .../report_ammunition_resupply_disabled.svg | 179 ++ Z/src/nglwidgets/icons/svg/report_awes.svg | 493 ++++ .../icons/svg/report_awes_disabled.svg | 168 ++ .../icons/svg/report_combat_effectiveness.svg | 480 ++++ .../report_combat_effectiveness_disabled.svg | 155 ++ .../icons/svg/report_combat_power.svg | 494 ++++ .../svg/report_combat_power_disabled.svg | 168 ++ .../icons/svg/report_explosive_devices.svg | 454 ++++ .../svg/report_explosive_devices_disabled.svg | 130 + .../icons/svg/report_maintenance.svg | 432 ++++ .../icons/svg/report_maintenance_disabled.svg | 108 + .../icons/svg/report_mine_barrier.svg | 464 ++++ .../svg/report_mine_barrier_disabled.svg | 138 + .../icons/svg/report_mortar_firings.svg | 461 ++++ .../svg/report_mortar_firings_disabled.svg | 135 + .../icons/svg/report_nbc_events.svg | 493 ++++ .../icons/svg/report_nbc_events_disabled.svg | 170 ++ .../nglwidgets/icons/svg/report_nc_events.svg | 464 ++++ .../icons/svg/report_nc_events_disabled.svg | 138 + .../nglwidgets/icons/svg/report_treatment.svg | 449 ++++ .../icons/svg/report_treatment_disabled.svg | 125 + .../icons/svg/report_treatmentmaintanance.svg | 460 ++++ .../report_treatmentmaintanance_disabled.svg | 136 + .../nglwidgets/icons/svg/save_preferences.svg | 468 ++++ .../icons/svg/save_preferences_disabled.svg | 130 + Z/src/nglwidgets/icons/svg/screenshot.svg | 398 +++ .../icons/svg/screenshot_disabled.svg | 71 + .../icons/svg/secondary_map_position.svg | 420 +++ .../svg/secondary_map_position_disabled.svg | 96 + .../icons/svg/secondary_map_toolbar.svg | 461 ++++ .../svg/secondary_map_toolbar_disabled.svg | 138 + Z/src/nglwidgets/icons/svg/select_player.svg | 474 ++++ .../icons/svg/select_player_disabled.svg | 159 ++ .../icons/svg/select_training_areas.svg | 404 +++ .../svg/select_training_areas_disabled.svg | 77 + .../icons/svg/select_training_cylces.svg | 442 ++++ .../svg/select_training_cylces_disabled.svg | 114 + .../icons/svg/send_player_message.svg | 419 +++ .../svg/send_player_message_disabled.svg | 92 + .../icons/svg/set_exercise_process.svg | 485 ++++ .../svg/set_exercise_process_disabled.svg | 161 ++ .../icons/svg/set_force_visibility.svg | 477 ++++ .../svg/set_force_visibility_disabled.svg | 149 ++ .../icons/svg/set_home_transparency.svg | 444 ++++ .../svg/set_home_transparency_disabled.svg | 119 + .../icons/svg/set_marker_situation.svg | 445 ++++ .../svg/set_marker_situation_disabled.svg | 126 + .../nglwidgets/icons/svg/set_marker_video.svg | 474 ++++ .../icons/svg/set_marker_video_disabled.svg | 155 ++ .../icons/svg/set_markers_audio.svg | 461 ++++ .../icons/svg/set_markers_audio_disabled.svg | 139 + .../nglwidgets/icons/svg/set_player_mode.svg | 401 +++ .../icons/svg/set_player_mode_disabled.svg | 73 + .../icons/svg/set_player_status.svg | 391 +++ .../icons/svg/set_player_status_disabled.svg | 67 + .../icons/svg/set_view_position.svg | 454 ++++ .../icons/svg/set_view_position_disabled.svg | 125 + .../icons/svg/show_building_configuration.svg | 466 ++++ .../show_building_configuration_disabled.svg | 138 + .../icons/svg/show_distance_measure.svg | 455 ++++ .../svg/show_distance_measure_disabled.svg | 130 + .../icons/svg/show_line_of_sight.svg | 454 ++++ .../icons/svg/show_line_of_sight_disabled.svg | 126 + .../icons/svg/show_terrain_profile.svg | 439 ++++ .../svg/show_terrain_profile_disabled.svg | 113 + .../icons/svg/simulated_players.svg | 409 +++ .../icons/svg/simulated_players_disabled.svg | 85 + Z/src/nglwidgets/icons/svg/situation.svg | 431 ++++ .../icons/svg/situation_disabled.svg | 106 + Z/src/nglwidgets/icons/svg/status_bar.svg | 486 ++++ .../icons/svg/status_bar_disabled.svg | 159 ++ .../icons/svg/support_documents.svg | 449 ++++ .../icons/svg/support_documents_disabled.svg | 120 + Z/src/nglwidgets/icons/svg/switch_display.svg | 435 ++++ .../icons/svg/switch_display_disabled.svg | 111 + .../icons/svg/switch_to_primary_map.svg | 439 ++++ .../svg/switch_to_primary_map_disabled.svg | 110 + .../icons/svg/switch_to_sec_map.svg | 447 ++++ .../icons/svg/switch_to_sec_map_disabled.svg | 120 + Z/src/nglwidgets/icons/svg/symbol_display.svg | 411 +++ .../icons/svg/symbol_display_disabled.svg | 86 + Z/src/nglwidgets/icons/svg/system_status.svg | 456 ++++ .../icons/svg/system_status_disabled.svg | 127 + .../icons/svg/tactical_organization.svg | 455 ++++ .../svg/tactical_organization_disabled.svg | 129 + .../nglwidgets/icons/svg/tactical_symbol.svg | 404 +++ .../icons/svg/tactical_symbol_disabled.svg | 76 + Z/src/nglwidgets/icons/svg/target.svg | 402 +++ .../nglwidgets/icons/svg/terminal_window.svg | 399 +++ .../icons/svg/terminal_window_disabled.svg | 70 + Z/src/nglwidgets/icons/svg/toolbar_editor.svg | 480 ++++ .../icons/svg/toolbar_editor_disabled.svg | 157 ++ .../icons/svg/translation_editor.svg | 391 +++ .../icons/svg/update_player_position.svg | 423 +++ .../svg/update_player_position_disabled.svg | 97 + Z/src/nglwidgets/icons/svg/video_menu.svg | 404 +++ .../icons/svg/video_menu_disabled.svg | 79 + .../nglwidgets/icons/svg/view-statistics.svg | 378 +++ Z/src/nglwidgets/icons/svg/visible_teams.svg | 487 ++++ .../icons/svg/voice_communication.svg | 470 ++++ .../icons/svg/voice_communication_access.svg | 455 ++++ .../voice_communication_access_disabled.svg | 125 + .../svg/voice_communication_disabled.svg | 140 + Z/src/nglwidgets/icons/svg/weapon_firing.svg | 438 ++++ .../icons/svg/weapon_firing_disabled.svg | 112 + Z/src/nglwidgets/icons/svg/wireless.svg | 448 ++++ Z/src/nglwidgets/ngldialog.cpp | 149 ++ Z/src/nglwidgets/ngldialog.h | 62 + Z/src/nglwidgets/ngldialogbuttonbox.cpp | 445 ++++ Z/src/nglwidgets/ngldialogbuttonbox.h | 189 ++ Z/src/nglwidgets/nglmainwindow.cpp | 107 + Z/src/nglwidgets/nglmainwindow.h | 46 + Z/src/nglwidgets/nglpdfdocument.cpp | 332 +++ Z/src/nglwidgets/nglpdfdocument.h | 118 + Z/src/nglwidgets/nglpdfpage.cpp | 203 ++ Z/src/nglwidgets/nglpdfpage.h | 54 + Z/src/nglwidgets/nglpdfwidget.cpp | 151 ++ Z/src/nglwidgets/nglpdfwidget.h | 48 + Z/src/nglwidgets/nglpdfwidget.ui | 253 ++ Z/src/nglwidgets/nglresources.qrc | 669 +++++ Z/src/nglwidgets/nglstandardbutton.cpp | 336 +++ Z/src/nglwidgets/nglstandardbutton.h | 105 + Z/src/nglwidgets/ngltreeitem.cpp | 131 + Z/src/nglwidgets/ngltreeitem.h | 72 + Z/src/nglwidgets/ngltreemodel.cpp | 458 ++++ Z/src/nglwidgets/ngltreemodel.h | 98 + Z/src/nglwidgets/nglwidgets_export.h | 17 + Z/src/qsql_informix/CMakeLists.txt | 49 + Z/src/qsql_informix/FindCrypt.cmake | 38 + Z/src/qsql_informix/FindIClientSDK.cmake | 209 ++ Z/src/qsql_informix/qsql_informix.cpp | 1333 ++++++++++ Z/src/qsql_informix/qsql_informix.h | 88 + Z/src/qsql_informix/qsql_informix.json | 3 + Z/src/qsql_informix/qsql_informix_plugin.cpp | 28 + Z/src/qsql_informix/qsql_informix_test.cpp | 277 ++ Z/src/qsql_informix/qsql_informix_utils.cpp | 98 + Z/src/qsql_informix/qsql_informix_utils.h | 41 + Z/src/tcpserver/CMakeLists.txt | 56 + Z/src/tcpserver/cbi_help.cpp | 29 + Z/src/tcpserver/cbi_help.h | 19 + Z/src/tcpserver/cbi_pingpong.cpp | 23 + Z/src/tcpserver/cbi_pingpong.h | 19 + Z/src/tcpserver/cbi_quit.cpp | 19 + Z/src/tcpserver/cbi_quit.h | 19 + Z/src/tcpserver/cbi_recvfile.cpp | 86 + Z/src/tcpserver/cbi_recvfile.h | 23 + Z/src/tcpserver/cbi_sendfile.cpp | 45 + Z/src/tcpserver/cbi_sendfile.h | 17 + Z/src/tcpserver/cbi_shutdown.cpp | 25 + Z/src/tcpserver/cbi_shutdown.h | 25 + Z/src/tcpserver/commandinterface.cpp | 329 +++ Z/src/tcpserver/commandinterface.h | 158 ++ Z/src/tcpserver/tcpserver.cpp | 209 ++ Z/src/tcpserver/tcpserver.h | 96 + Z/src/tcpserver/tcpserver_export.h | 27 + Z/src/tcpserver/tcpserver_logger.h | 27 + Z/src/tcpserver/tcpserver_test.cpp | 43 + Z/src/tcpserver/workerbase.cpp | 304 +++ Z/src/tcpserver/workerbase.h | 127 + cmake/DoxygenMacros.cmake | 22 + cmake/FindArcGIS.cmake | 126 + cmake/FindBgViewer.cmake | 36 + cmake/FindBotan2.cmake | 48 + cmake/FindKDChart.cmake | 40 + cmake/FindKDReports.cmake | 49 + cmake/FindLibraryWithDebug.cmake | 113 + cmake/FindNGS.cmake | 134 + cmake/FindPopplerQt5.cmake | 61 + cmake/FindRTI.cmake | 179 ++ cmake/FindSchusstafel.cmake | 40 + cmake/FindTMSIF.cmake | 104 + cmake/FindVLC.cmake | 49 + cmake/FindXSD.cmake | 81 + cmake/MacroCodeGenIdl.cmake | 511 ++++ cmake/MacroEnsureOutOfSourceBuild.cmake | 21 + cmake/MacroRTIDDSGen.cmake | 72 + cmake/NGLMacros.cmake | 598 +++++ cmake/make_qt_help.py | 186 ++ cmake/ngl_dep_test_main.cpp | 5 + 991 files changed, 178451 insertions(+) create mode 100755 CMakeLists.txt create mode 100644 TetraIF/CMakeLists.txt create mode 100644 TetraIF/CoPrtCnv/CMakeLists.txt create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvTelegramConverter.hpp create mode 100644 TetraIF/CoPrtCnv/CoPrtCnvTelegramConverterNewIcd.cpp create mode 100644 TetraIF/CoPrtCnv/tetra_telegram_ids.h create mode 100644 TetraIF/LogView/CMakeLists.txt create mode 100644 TetraIF/LogView/Console/CMakeLists.txt create mode 100644 TetraIF/LogView/Console/main.cpp create mode 100644 TetraIF/LogView/IntegerCalculator.cpp create mode 100644 TetraIF/LogView/IntegerCalculator.hpp create mode 100644 TetraIF/LogView/LogViewBooleanEdit.cpp create mode 100644 TetraIF/LogView/LogViewBooleanEdit.hpp create mode 100644 TetraIF/LogView/LogViewDateTimeEdit.cpp create mode 100644 TetraIF/LogView/LogViewDateTimeEdit.hpp create mode 100644 TetraIF/LogView/LogViewEnumEdit.cpp create mode 100644 TetraIF/LogView/LogViewEnumEdit.hpp create mode 100644 TetraIF/LogView/LogViewField.cpp create mode 100644 TetraIF/LogView/LogViewField.hpp create mode 100644 TetraIF/LogView/LogViewGui.cpp create mode 100644 TetraIF/LogView/LogViewGui.hpp create mode 100644 TetraIF/LogView/LogViewInjectionThread.cpp create mode 100644 TetraIF/LogView/LogViewInjectionThread.hpp create mode 100644 TetraIF/LogView/LogViewMain.cpp create mode 100644 TetraIF/LogView/LogViewModels.cpp create mode 100644 TetraIF/LogView/LogViewModels.hpp create mode 100644 TetraIF/LogView/LogViewOptionDialog.cpp create mode 100644 TetraIF/LogView/LogViewOptionDialog.hpp create mode 100644 TetraIF/LogView/LogViewResources.qrc create mode 100644 TetraIF/LogView/LogViewSpinBox.cpp create mode 100644 TetraIF/LogView/LogViewSpinBox.hpp create mode 100644 TetraIF/LogView/LogViewTabWidget.cpp create mode 100644 TetraIF/LogView/LogViewTabWidget.hpp create mode 100644 TetraIF/LogView/LogViewTableWidget.cpp create mode 100644 TetraIF/LogView/LogViewTableWidget.hpp create mode 100644 TetraIF/LogView/LogViewTelegram.cpp create mode 100644 TetraIF/LogView/LogViewTelegram.hpp create mode 100644 TetraIF/LogView/LogViewTelegramDialog.cpp create mode 100644 TetraIF/LogView/LogViewTelegramDialog.hpp create mode 100644 TetraIF/LogView/LogViewTelegramEdit.cpp create mode 100644 TetraIF/LogView/LogViewTelegramEdit.hpp create mode 100644 TetraIF/LogView/LogViewTelegramEditModel.cpp create mode 100644 TetraIF/LogView/LogViewTelegramEditModel.hpp create mode 100644 TetraIF/LogView/LogViewTelegramSelectionDialog.cpp create mode 100644 TetraIF/LogView/LogViewTelegramSelectionDialog.hpp create mode 100644 TetraIF/LogView/LogViewTetraTelegramsParser.cpp create mode 100644 TetraIF/LogView/LogViewTetraTelegramsParser.hpp create mode 100644 TetraIF/LogView/LogViewTextEdit.cpp create mode 100644 TetraIF/LogView/LogViewTextEdit.hpp create mode 100644 TetraIF/LogView/LogViewValueEdit.cpp create mode 100644 TetraIF/LogView/LogViewValueEdit.hpp create mode 100644 TetraIF/LogView/LogViewWidget.cpp create mode 100644 TetraIF/LogView/LogViewWidget.hpp create mode 100644 TetraIF/LogView/LogViewXdrElement.cpp create mode 100644 TetraIF/LogView/LogViewXdrElement.hpp create mode 100644 TetraIF/LogView/LogViewXdrParser.cpp create mode 100644 TetraIF/LogView/LogViewXdrParser.hpp create mode 100644 TetraIF/LogView/LogViewXdrStandardType.cpp create mode 100644 TetraIF/LogView/LogViewXdrStandardType.hpp create mode 100644 TetraIF/LogView/LogViewXdrStruct.cpp create mode 100644 TetraIF/LogView/LogViewXdrStruct.hpp create mode 100644 TetraIF/LogView/LogViewXdrType.cpp create mode 100644 TetraIF/LogView/LogViewXdrType.hpp create mode 100644 TetraIF/LogView/LogViewXdrValue.cpp create mode 100644 TetraIF/LogView/LogViewXdrValue.hpp create mode 100644 TetraIF/LogView/LogView_log4cxx.props create mode 100644 TetraIF/LogView/image/C2P.png create mode 100644 TetraIF/LogView/image/Central.png create mode 100644 TetraIF/LogView/image/GreenDarkLamp.png create mode 100644 TetraIF/LogView/image/GreenLamp.png create mode 100644 TetraIF/LogView/image/P2C.png create mode 100644 TetraIF/LogView/image/P2T.png create mode 100644 TetraIF/LogView/image/P2W.png create mode 100644 TetraIF/LogView/image/RedLamp.png create mode 100644 TetraIF/LogView/image/ShowSend.png create mode 100644 TetraIF/LogView/image/T2P.png create mode 100644 TetraIF/LogView/image/TNE.png create mode 100644 TetraIF/LogView/image/Tetra.png create mode 100644 TetraIF/LogView/image/W2P.png create mode 100644 TetraIF/LogView/image/Wls.png create mode 100644 TetraIF/LogView/image/YellowDarkLamp.png create mode 100644 TetraIF/LogView/image/YellowLamp.png create mode 100644 TetraIF/LogView/logger.cpp create mode 100644 TetraIF/LogView/logger.h create mode 120000 TetraIF/LogView/zsksxd_tetraForLogView.cpp create mode 100644 TetraIF/LogView/zsksxd_tetraForLogView.x create mode 120000 TetraIF/LogView/zsksxd_tetraForLogView_guez.cpp create mode 100644 TetraIF/LogView/zsksxd_tetraForLogView_guez.x create mode 100644 TetraIF/PrtCnv/AppComponent.cpp create mode 100644 TetraIF/PrtCnv/AppComponent.hpp create mode 100644 TetraIF/PrtCnv/CMakeLists.txt create mode 100644 TetraIF/PrtCnv/IAppComponent.hpp create mode 100644 TetraIF/PrtCnv/LastTest/CMakeLists.txt create mode 100644 TetraIF/PrtCnv/LastTest/main.cpp create mode 100644 TetraIF/PrtCnv/LastTest/tetra_if.cpp create mode 100644 TetraIF/PrtCnv/LastTest/tetra_if.h create mode 100644 TetraIF/PrtCnv/LastTestAuswertung/CMakeLists.txt create mode 100644 TetraIF/PrtCnv/LastTestAuswertung/LastTestAuswertung.pro create mode 100644 TetraIF/PrtCnv/LastTestAuswertung/main.cpp create mode 100644 TetraIF/PrtCnv/LastTestAuswertung/mainwindow.cpp create mode 100644 TetraIF/PrtCnv/LastTestAuswertung/mainwindow.h create mode 100644 TetraIF/PrtCnv/LastTestAuswertung/mainwindow.ui create mode 100644 TetraIF/PrtCnv/PrtCnv.dat.tts create mode 100644 TetraIF/PrtCnv/PrtCnvApplication.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvApplication.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvCentralThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvCentralThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvDbThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvDbThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvInjectionThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvInjectionThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvMain.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvMember.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvMember.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvRadioThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvRadioThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvSocketThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvSocketThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvStoredCentralTelegram.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvThread.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvThread.hpp create mode 100644 TetraIF/PrtCnv/PrtCnvThreadStarter.cpp create mode 100644 TetraIF/PrtCnv/PrtCnvThreadStarter.hpp create mode 100644 TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt create mode 100644 TetraIF/PrtCnv/TetraTestServer/log4cxx_tetratestserver.props create mode 100644 TetraIF/PrtCnv/TetraTestServer/main.cpp create mode 100644 TetraIF/PrtCnv/TetraTestServer/server.cpp create mode 100644 TetraIF/PrtCnv/TetraTestServer/server.h create mode 100644 TetraIF/PrtCnv/TetraTestServer/tts.txt create mode 100644 TetraIF/PrtCnv/TetraTestServer/worker.cpp create mode 100644 TetraIF/PrtCnv/TetraTestServer/worker.h create mode 100644 TetraIF/PrtCnv/log4cxx_prtcnv.props create mode 100644 TetraIF/PrtCnv/logger.cpp create mode 100644 TetraIF/PrtCnv/logger.h create mode 100755 Z/src/CMakeLists.txt create mode 100755 Z/src/NGLLogger/CMakeLists.txt create mode 100755 Z/src/NGLLogger/INGLLogger.h create mode 100755 Z/src/NGLLogger/MurmurHash2.cpp create mode 100755 Z/src/NGLLogger/MurmurHash2.h create mode 100755 Z/src/NGLLogger/NGLLogger.cpp create mode 100755 Z/src/NGLLogger/NGLLogger.h create mode 100755 Z/src/NGLLogger/NGLLoggerBootstrap.cpp create mode 100755 Z/src/NGLLogger/NGLLoggerBootstrap.h create mode 100755 Z/src/NGLLogger/NGLLogger_export.h create mode 100755 Z/src/NGLLogger/log4cxx.props create mode 100755 Z/src/NGLLogger/test_ngllogger.cpp create mode 100755 Z/src/QtSingleApplication/CMakeLists.txt create mode 100755 Z/src/QtSingleApplication/QtLockedFile create mode 100755 Z/src/QtSingleApplication/QtSingleApplication create mode 100755 Z/src/QtSingleApplication/QtSingleCoreApplication create mode 100755 Z/src/QtSingleApplication/qtlocalpeer.cpp create mode 100755 Z/src/QtSingleApplication/qtlocalpeer.h create mode 100755 Z/src/QtSingleApplication/qtlockedfile.cpp create mode 100755 Z/src/QtSingleApplication/qtlockedfile.h create mode 100755 Z/src/QtSingleApplication/qtlockedfile_unix.cpp create mode 100755 Z/src/QtSingleApplication/qtlockedfile_win.cpp create mode 100755 Z/src/QtSingleApplication/qtsingleapplication.cpp create mode 100755 Z/src/QtSingleApplication/qtsingleapplication.h create mode 100755 Z/src/QtSingleApplication/qtsinglecoreapplication.cpp create mode 100755 Z/src/QtSingleApplication/qtsinglecoreapplication.h create mode 100755 Z/src/WMS_Interface/CMakeLists.txt create mode 100755 Z/src/WMS_Interface/IECC2WMS.h create mode 100755 Z/src/WMS_Interface/IWMS2ECC.h create mode 100755 Z/src/WMS_Interface/json_keys.h create mode 100755 Z/src/WMS_Interface/wms_ecc_equipRequirements.cpp create mode 100755 Z/src/WMS_Interface/wms_ecc_equipRequirements.h create mode 100755 Z/src/WMS_Interface/wms_ecc_equipmenttypes.cpp create mode 100755 Z/src/WMS_Interface/wms_ecc_equipmenttypes.h create mode 100755 Z/src/WMS_Interface/wms_ecc_exercises.cpp create mode 100755 Z/src/WMS_Interface/wms_ecc_exercises.h create mode 100755 Z/src/WMS_Interface/wms_ecc_ibase.h create mode 100755 Z/src/WMS_Interface/wms_ecc_playerInfo.cpp create mode 100755 Z/src/WMS_Interface/wms_ecc_playerInfo.h create mode 100755 Z/src/WMS_Interface/wms_ecc_registration.cpp create mode 100755 Z/src/WMS_Interface/wms_ecc_registration.h create mode 100755 Z/src/WMS_Interface/wms_ecc_unregister.cpp create mode 100755 Z/src/WMS_Interface/wms_ecc_unregister.h create mode 100755 Z/src/nglapplication/CMakeLists.txt create mode 100755 Z/src/nglapplication/ngl_qt_msg_handler.inc create mode 100755 Z/src/nglapplication/ngl_signal_handler.inc create mode 100755 Z/src/nglapplication/nglapplication.cpp create mode 100755 Z/src/nglapplication/nglapplication.h create mode 100755 Z/src/nglapplication/nglcoreapplication.cpp create mode 100755 Z/src/nglapplication/nglcoreapplication.h create mode 100755 Z/src/nglapplication/nglguiapplication.cpp create mode 100755 Z/src/nglapplication/nglguiapplication.h create mode 100755 Z/src/nglapplication/nglloggerhandler.cpp create mode 100755 Z/src/nglapplication/nglloggerhandler.h create mode 100755 Z/src/nglapplication/nglsingleapplication.cpp create mode 100755 Z/src/nglapplication/nglsingleapplication.h create mode 100755 Z/src/nglapplication/nglsinglecoreapplication.cpp create mode 100755 Z/src/nglapplication/nglsinglecoreapplication.h create mode 100755 Z/src/nglcompression/CMakeLists.txt create mode 100755 Z/src/nglcompression/nglcomp_bzip2iodevice.cpp create mode 100755 Z/src/nglcompression/nglcomp_bzip2iodevice.h create mode 100755 Z/src/nglcompression/nglcomp_compress.cpp create mode 100755 Z/src/nglcompression/nglcomp_compress.h create mode 100755 Z/src/nglcompression/nglcomp_export.h create mode 100755 Z/src/nglcompression/nglcomp_tarfilter.cpp create mode 100755 Z/src/nglcompression/nglcomp_tarfilter.h create mode 100755 Z/src/nglcompression/nglcomp_test.cpp create mode 100755 Z/src/nglcompression/nglcomp_test.h create mode 100755 Z/src/ngldb/CMakeLists.txt create mode 100755 Z/src/ngldb/db_service_handler.h create mode 100755 Z/src/ngldb/dbcommon.h create mode 100755 Z/src/ngldb/dbconnection.cpp create mode 100755 Z/src/ngldb/dbconnection.h create mode 100755 Z/src/ngldb/dbtransaction.cpp create mode 100755 Z/src/ngldb/dbtransaction.h create mode 100755 Z/src/ngldb/ngldb_export.h create mode 100755 Z/src/ngldb/ngldb_logger.cpp create mode 100755 Z/src/ngldb/ngldb_logger.h create mode 100755 Z/src/ngldb/nsqlquery.cpp create mode 100755 Z/src/ngldb/nsqlquery.h create mode 100755 Z/src/ngldb/sql_query_janitor.cpp create mode 100755 Z/src/ngldb/sql_query_janitor.h create mode 100755 Z/src/nglsettings/CMakeLists.txt create mode 100755 Z/src/nglsettings/nglsettings_connections.cpp create mode 100755 Z/src/nglsettings/nglsettings_connections.h create mode 100755 Z/src/nglsettings/nglsettings_export.h create mode 100755 Z/src/nglsettings/nglsettings_settings.cpp create mode 100755 Z/src/nglsettings/nglsettings_settings.h create mode 100755 Z/src/ngltools/CMakeLists.txt create mode 100755 Z/src/ngltools/ngltools_bitset.h create mode 100755 Z/src/ngltools/ngltools_convert.cpp create mode 100755 Z/src/ngltools/ngltools_convert.h create mode 100755 Z/src/ngltools/ngltools_dtg.cpp create mode 100755 Z/src/ngltools/ngltools_dtg.h create mode 100755 Z/src/ngltools/ngltools_export.h create mode 100755 Z/src/ngltools/ngltools_filesystem.cpp create mode 100755 Z/src/ngltools/ngltools_filesystem.h create mode 100755 Z/src/ngltools/ngltools_helpevent.cpp create mode 100755 Z/src/ngltools/ngltools_helpevent.h create mode 100755 Z/src/ngltranslator/CMakeLists.txt create mode 100755 Z/src/ngltranslator/ngltranslator.cpp create mode 100755 Z/src/ngltranslator/ngltranslator.h create mode 100755 Z/src/ngltranslator/ngltranslator_export.h create mode 100755 Z/src/ngltranslator/ngltranslator_p.h create mode 100755 Z/src/nglwidgets/CMakeLists.txt create mode 100755 Z/src/nglwidgets/icons/16x16/LICENSE create mode 100755 Z/src/nglwidgets/icons/16x16/application-pdf.png create mode 100755 Z/src/nglwidgets/icons/16x16/arrow-left.png create mode 100755 Z/src/nglwidgets/icons/16x16/arrow-right.png create mode 100755 Z/src/nglwidgets/icons/16x16/audio-x-generic.png create mode 100755 Z/src/nglwidgets/icons/16x16/bg.gif create mode 100755 Z/src/nglwidgets/icons/16x16/camera-photo.png create mode 100755 Z/src/nglwidgets/icons/16x16/configure.png create mode 100755 Z/src/nglwidgets/icons/16x16/dialog-close.png create mode 100755 Z/src/nglwidgets/icons/16x16/dialog-ok-apply.png create mode 100755 Z/src/nglwidgets/icons/16x16/dialog-ok.png create mode 100755 Z/src/nglwidgets/icons/16x16/dirs.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-edit.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-import.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-new.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-open-data.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-open.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-preview.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-print.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-properties.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-save-all.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-save-as.png create mode 100755 Z/src/nglwidgets/icons/16x16/document-save.png create mode 100755 Z/src/nglwidgets/icons/16x16/download.png create mode 100755 Z/src/nglwidgets/icons/16x16/draw-bezier-curves.png create mode 100755 Z/src/nglwidgets/icons/16x16/draw-ellipse.png create mode 100755 Z/src/nglwidgets/icons/16x16/draw-line.png create mode 100755 Z/src/nglwidgets/icons/16x16/draw-polygon.png create mode 100755 Z/src/nglwidgets/icons/16x16/draw-polyline.png create mode 100755 Z/src/nglwidgets/icons/16x16/draw-rectangle.png create mode 100755 Z/src/nglwidgets/icons/16x16/draw-text.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-clear-locationbar-rtl.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-copy.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-cut.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-delete.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-paste.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-redo.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-rename.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-select.png create mode 100755 Z/src/nglwidgets/icons/16x16/edit-undo.png create mode 100755 Z/src/nglwidgets/icons/16x16/fill-color.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-justify-center.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-justify-fill.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-justify-left.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-justify-right.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-stroke-color.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-text-bold.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-text-italic.png create mode 100755 Z/src/nglwidgets/icons/16x16/format-text-underline.png create mode 100755 Z/src/nglwidgets/icons/16x16/freu.gif create mode 100755 Z/src/nglwidgets/icons/16x16/go-down.png create mode 100755 Z/src/nglwidgets/icons/16x16/go-home.png create mode 100755 Z/src/nglwidgets/icons/16x16/go-next.png create mode 100755 Z/src/nglwidgets/icons/16x16/go-previous.png create mode 100755 Z/src/nglwidgets/icons/16x16/go-up.png create mode 100755 Z/src/nglwidgets/icons/16x16/help-about.png create mode 100755 Z/src/nglwidgets/icons/16x16/help-contents.png create mode 100755 Z/src/nglwidgets/icons/16x16/image-x-generic.png create mode 100755 Z/src/nglwidgets/icons/16x16/internet-mail.png create mode 100755 Z/src/nglwidgets/icons/16x16/led-blue-on.png create mode 100755 Z/src/nglwidgets/icons/16x16/led-gray-on.png create mode 100755 Z/src/nglwidgets/icons/16x16/led-green-on.png create mode 100755 Z/src/nglwidgets/icons/16x16/led-red-on.png create mode 100755 Z/src/nglwidgets/icons/16x16/led-yellow-on.png create mode 100755 Z/src/nglwidgets/icons/16x16/list-add-user.png create mode 100755 Z/src/nglwidgets/icons/16x16/list-add.png create mode 100755 Z/src/nglwidgets/icons/16x16/list-remove-user.png create mode 100755 Z/src/nglwidgets/icons/16x16/list-remove.png create mode 100755 Z/src/nglwidgets/icons/16x16/mail-mark-read.png create mode 100755 Z/src/nglwidgets/icons/16x16/mail-mark-unread.png create mode 100755 Z/src/nglwidgets/icons/16x16/mail-message-new.png create mode 100755 Z/src/nglwidgets/icons/16x16/mail-send.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-eject.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-flash.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-play-faster.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-play-normal.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-play-slower.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-playback-pause.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-playback-start.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-playback-stop.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-record.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-seek-backward.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-seek-forward.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-skip-backward.png create mode 100755 Z/src/nglwidgets/icons/16x16/media-skip-forward.png create mode 100755 Z/src/nglwidgets/icons/16x16/oO.gif create mode 100755 Z/src/nglwidgets/icons/16x16/object-group.png create mode 100755 Z/src/nglwidgets/icons/16x16/object-ungroup.png create mode 100755 Z/src/nglwidgets/icons/16x16/ooo-calc.png create mode 100755 Z/src/nglwidgets/icons/16x16/ooo-impress.png create mode 100755 Z/src/nglwidgets/icons/16x16/ooo-writer.png create mode 100755 Z/src/nglwidgets/icons/16x16/player_status.png create mode 100755 Z/src/nglwidgets/icons/16x16/preferences-desktop-font.png create mode 100755 Z/src/nglwidgets/icons/16x16/preferences-web-browser-cache.png create mode 100755 Z/src/nglwidgets/icons/16x16/printer.png create mode 100755 Z/src/nglwidgets/icons/16x16/process-stop.png create mode 100755 Z/src/nglwidgets/icons/16x16/rde.ico create mode 100755 Z/src/nglwidgets/icons/16x16/rde_16x16.png create mode 100755 Z/src/nglwidgets/icons/16x16/system-help.png create mode 100755 Z/src/nglwidgets/icons/16x16/text-plain.png create mode 100755 Z/src/nglwidgets/icons/16x16/transform-move.png create mode 100755 Z/src/nglwidgets/icons/16x16/transform-rotate.png create mode 100755 Z/src/nglwidgets/icons/16x16/transform-scale.png create mode 100755 Z/src/nglwidgets/icons/16x16/traurig.gif create mode 100755 Z/src/nglwidgets/icons/16x16/video-x-generic.png create mode 100755 Z/src/nglwidgets/icons/16x16/view-fullscreen.png create mode 100755 Z/src/nglwidgets/icons/16x16/view-statistics.png create mode 100755 Z/src/nglwidgets/icons/16x16/weinend.gif create mode 100755 Z/src/nglwidgets/icons/16x16/x-office-address-book.png create mode 100755 Z/src/nglwidgets/icons/16x16/yellow-off-16.png create mode 100755 Z/src/nglwidgets/icons/16x16/yellow-on-16.png create mode 100755 Z/src/nglwidgets/icons/16x16/zoom-in.png create mode 100755 Z/src/nglwidgets/icons/16x16/zoom-out.png create mode 100755 Z/src/nglwidgets/icons/16x16/zunge.gif create mode 100755 Z/src/nglwidgets/icons/16x16/zwinker.gif create mode 100755 Z/src/nglwidgets/icons/22x22/dialogbuttonbox.png create mode 100755 Z/src/nglwidgets/icons/22x22/edit-redo.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-justify-center.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-justify-fill.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-justify-left.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-justify-right.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-stroke-color.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-text-bold.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-text-italic.png create mode 100755 Z/src/nglwidgets/icons/22x22/format-text-underline.png create mode 100755 Z/src/nglwidgets/icons/22x22/kdialog.png create mode 100755 Z/src/nglwidgets/icons/22x22/klineedit.png create mode 100755 Z/src/nglwidgets/icons/22x22/layer.png create mode 100755 Z/src/nglwidgets/icons/22x22/lkm_einsatz.png create mode 100755 Z/src/nglwidgets/icons/22x22/pushbutton.png create mode 100755 Z/src/nglwidgets/icons/22x22/scricon.png create mode 100755 Z/src/nglwidgets/icons/32x32/database.png create mode 100755 Z/src/nglwidgets/icons/32x32/hand_grenade_locations.png create mode 100755 Z/src/nglwidgets/icons/32x32/hideshow.png create mode 100755 Z/src/nglwidgets/icons/32x32/marker-end.png create mode 100755 Z/src/nglwidgets/icons/32x32/marker-start.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-eject.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-backward.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-faster.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-faster.svg create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-normal.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-normal.svg create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-slower.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-slower.svg create mode 100755 Z/src/nglwidgets/icons/32x32/media-play-slower.svg.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-playback-pause.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-playback-start-single.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-playback-start.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-playback-stop.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-record.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-seek-backward.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-seek-forward.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-skip-backward.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-skip-forward.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-vcr-nopause.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-vcr-normal.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-vcr-repeat.png create mode 100755 Z/src/nglwidgets/icons/32x32/media-vcr-withpause.png create mode 100755 Z/src/nglwidgets/icons/32x32/service_message.png create mode 100755 Z/src/nglwidgets/icons/32x32/showhide.png create mode 100755 Z/src/nglwidgets/icons/32x32/wireless.png create mode 100755 Z/src/nglwidgets/icons/LICENSE create mode 100755 Z/src/nglwidgets/icons/png/add.png create mode 100755 Z/src/nglwidgets/icons/png/add_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/add_tactical_sign_act.png create mode 100755 Z/src/nglwidgets/icons/png/add_tactical_sign_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/add_text_act.png create mode 100755 Z/src/nglwidgets/icons/png/add_text_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/address_book.png create mode 100755 Z/src/nglwidgets/icons/png/big_letters_act.png create mode 100755 Z/src/nglwidgets/icons/png/big_letters_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/camera_arrow_down.png create mode 100755 Z/src/nglwidgets/icons/png/camera_arrow_left.png create mode 100755 Z/src/nglwidgets/icons/png/camera_arrow_right.png create mode 100755 Z/src/nglwidgets/icons/png/camera_arrow_up.png create mode 100755 Z/src/nglwidgets/icons/png/center_object_in_map_act.png create mode 100755 Z/src/nglwidgets/icons/png/center_object_in_map_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/clear_plan_act.png create mode 100755 Z/src/nglwidgets/icons/png/clear_plan_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/copy_exercise.png create mode 100755 Z/src/nglwidgets/icons/png/copy_exercise_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/delete.png create mode 100755 Z/src/nglwidgets/icons/png/delete_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/delete_exercise.png create mode 100755 Z/src/nglwidgets/icons/png/delete_exercise_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/delete_graphic_eass.png create mode 100755 Z/src/nglwidgets/icons/png/delete_graphic_eass_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/deleteall.png create mode 100755 Z/src/nglwidgets/icons/png/download.png create mode 100755 Z/src/nglwidgets/icons/png/draw_ellipse_act.png create mode 100755 Z/src/nglwidgets/icons/png/draw_ellipse_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/draw_line.png create mode 100755 Z/src/nglwidgets/icons/png/draw_line_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/draw_polygon_act.png create mode 100755 Z/src/nglwidgets/icons/png/draw_polygon_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/draw_rectangle_act.png create mode 100755 Z/src/nglwidgets/icons/png/draw_rectangle_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/draw_spline.png create mode 100755 Z/src/nglwidgets/icons/png/draw_spline_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/eass_line.png create mode 100755 Z/src/nglwidgets/icons/png/eass_line_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/eass_polygon.png create mode 100755 Z/src/nglwidgets/icons/png/eass_polygon_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/edit_element_act.png create mode 100755 Z/src/nglwidgets/icons/png/edit_element_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/edith_graphic_eass.png create mode 100755 Z/src/nglwidgets/icons/png/edith_graphic_eass_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/fast_playback.png create mode 100755 Z/src/nglwidgets/icons/png/fast_playback_backward.png create mode 100755 Z/src/nglwidgets/icons/png/fast_playback_backward_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/fast_playback_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/fill_colour_act.png create mode 100755 Z/src/nglwidgets/icons/png/fill_colour_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/folder_open.png create mode 100755 Z/src/nglwidgets/icons/png/kosy_audio_control_act.png create mode 100755 Z/src/nglwidgets/icons/png/kosy_audio_control_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/kosy_radio_error_act.png create mode 100755 Z/src/nglwidgets/icons/png/kosy_radio_error_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/kosy_remote_control_act.png create mode 100755 Z/src/nglwidgets/icons/png/kosy_remote_control_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/line_color.png create mode 100755 Z/src/nglwidgets/icons/png/marker_left.png create mode 100755 Z/src/nglwidgets/icons/png/marker_left_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/marker_right.png create mode 100755 Z/src/nglwidgets/icons/png/marker_right_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/messages_new.png create mode 100755 Z/src/nglwidgets/icons/png/missionmarch.png create mode 100755 Z/src/nglwidgets/icons/png/missionmarch_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/normal_letters_act.png create mode 100755 Z/src/nglwidgets/icons/png/normal_letters_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/ok.png create mode 100755 Z/src/nglwidgets/icons/png/ok_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/paste_exercise.png create mode 100755 Z/src/nglwidgets/icons/png/paste_exercise_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/pause_playback.png create mode 100755 Z/src/nglwidgets/icons/png/pause_playback_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/polygonmap.png create mode 100755 Z/src/nglwidgets/icons/png/polygonmap_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/position_map.png create mode 100755 Z/src/nglwidgets/icons/png/position_map_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/preview.png create mode 100755 Z/src/nglwidgets/icons/png/printer.png create mode 100755 Z/src/nglwidgets/icons/png/redo.png create mode 100755 Z/src/nglwidgets/icons/png/redo_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/remove.png create mode 100755 Z/src/nglwidgets/icons/png/remove_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/rename_exercise.png create mode 100755 Z/src/nglwidgets/icons/png/rename_exercise_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/save.png create mode 100755 Z/src/nglwidgets/icons/png/save_as.png create mode 100755 Z/src/nglwidgets/icons/png/settings.png create mode 100755 Z/src/nglwidgets/icons/png/settings_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/start_playback.png create mode 100755 Z/src/nglwidgets/icons/png/start_playback_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/stop.png create mode 100755 Z/src/nglwidgets/icons/png/stop_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/stop_playback.png create mode 100755 Z/src/nglwidgets/icons/png/stop_playback_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/thick_line_act.png create mode 100755 Z/src/nglwidgets/icons/png/thick_line_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/turn_left.png create mode 100755 Z/src/nglwidgets/icons/png/turn_left_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/undo_act.png create mode 100755 Z/src/nglwidgets/icons/png/undo_act_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/zoom_in.png create mode 100755 Z/src/nglwidgets/icons/png/zoom_in_disabled.png create mode 100755 Z/src/nglwidgets/icons/png/zoom_out.png create mode 100755 Z/src/nglwidgets/icons/png/zoom_out_disabled.png create mode 100755 Z/src/nglwidgets/icons/svg/3d_viewer.svg create mode 100755 Z/src/nglwidgets/icons/svg/3d_viewer_config.svg create mode 100755 Z/src/nglwidgets/icons/svg/3d_viewer_config_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/3d_viewer_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/about.svg create mode 100755 Z/src/nglwidgets/icons/svg/about_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/ac_adapter_plugged_in.svg create mode 100755 Z/src/nglwidgets/icons/svg/access_rights.svg create mode 100755 Z/src/nglwidgets/icons/svg/access_rights_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/aircraft_sim.svg create mode 100755 Z/src/nglwidgets/icons/svg/announcement.svg create mode 100755 Z/src/nglwidgets/icons/svg/announcement_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/announcement_menu.svg create mode 100755 Z/src/nglwidgets/icons/svg/announcement_menu_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/application-exit.svg create mode 100755 Z/src/nglwidgets/icons/svg/arrow_back.svg create mode 100755 Z/src/nglwidgets/icons/svg/arrow_back_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/artillery_firings.svg create mode 100755 Z/src/nglwidgets/icons/svg/artillery_firings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/audio-volume-high.svg create mode 100755 Z/src/nglwidgets/icons/svg/audio-volume-low.svg create mode 100755 Z/src/nglwidgets/icons/svg/audio-volume-medium.svg create mode 100755 Z/src/nglwidgets/icons/svg/audio-volume-muted.svg create mode 100755 Z/src/nglwidgets/icons/svg/battery_mode.svg create mode 100755 Z/src/nglwidgets/icons/svg/camera_control.svg create mode 100755 Z/src/nglwidgets/icons/svg/camera_control_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/change_password.svg create mode 100755 Z/src/nglwidgets/icons/svg/change_password_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/chat.svg create mode 100755 Z/src/nglwidgets/icons/svg/chat_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/chemical_agents.svg create mode 100755 Z/src/nglwidgets/icons/svg/chemical_agents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/config_gobal_alarms.svg create mode 100755 Z/src/nglwidgets/icons/svg/config_gobal_alarms_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_arrow.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_buildings.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_buildings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_line_of_sight.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_line_of_sight_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_symbol_attributes.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_symbol_attributes_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_tunnels.svg create mode 100755 Z/src/nglwidgets/icons/svg/configure_tunnels_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_distance_measure.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_distance_measure_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_evaluation_topic.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_image_topic.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_lecture_topic.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_pdf_topic.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_snapshot.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_snapshot_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_terrain_profile.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_terrain_profile_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_thp.svg create mode 100755 Z/src/nglwidgets/icons/svg/create_thp_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/danger_areas.svg create mode 100755 Z/src/nglwidgets/icons/svg/debug-execute-from-cursor.svg create mode 100755 Z/src/nglwidgets/icons/svg/debug-execute-to-cursor.svg create mode 100755 Z/src/nglwidgets/icons/svg/default_operator_rights.svg create mode 100755 Z/src/nglwidgets/icons/svg/default_operator_rights_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_border_lines.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_border_lines_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_force_templates.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_force_templates_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_movement_simulation.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_movement_simulation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_player_types.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_player_types_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_position_system.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_position_system_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_presentation.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_presentation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_tactical_symbols.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_tactical_symbols_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_teams.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_teams_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_training_cycles.svg create mode 100755 Z/src/nglwidgets/icons/svg/define_training_cycles_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/delete_thp.svg create mode 100755 Z/src/nglwidgets/icons/svg/delete_thp_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/dialog-close.svg create mode 100755 Z/src/nglwidgets/icons/svg/dialog-ok-apply.svg create mode 100755 Z/src/nglwidgets/icons/svg/dialog-ok.svg create mode 100755 Z/src/nglwidgets/icons/svg/display_oc_evaluations.svg create mode 100755 Z/src/nglwidgets/icons/svg/display_oc_evaluations_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/display_reports.svg create mode 100755 Z/src/nglwidgets/icons/svg/display_reports_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/document-edit.svg create mode 100755 Z/src/nglwidgets/icons/svg/document-new.svg create mode 100755 Z/src/nglwidgets/icons/svg/document-open-data.svg create mode 100755 Z/src/nglwidgets/icons/svg/document-open.svg create mode 100755 Z/src/nglwidgets/icons/svg/document-properties.svg create mode 100755 Z/src/nglwidgets/icons/svg/documents.svg create mode 100755 Z/src/nglwidgets/icons/svg/documents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/download.svg create mode 100755 Z/src/nglwidgets/icons/svg/draw-bezier-curves.svg create mode 100755 Z/src/nglwidgets/icons/svg/edit-cut.svg create mode 100755 Z/src/nglwidgets/icons/svg/edit_evaluation_marker.svg create mode 100755 Z/src/nglwidgets/icons/svg/edit_evaluation_marker_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/electronical_warfare_measures.svg create mode 100755 Z/src/nglwidgets/icons/svg/electronical_warfare_measures_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/evaluate.svg create mode 100755 Z/src/nglwidgets/icons/svg/evaluate_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/evaluation_elements.svg create mode 100755 Z/src/nglwidgets/icons/svg/evaluation_elements_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/execute_presentation.svg create mode 100755 Z/src/nglwidgets/icons/svg/execute_presentation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/exercise_force.svg create mode 100755 Z/src/nglwidgets/icons/svg/exercise_force_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/exercise_purpose.svg create mode 100755 Z/src/nglwidgets/icons/svg/exercise_purpose_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/export_documents.svg create mode 100755 Z/src/nglwidgets/icons/svg/export_documents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/fill_pattern.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_barriers.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_barriers_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_border_lines.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_border_lines_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_collapse_expand.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_collapse_expand_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_effect_simulation.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_effect_simulation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_firings.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_firings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_line_of_sight.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_line_of_sight_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_map_settings.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_map_settings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_map_settings_load.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_map_settings_load_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_maps_settings_save.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_maps_settings_save_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_nbc_agents.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_nbc_agents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_nc_agents.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_nc_agents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_player.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_player_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_teams.svg create mode 100755 Z/src/nglwidgets/icons/svg/filter_teams_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/fixed_video_announcement.svg create mode 100755 Z/src/nglwidgets/icons/svg/fixed_video_announcement_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/force_composition.svg create mode 100755 Z/src/nglwidgets/icons/svg/force_composition_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/force_organization.svg create mode 100755 Z/src/nglwidgets/icons/svg/force_organization_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/force_player_configuration.svg create mode 100755 Z/src/nglwidgets/icons/svg/force_player_configuration_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/freq_plan.svg create mode 100755 Z/src/nglwidgets/icons/svg/function_key_toolbar.svg create mode 100755 Z/src/nglwidgets/icons/svg/function_key_toolbar_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/getpos.svg create mode 100755 Z/src/nglwidgets/icons/svg/global_alarms_history.svg create mode 100755 Z/src/nglwidgets/icons/svg/global_alarms_history_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/global_exercise_settings.svg create mode 100755 Z/src/nglwidgets/icons/svg/global_exercise_settings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/go-home.svg create mode 100755 Z/src/nglwidgets/icons/svg/hand_grenade_locations.svg create mode 100755 Z/src/nglwidgets/icons/svg/help_index.svg create mode 100755 Z/src/nglwidgets/icons/svg/help_index_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_buildings.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_buildings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_documents.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_documents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_images.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_images_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_msdl.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_pdf_document.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_pdf_document_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_video.svg create mode 100755 Z/src/nglwidgets/icons/svg/import_video_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/insert_script.svg create mode 100755 Z/src/nglwidgets/icons/svg/karte.svg create mode 100755 Z/src/nglwidgets/icons/svg/layer.svg create mode 100755 Z/src/nglwidgets/icons/svg/line_styles.svg create mode 100755 Z/src/nglwidgets/icons/svg/list-add-user.svg create mode 100755 Z/src/nglwidgets/icons/svg/list-remove-user.svg create mode 100755 Z/src/nglwidgets/icons/svg/load.svg create mode 100755 Z/src/nglwidgets/icons/svg/load_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/load_global_filter.svg create mode 100755 Z/src/nglwidgets/icons/svg/load_global_filter_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/logout.svg create mode 100755 Z/src/nglwidgets/icons/svg/logout_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/map_context_menu.svg create mode 100755 Z/src/nglwidgets/icons/svg/map_context_menu_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/map_settings.svg create mode 100755 Z/src/nglwidgets/icons/svg/map_settings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/marke.svg create mode 100755 Z/src/nglwidgets/icons/svg/marker-end.svg create mode 100755 Z/src/nglwidgets/icons/svg/marker-start.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-flash.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-play-backward.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-play-slower.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-record.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-seek-backward.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-seek-forward.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-skip-backward.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-skip-forward.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-vcr-nopause.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-vcr-normal.svg create mode 100755 Z/src/nglwidgets/icons/svg/media-vcr-withpause.svg create mode 100755 Z/src/nglwidgets/icons/svg/messages.svg create mode 100755 Z/src/nglwidgets/icons/svg/messages_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/metereological_data.svg create mode 100755 Z/src/nglwidgets/icons/svg/metereological_data_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/mgrs_grid.svg create mode 100755 Z/src/nglwidgets/icons/svg/mgrs_grid_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/mine_barrier_corridor.svg create mode 100755 Z/src/nglwidgets/icons/svg/mine_barrier_corridor_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/mine_barriers.svg create mode 100755 Z/src/nglwidgets/icons/svg/mine_barriers_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/mini_map.svg create mode 100755 Z/src/nglwidgets/icons/svg/mini_map_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/mlvs_control.svg create mode 100755 Z/src/nglwidgets/icons/svg/mobile_video.svg create mode 100755 Z/src/nglwidgets/icons/svg/mobile_video_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/mortar_ammunition_administration.svg create mode 100755 Z/src/nglwidgets/icons/svg/mortar_ammunition_administration_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/mortar_ammunition_firings.svg create mode 100755 Z/src/nglwidgets/icons/svg/mortar_ammunition_firings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/network-wireless.svg create mode 100755 Z/src/nglwidgets/icons/svg/new_documents.svg create mode 100755 Z/src/nglwidgets/icons/svg/new_mail_indicator.svg create mode 100755 Z/src/nglwidgets/icons/svg/nuclear_agents.svg create mode 100755 Z/src/nglwidgets/icons/svg/object-group.svg create mode 100755 Z/src/nglwidgets/icons/svg/object-ungroup.svg create mode 100755 Z/src/nglwidgets/icons/svg/objects_define_areas.svg create mode 100755 Z/src/nglwidgets/icons/svg/objects_define_areas_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_aar_preparation.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_aar_preparation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_composition.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_composition_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_evaluation_schemes.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_evaluation_schemes_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_player_configuration.svg create mode 100755 Z/src/nglwidgets/icons/svg/oc_player_configuration_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/operator_administration.svg create mode 100755 Z/src/nglwidgets/icons/svg/operator_administration_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/organize_documents.svg create mode 100755 Z/src/nglwidgets/icons/svg/organize_documents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/organize_library.svg create mode 100755 Z/src/nglwidgets/icons/svg/organize_library_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/overlay_plans.svg create mode 100755 Z/src/nglwidgets/icons/svg/overlay_plans_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/overlays.svg create mode 100755 Z/src/nglwidgets/icons/svg/phase_def.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_force_collapse.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_force_expand.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_force_left.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_force_right.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_markup_3d.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_movementtrack.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_nbc.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_set_player_mode.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_show_bite.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_show_building.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_tact_status_history.svg create mode 100755 Z/src/nglwidgets/icons/svg/pi_type_weaponrange.svg create mode 100755 Z/src/nglwidgets/icons/svg/planned_training_cycles.svg create mode 100755 Z/src/nglwidgets/icons/svg/plans.svg create mode 100755 Z/src/nglwidgets/icons/svg/plans_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/playback_audio.svg create mode 100755 Z/src/nglwidgets/icons/svg/playback_audio_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/playback_situation.svg create mode 100755 Z/src/nglwidgets/icons/svg/playback_situation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/playback_video.svg create mode 100755 Z/src/nglwidgets/icons/svg/playback_video_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/player_equipment.svg create mode 100755 Z/src/nglwidgets/icons/svg/player_equipment_check.svg create mode 100755 Z/src/nglwidgets/icons/svg/player_equipment_check_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/player_mode.svg create mode 100755 Z/src/nglwidgets/icons/svg/preferences-web-browser-cache.svg create mode 100755 Z/src/nglwidgets/icons/svg/prepare_thp.svg create mode 100755 Z/src/nglwidgets/icons/svg/prepare_thp_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/presets.svg create mode 100755 Z/src/nglwidgets/icons/svg/presets_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/primary_map_position.svg create mode 100755 Z/src/nglwidgets/icons/svg/primary_map_position_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/primary_map_toolbar.svg create mode 100755 Z/src/nglwidgets/icons/svg/primary_map_toolbar_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/proj_audio.svg create mode 100755 Z/src/nglwidgets/icons/svg/projection.svg create mode 100755 Z/src/nglwidgets/icons/svg/raster.svg create mode 100755 Z/src/nglwidgets/icons/svg/raster_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_ammunition_left.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_ammunition_left_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_ammunition_resupply.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_ammunition_resupply_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_awes.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_awes_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_combat_effectiveness.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_combat_effectiveness_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_combat_power.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_combat_power_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_explosive_devices.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_explosive_devices_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_maintenance.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_maintenance_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_mine_barrier.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_mine_barrier_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_mortar_firings.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_mortar_firings_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_nbc_events.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_nbc_events_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_nc_events.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_nc_events_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_treatment.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_treatment_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_treatmentmaintanance.svg create mode 100755 Z/src/nglwidgets/icons/svg/report_treatmentmaintanance_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/save_preferences.svg create mode 100755 Z/src/nglwidgets/icons/svg/save_preferences_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/screenshot.svg create mode 100755 Z/src/nglwidgets/icons/svg/screenshot_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/secondary_map_position.svg create mode 100755 Z/src/nglwidgets/icons/svg/secondary_map_position_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/secondary_map_toolbar.svg create mode 100755 Z/src/nglwidgets/icons/svg/secondary_map_toolbar_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/select_player.svg create mode 100755 Z/src/nglwidgets/icons/svg/select_player_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/select_training_areas.svg create mode 100755 Z/src/nglwidgets/icons/svg/select_training_areas_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/select_training_cylces.svg create mode 100755 Z/src/nglwidgets/icons/svg/select_training_cylces_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/send_player_message.svg create mode 100755 Z/src/nglwidgets/icons/svg/send_player_message_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_exercise_process.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_exercise_process_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_force_visibility.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_force_visibility_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_home_transparency.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_home_transparency_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_marker_situation.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_marker_situation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_marker_video.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_marker_video_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_markers_audio.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_markers_audio_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_player_mode.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_player_mode_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_player_status.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_player_status_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_view_position.svg create mode 100755 Z/src/nglwidgets/icons/svg/set_view_position_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_building_configuration.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_building_configuration_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_distance_measure.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_distance_measure_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_line_of_sight.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_line_of_sight_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_terrain_profile.svg create mode 100755 Z/src/nglwidgets/icons/svg/show_terrain_profile_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/simulated_players.svg create mode 100755 Z/src/nglwidgets/icons/svg/simulated_players_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/situation.svg create mode 100755 Z/src/nglwidgets/icons/svg/situation_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/status_bar.svg create mode 100755 Z/src/nglwidgets/icons/svg/status_bar_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/support_documents.svg create mode 100755 Z/src/nglwidgets/icons/svg/support_documents_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/switch_display.svg create mode 100755 Z/src/nglwidgets/icons/svg/switch_display_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/switch_to_primary_map.svg create mode 100755 Z/src/nglwidgets/icons/svg/switch_to_primary_map_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/switch_to_sec_map.svg create mode 100755 Z/src/nglwidgets/icons/svg/switch_to_sec_map_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/symbol_display.svg create mode 100755 Z/src/nglwidgets/icons/svg/symbol_display_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/system_status.svg create mode 100755 Z/src/nglwidgets/icons/svg/system_status_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/tactical_organization.svg create mode 100755 Z/src/nglwidgets/icons/svg/tactical_organization_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/tactical_symbol.svg create mode 100755 Z/src/nglwidgets/icons/svg/tactical_symbol_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/target.svg create mode 100755 Z/src/nglwidgets/icons/svg/terminal_window.svg create mode 100755 Z/src/nglwidgets/icons/svg/terminal_window_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/toolbar_editor.svg create mode 100755 Z/src/nglwidgets/icons/svg/toolbar_editor_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/translation_editor.svg create mode 100755 Z/src/nglwidgets/icons/svg/update_player_position.svg create mode 100755 Z/src/nglwidgets/icons/svg/update_player_position_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/video_menu.svg create mode 100755 Z/src/nglwidgets/icons/svg/video_menu_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/view-statistics.svg create mode 100755 Z/src/nglwidgets/icons/svg/visible_teams.svg create mode 100755 Z/src/nglwidgets/icons/svg/voice_communication.svg create mode 100755 Z/src/nglwidgets/icons/svg/voice_communication_access.svg create mode 100755 Z/src/nglwidgets/icons/svg/voice_communication_access_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/voice_communication_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/weapon_firing.svg create mode 100755 Z/src/nglwidgets/icons/svg/weapon_firing_disabled.svg create mode 100755 Z/src/nglwidgets/icons/svg/wireless.svg create mode 100755 Z/src/nglwidgets/ngldialog.cpp create mode 100755 Z/src/nglwidgets/ngldialog.h create mode 100755 Z/src/nglwidgets/ngldialogbuttonbox.cpp create mode 100755 Z/src/nglwidgets/ngldialogbuttonbox.h create mode 100755 Z/src/nglwidgets/nglmainwindow.cpp create mode 100755 Z/src/nglwidgets/nglmainwindow.h create mode 100755 Z/src/nglwidgets/nglpdfdocument.cpp create mode 100755 Z/src/nglwidgets/nglpdfdocument.h create mode 100755 Z/src/nglwidgets/nglpdfpage.cpp create mode 100755 Z/src/nglwidgets/nglpdfpage.h create mode 100755 Z/src/nglwidgets/nglpdfwidget.cpp create mode 100755 Z/src/nglwidgets/nglpdfwidget.h create mode 100755 Z/src/nglwidgets/nglpdfwidget.ui create mode 100755 Z/src/nglwidgets/nglresources.qrc create mode 100755 Z/src/nglwidgets/nglstandardbutton.cpp create mode 100755 Z/src/nglwidgets/nglstandardbutton.h create mode 100755 Z/src/nglwidgets/ngltreeitem.cpp create mode 100755 Z/src/nglwidgets/ngltreeitem.h create mode 100755 Z/src/nglwidgets/ngltreemodel.cpp create mode 100755 Z/src/nglwidgets/ngltreemodel.h create mode 100755 Z/src/nglwidgets/nglwidgets_export.h create mode 100755 Z/src/qsql_informix/CMakeLists.txt create mode 100755 Z/src/qsql_informix/FindCrypt.cmake create mode 100755 Z/src/qsql_informix/FindIClientSDK.cmake create mode 100755 Z/src/qsql_informix/qsql_informix.cpp create mode 100755 Z/src/qsql_informix/qsql_informix.h create mode 100755 Z/src/qsql_informix/qsql_informix.json create mode 100755 Z/src/qsql_informix/qsql_informix_plugin.cpp create mode 100755 Z/src/qsql_informix/qsql_informix_test.cpp create mode 100755 Z/src/qsql_informix/qsql_informix_utils.cpp create mode 100755 Z/src/qsql_informix/qsql_informix_utils.h create mode 100755 Z/src/tcpserver/CMakeLists.txt create mode 100755 Z/src/tcpserver/cbi_help.cpp create mode 100755 Z/src/tcpserver/cbi_help.h create mode 100755 Z/src/tcpserver/cbi_pingpong.cpp create mode 100755 Z/src/tcpserver/cbi_pingpong.h create mode 100755 Z/src/tcpserver/cbi_quit.cpp create mode 100755 Z/src/tcpserver/cbi_quit.h create mode 100755 Z/src/tcpserver/cbi_recvfile.cpp create mode 100755 Z/src/tcpserver/cbi_recvfile.h create mode 100755 Z/src/tcpserver/cbi_sendfile.cpp create mode 100755 Z/src/tcpserver/cbi_sendfile.h create mode 100755 Z/src/tcpserver/cbi_shutdown.cpp create mode 100755 Z/src/tcpserver/cbi_shutdown.h create mode 100755 Z/src/tcpserver/commandinterface.cpp create mode 100755 Z/src/tcpserver/commandinterface.h create mode 100755 Z/src/tcpserver/tcpserver.cpp create mode 100755 Z/src/tcpserver/tcpserver.h create mode 100755 Z/src/tcpserver/tcpserver_export.h create mode 100755 Z/src/tcpserver/tcpserver_logger.h create mode 100755 Z/src/tcpserver/tcpserver_test.cpp create mode 100755 Z/src/tcpserver/workerbase.cpp create mode 100755 Z/src/tcpserver/workerbase.h create mode 100755 cmake/DoxygenMacros.cmake create mode 100755 cmake/FindArcGIS.cmake create mode 100755 cmake/FindBgViewer.cmake create mode 100755 cmake/FindBotan2.cmake create mode 100755 cmake/FindKDChart.cmake create mode 100755 cmake/FindKDReports.cmake create mode 100755 cmake/FindLibraryWithDebug.cmake create mode 100755 cmake/FindNGS.cmake create mode 100755 cmake/FindPopplerQt5.cmake create mode 100755 cmake/FindRTI.cmake create mode 100755 cmake/FindSchusstafel.cmake create mode 100755 cmake/FindTMSIF.cmake create mode 100755 cmake/FindVLC.cmake create mode 100755 cmake/FindXSD.cmake create mode 100755 cmake/MacroCodeGenIdl.cmake create mode 100755 cmake/MacroEnsureOutOfSourceBuild.cmake create mode 100755 cmake/MacroRTIDDSGen.cmake create mode 100755 cmake/NGLMacros.cmake create mode 100755 cmake/make_qt_help.py create mode 100755 cmake/ngl_dep_test_main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 000000000..cc9cd36f1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,289 @@ +# +# Haupt CMakeLists.txt für das Projekt TDS +# +# $Id$ +# $HeadURL$ +# $Author$ +# +# Setzen von CMAKE_INSTALL_PREFIX auf "/shd/CTC" falls nicht über Kommandozeile angegeben +# + +CMAKE_MINIMUM_REQUIRED(VERSION 3.5.0) +IF(POLICY CMP0069) + CMAKE_POLICY(SET CMP0069 NEW) # cmake >= 3.9.0 - INTERPROCEDURAL_OPTIMIZATION behavior +ENDIF() +IF(POLICY CMP0071) + CMAKE_POLICY(SET CMP0071 NEW) # cmake >= 3.10.0 - automatically process generated sources with AUTOMOC +ENDIF() +IF(POLICY CMP0072) + CMAKE_POLICY(SET CMP0072 NEW) # cmake >= 3.11.0 - prefer libOpenGL.so over legacy libGL.so +ENDIF() + + +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/shd/CTC" CACHE STRING "Install path prefix, prepended onto install directories." FORCE) +ENDIF() +# +# # Setzen von CMAKE_BUILD_TYPE auf "Debug" falls nicht über Kommandozeile angegeben +# +IF(NOT DEFINED CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE) +ENDIF() +ADD_DEFINITIONS(-DEXPORT_BDV_TOPIC_AS_JSON) +SET(_ver "1.2.0") +IF(DEFINED LTS_VERSION_MAJOR AND DEFINED LTS_VERSION_MINOR AND DEFINED LTS_VERSION_PATCH) + SET(_ver "${LTS_VERSION_MAJOR}.${LTS_VERSION_MINOR}.${LTS_VERSION_PATCH}") +ENDIF() +PROJECT(LTS VERSION ${_ver}) +MESSAGE(STATUS "LTS Version: ${LTS_VERSION_MAJOR}.${LTS_VERSION_MINOR}.${LTS_VERSION_PATCH}") +SET(LTS_VERSION_DATE "01.01.2018" CACHE STRING "The date when this software was compiled") +ADD_DEFINITIONS(-DLTS_VERSION_MAJOR=\"${LTS_VERSION_MAJOR}\") +ADD_DEFINITIONS(-DLTS_VERSION_MINOR=\"${LTS_VERSION_MINOR}\") +ADD_DEFINITIONS(-DLTS_VERSION_PATCH=\"${LTS_VERSION_PATCH}\") +ADD_DEFINITIONS(-DLTS_VERSION_DATE=\"${LTS_VERSION_DATE}\") +IF(JENKINS_BUILD_NUMBER) + ADD_DEFINITIONS(-DJENKINS_BUILD_NUMBER=\"${JENKINS_BUILD_NUMBER}\") +ELSE() + ADD_DEFINITIONS(-DJENKINS_BUILD_NUMBER=\"unknown\") +ENDIF() + +ADD_DEFINITIONS(-DAPP6C) +SET(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 14) +SET(CMAKE_CXX_STANDARD_REQUIRED 14) +SET(CMAKE_VISIBILITY_INLINES_HIDDEN ON) +SET(CMAKE_CXX_VISIBILITY_PRESET hidden) +SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + +IF(CMAKE_VERSION VERSION_GREATER 3.15.9) + OPTION(USE_UNITY_BUILDS "Use Unity builds to speed up compilation (cmake 3.16 or newer required!)" OFF) + IF (USE_UNITY_BUILDS) + SET(CMAKE_UNITY_BUILD ON) + SET(CMAKE_UNITY_BUILD_BATCH_SIZE 40) + ENDIF() +ENDIF() + +IF(WIN32) + SET(EXTERNAL_LIBRARY_DIR "C:/Development/Projekte/SituationMap/ExtFw" CACHE STRING "Library dir with all external dependencies") + LIST(APPEND CMAKE_PREFIX_PATH "${EXTERNAL_LIBRARY_DIR}") + LIST(APPEND CMAKE_PROGRAM_PATH "${EXTERNAL_LIBRARY_DIR}/bin;${EXTERNAL_LIBRARY_DIR}/dev-utils/bin") +ENDIF() + +ENABLE_TESTING() +INCLUDE(CTest) +CONFIGURE_FILE(CTestCustom.ctest ${CMAKE_BINARY_DIR}/CTestCustom.ctest COPYONLY) +CONFIGURE_FILE(lts-cc.conf ${CMAKE_BINARY_DIR}/lts-cc.conf.distrib COPYONLY) + +SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +IF(WIN32) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +ELSE(WIN32) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) +ENDIF() + +# +# Disallow in-source build +# +INCLUDE(MacroEnsureOutOfSourceBuild) + +macro_ensure_out_of_source_build("In-Source build nicht erlaubt!") + +# +# Qt ist wichtig - zuerst suchen +# +SET(CMAKE_AUTOMOC TRUE) +SET(QT_USE_IMPORTED_TARGETS TRUE) +FIND_PACKAGE(Qt5 5.9.0 COMPONENTS Concurrent Core Gui Location LinguistTools + Network OpenGL PrintSupport Sensors Multimedia + Sql Svg SerialPort Test UiTools WebSockets + WebEngineCore WebEngineWidgets Widgets + Xml XmlPatterns + REQUIRED) + +MESSAGE(STATUS "Qt version is ${Qt5Core_VERSION}") +ADD_DEFINITIONS(-DQT_USE_QSTRINGBUILDER) +ADD_DEFINITIONS(-DQT_NO_CAST_TO_ASCII) +ADD_DEFINITIONS(-DQT_NO_CAST_FROM_ASCII) +ADD_DEFINITIONS(-DQT_NO_URL_CAST_FROM_STRING) +ADD_DEFINITIONS(-DQT_DEPRECATED_WARNINGS) +ADD_DEFINITIONS(-DQT_NO_CAST_FROM_BYTEARRAY) +#ADD_DEFINITIONS(-DQT_NO_DEPRECATED) +ADD_DEFINITIONS(-DQT_DISABLE_DEPRECATED_BEFORE=0x050900) +ADD_DEFINITIONS(-DQT_NO_FOREACH) +IF(NOT WIN32) + ADD_DEFINITIONS(-DQT_STRICT_ITERATORS) +ENDIF() + +# +# Ein paar NGL-spezifische Macros +# +INCLUDE(NGLMacros) + +# +# Projektspezifische Einstellungen? +# +NGL_INSTALL(SV AAR WS FILES lts-cc.conf DESTINATION . RENAME lts-cc.conf.distrib) + +OPTION(ETS_MODE "Build for ETS (No B-Contamination etc)" OFF) +IF(ETS_MODE) + ADD_DEFINITIONS(-DETS_MODE) +ENDIF() +OPTION(TABLET_MODE "Build for TABLET " OFF) +IF(TABLET_MODE) + ADD_DEFINITIONS(-DTABLET_MODE) +ENDIF() + +OPTION(GUEZ_MODE "Build for GUEZ " ON) +IF(GUEZ_MODE) + ADD_DEFINITIONS(-DGUEZ_MODE) +ENDIF() + +# +# Doxygen +# +INCLUDE(DoxygenMacros) +IF(NOT DOXYGEN_OUT_DIR) + SET(DOXYGEN_OUT_DIR ${CMAKE_BINARY_DIR}/doxygen) +ENDIF() +ADD_DOXYGEN_TARGET(TDS ${CMAKE_SOURCE_DIR}/doxygen/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile + ${CMAKE_SOURCE_DIR}/doxygen/rheinmetall_defence_logo.jpg + ${DOXYGEN_OUT_DIR}) + +IF(NOT DOXYGEN_OUT_DIR_2025) + SET(DOXYGEN_OUT_DIR_2025 ${CMAKE_BINARY_DIR}/doxygen2025) +ENDIF() +ADD_DOXYGEN_TARGET(TDS2025 ${CMAKE_SOURCE_DIR}/doxygen/Doxyfile2025.in ${CMAKE_BINARY_DIR}/Doxyfile + ${CMAKE_SOURCE_DIR}/doxygen/rheinmetall_defence_logo.jpg + ${DOXYGEN_OUT_DIR_2025}) + +# +# Compilerflags +# +IF(WIN32) + ADD_DEFINITIONS(-DWIN32 -D_USE_MATH_DEFINES -D_WIN32_WINNT=0x0501 -DUNICODE) +ELSE() + ADD_DEFINITIONS(-D_LINUX) +ENDIF() + +IF(MSVC) + # C4250: 'class1' : inherits 'class2::member' via dominance + # C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' + # C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow) + # C4496: 'function': was declared deprecated + # C4267: 'var' : conversion from 'size_t' to 'type', possible loss of data + ADD_DEFINITIONS(-wd4250 + -wd4251 + -wd4290 + -wd4496 + -wd4267 + -D_CRT_SECURE_NO_DEPRECATE + -D_CRT_NONSTDC_NO_DEPRECATE + -D_SCL_SECURE_NO_WARNINGS + -D_WINSOCK_DEPRECATED_NO_WARNINGS + /bigobj + ) + # komplette Programmoptimierung + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + # .pdb - Datei nicht gefunden + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4099") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNORE:4099") + # min() und max() nicht als Macros + ADD_DEFINITIONS(-DNOMINMAX) + SET(CMAKE_MSVCIDE_RUN_PATH "" CACHE PATH "Run path to use when starting programs from MSVC") +ENDIF() + +IF(UNIX) + # Alle Warnungen aktivieren + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wmissing-include-dirs") + # disable + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-overloaded-virtual") + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.0) + MESSAGE(FATAL_ERROR "gcc 4.8 or higher is required to build TDS: ${CMAKE_CXX_COMPILER_VERSION}") + ENDIF() + IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9.99) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-attribute=const") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-final-types") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-final-methods") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override") + ENDIF() + ENDIF() +ENDIF() + +OPTION(USE_IPO "Use interprocedural optimizations (cmake 3.9 or higher required)" OFF) +IF (USE_IPO AND CMAKE_VERSION VERSION_GREATER 3.8.9) + INCLUDE(CheckIPOSupported) + check_ipo_supported(RESULT result OUTPUT output) + IF(result) + SET(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + ELSE() + MESSAGE(WARNING "IPO is not supported: ${output}") + ENDIF() +ENDIF() + +OPTION(USE_ASAN "Use Address Sanitizer (current Clang only)" OFF) +IF (USE_ASAN) + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + MESSAGE(STATUS "enable Address Sanitizer with Clang (is: ${CMAKE_CXX_COMPILER_ID})") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1") + ELSE() + MESSAGE(STATUS "Address Sanitizer only supported with Clang (is: ${CMAKE_CXX_COMPILER_ID})") + ENDIF() +ENDIF(USE_ASAN) + +OPTION(USE_UBSAN "Use UndefinedBehavior Sanitizer (current Clang only)" OFF) +IF (USE_UBSAN) + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + ELSE() + MESSAGE(STATUS "UndefinedBehavior only supported with Clang (is: ${CMAKE_CXX_COMPILER_ID})") + ENDIF() +ENDIF(USE_UBSAN) + +OPTION(BUILD_RPM "Build a RPM - install script in scripts subdir" OFF) + +IF(BUILD_RPM) + ADD_SUBDIRECTORY(scripts) +ELSE() + ADD_DEFINITIONS(-DLTS_DEBUG) +ENDIF() + +IF (NOT DEFINED _pname) + IF(GUEZ_MODE) + SET (_pname "guez") + ADD_DEFINITIONS(-DPROJECTBUILD="guez") + MESSAGE(STATUS "NO ProjectName givin! BUT GUEZ_MODE set PROJECTBUILD to guez") + ELSE() + MESSAGE(WARNING "NO ProjectName givin! Can't install coresponding lts-cc.conf! and PROJECTBUILD is empty") + ADD_DEFINITIONS(-DPROJECTBUILD="") + ENDIF() +ELSE() + MESSAGE(STATUS "ProjectName givin! PROJECTBUILD is ${_pname} ") + ADD_DEFINITIONS(-DPROJECTBUILD=\"${_pname}\") +ENDIF() + + +# +# DDS benoetigt zwingend RTI +# +FIND_PACKAGE(RTI REQUIRED) + +ADD_SUBDIRECTORY(TetraIF) +ADD_SUBDIRECTORY(Z/src) +ADD_SUBDIRECTORY(Lts) +# at last, to make sure we get all targets in NGL_TS_TARGETS property +ADD_SUBDIRECTORY(translations) +#----------------------------------------------------------------------------------------------------- + + +OPTION(BUILD_QAV "Build script for local QAV analysis" OFF) +IF (BUILD_QAV) + ADD_SUBDIRECTORY(qav) +ENDIF() diff --git a/TetraIF/CMakeLists.txt b/TetraIF/CMakeLists.txt new file mode 100644 index 000000000..2440f9340 --- /dev/null +++ b/TetraIF/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +ADD_SUBDIRECTORY(CoPrtCnv) +ADD_SUBDIRECTORY(LogView) +ADD_SUBDIRECTORY(PrtCnv) diff --git a/TetraIF/CoPrtCnv/CMakeLists.txt b/TetraIF/CoPrtCnv/CMakeLists.txt new file mode 100644 index 000000000..b90771809 --- /dev/null +++ b/TetraIF/CoPrtCnv/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(my_SRCS + tetra_telegram_ids.h + CoPrtCnvCentralTelegram.cpp + CoPrtCnvCentralTelegram.hpp + CoPrtCnvHexDumpHelper.cpp + CoPrtCnvHexDumpHelper.hpp + CoPrtCnvInjectionHeader.hpp + CoPrtCnvLogHeader.hpp + CoPrtCnvRadioTelegram.cpp + CoPrtCnvRadioTelegram.hpp + CoPrtCnvTelegramConverter.hpp + CoPrtCnvTelegramConverterNewIcd.cpp +) + +NGL_ADD_LIBRARY2(AAR SV CoPrtCnv SHARED ${my_SRCS} ${my_HDRS}) +NGL_TARGET_LINK_LIBRARIES(CoPrtCnv + PUBLIC + NGLLogger + tabTelegrams +) +NGL_TARGET_INCLUDE_DIRECTORIES(CoPrtCnv + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) diff --git a/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp new file mode 100644 index 000000000..535211703 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp @@ -0,0 +1,82 @@ + + + +#include "CoPrtCnvCentralTelegram.hpp" +#include + +namespace N_CoPrtCnv +{ + +void CoPrtCnvCentralTelegram::setData(const QByteArray &data) +{ + m_data = data; + m_json = QJsonObject(); +} + +QByteArray CoPrtCnvCentralTelegram::data() +{ + ensureByteArray(); + return m_data; +} + +QJsonObject CoPrtCnvCentralTelegram::json() +{ + ensureJson(); + return m_json; +} + +QJsonObject CoPrtCnvCentralTelegram::jsonData() +{ + return json()[QStringLiteral("data")].toObject(); +} + +TrainingAreaBase::TetraIcd::TelegramId CoPrtCnvCentralTelegram::telegramId() +{ + if (m_telegramId != TrainingAreaBase::TetraIcd::UNKNOWN) + return m_telegramId; + + ensureJson(); + m_telegramId = static_cast(m_json[QStringLiteral("typeId")].toInt()); + return m_telegramId; +} + +void CoPrtCnvCentralTelegram::setCounter(qint32 counter) +{ + if (m_json.isEmpty()) + m_json = QJsonDocument::fromJson(m_data).object(); + m_json[QStringLiteral("counter")] = counter; + m_data.clear(); +} + +qint32 CoPrtCnvCentralTelegram::counter() +{ + ensureJson(); + const QString key(QStringLiteral("counter")); + const QJsonValue sendCounter(m_json[key]); + if (!sendCounter.isDouble()) + throw TrainingAreaBase::TetraIcd::JsonException(m_json, key); + return sendCounter.toInt(-1); +} + +void CoPrtCnvCentralTelegram::ensureJson() +{ + if (m_json.isEmpty()) + { + if (m_data.isEmpty()) + return; + m_json = QJsonDocument::fromJson(m_data).object(); + } +} + +void CoPrtCnvCentralTelegram::ensureByteArray() +{ + if (m_data.isEmpty()) + { + if (m_json.isEmpty()) + return; + m_data = QJsonDocument(m_json).toJson(QJsonDocument::Compact); + } +} + + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp new file mode 100644 index 000000000..dbb062fa8 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp @@ -0,0 +1,60 @@ + + + +#pragma once + +#include +#include +#include +#include + +namespace N_CoPrtCnv +{ + + + class COPRTCNV_EXPORT CoPrtCnvCentralTelegram final + { + public: + explicit CoPrtCnvCentralTelegram(TrainingAreaBase::TetraIcd::TelegramId telegramId) + : m_telegramId(telegramId) + {} + explicit CoPrtCnvCentralTelegram(const QByteArray &data) + : m_data(data) + , m_telegramId(TrainingAreaBase::TetraIcd::UNKNOWN) + {} + CoPrtCnvCentralTelegram(const QByteArray &data, TrainingAreaBase::TetraIcd::TelegramId telegramId) + : m_data(data) + , m_telegramId(telegramId) + {} + CoPrtCnvCentralTelegram(const QByteArray &data, const QJsonObject &json, TrainingAreaBase::TetraIcd::TelegramId telegramId) + : m_data(data) + , m_json(json) + , m_telegramId(telegramId) + {} + + explicit CoPrtCnvCentralTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram &tele) + : m_telegramId(tele.id()) + { + m_json[QStringLiteral("type")] = tele.type(); + m_json[QStringLiteral("typeId")] = tele.id(); + m_json[QStringLiteral("data")] = tele.toJson(); + } + + void setData(const QByteArray &data); + QByteArray data(); + QJsonObject json(); + QJsonObject jsonData(); + TrainingAreaBase::TetraIcd::TelegramId telegramId(); + void setCounter(qint32 counter); + qint32 counter(); + + private: + void ensureJson(); + void ensureByteArray(); + private: + QByteArray m_data; + QJsonObject m_json; + TrainingAreaBase::TetraIcd::TelegramId m_telegramId; + }; + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp new file mode 100644 index 000000000..9981d431a --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + +#include "CoPrtCnvHexDumpHelper.hpp" +#include "CoPrtCnvRadioTelegram.hpp" + +#include +#include + +static std::string dumpSammeldeaktivierung(const N_CoPrtCnv::CoPrtCnvRadioTelegram* sammelTelegram) +{ + const int ANZAHL_POS = 5; + const int SIZE_POS = sammelTelegram->getTelID() == GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN ? 2 : 1; + + std::stringstream sstream; + unsigned int cnt = sammelTelegram->getPayloadDataUInt32(ANZAHL_POS, SIZE_POS); + for (unsigned int i = 0; i < cnt; ++i) { + uint16_t telId = sammelTelegram->getPayloadDataUInt32(ANZAHL_POS + SIZE_POS + 2 * i, 2); + sstream << telId << " "; + } + return sstream.str(); +} + +QByteArray telegramId2String(gef_telegramm_id_et telId) +{ + const char *str = nullptr; + switch (telId) + { + case GEF_BESTAETIGUNG: str = "GEF_BESTAETIGUNG"; break; + case GEF_INIT: str = "GEF_INIT"; break; + case GEF_MANIPULATIONSMELDUNG: str = "GEF_MANIPULATIONSMELDUNG"; break; + case GEF_UMGEBUNGS_MELDUNG2: str = "GEF_UMGEBUNGS_MELDUNG2"; break; + case GEF_AUFFORDERUNG_BITE_MELDUNG: str = "GEF_AUFFORDERUNG_BITE_MELDUNG"; break; + case GEF_BITE_MELDUNG2: str = "GEF_BITE_MELDUNG2"; break; + case GEF_LIZENSIERUNG_TNE: str = "GEF_LIZENSIERUNG_TNE"; break; + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: str = "GEF_BETRIEBSZUSTAND_AUSSTATTUNG"; break; + case GEF_KONFIGURATION_WIRKMODELL: str = "GEF_KONFIGURATION_WIRKMODELL"; break; + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: str = "GEF_ANFORDERUNG_KONFIGURATIONSDATEN"; break; + case GEF_KONFIGURATIONSMELDUNG: str = "GEF_KONFIGURATIONSMELDUNG"; break; + case GEF_FEHLERMELDUNG_GFD: str = "GEF_FEHLERMELDUNG_GFD"; break; + case GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT: str = "GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT"; break; + case GEF_POSITIONS_MELDUNG: str = "GEF_POSITIONS_MELDUNG"; break; + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: str = "GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER"; break; + case GEF_POSITIONS_MELDUNG_LFZ: str = "GEF_POSITIONS_MELDUNG_LFZ"; break; + case GEF_IPS_POSITIONSDATEN: str = "GEF_IPS_POSITIONSDATEN"; break; + case GEF_SCHIEDSRICHTERKOMMANDO: str = "GEF_SCHIEDSRICHTERKOMMANDO"; break; + case GEF_WIRKFELD_EINZELGESCHOSS: str = "GEF_WIRKFELD_EINZELGESCHOSS"; break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER"; break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP"; break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN"; break; + case GEF_WIRKFELD_MINENSPERRE: str = "GEF_WIRKFELD_MINENSPERRE"; break; + case GEF_WIRKFELD_STATUS_MINENSPERRE: str = "GEF_WIRKFELD_STATUS_MINENSPERRE"; break; + case GEF_WIRKFELD_A_KAMPFMITTEL: str = "GEF_WIRKFELD_A_KAMPFMITTEL"; break; + case GEF_WIRKFELD_C_KAMPFMITTEL: str = "GEF_WIRKFELD_C_KAMPFMITTEL"; break; + case GEF_DEAKTIVIERUNG_WIRKFELD: str = "GEF_DEAKTIVIERUNG_WIRKFELD"; break; + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: str = "GEF_WIRKFELD_AENDERUNG_BEZEICHNER"; break; + case GEF_DEAKTIVIERUNG_EINZELMINE: str = "GEF_DEAKTIVIERUNG_EINZELMINE"; break; + case GEF_REAKTIVIERUNG_DUS_MINE: str = "GEF_REAKTIVIERUNG_DUS_MINE"; break; + case GEF_DEFINITION_IED: str = "GEF_DEFINITION_IED"; break; + case GEF_ZUSTAND_IED: str = "GEF_ZUSTAND_IED"; break; + case GEF_STATUS_EINZELMINENSIMULATOR: str = "GEF_STATUS_EINZELMINENSIMULATOR"; break; + case GEF_WIRKFELD_EINZELMINENSIMULATOR: str = "GEF_WIRKFELD_EINZELMINENSIMULATOR"; break; + case GEF_TREFFER_EREIGNIS_DUS: str = "GEF_TREFFER_EREIGNIS_DUS"; break; + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: str = "GEF_TREFFER_EREIGNIS_WIRKSIMULATION"; break; + case GEF_TREFFER_AUSLOESUNG: str = "GEF_TREFFER_AUSLOESUNG"; break; + case GEF_SCHIEDSRICHTEREINGRIFF: str = "GEF_SCHIEDSRICHTEREINGRIFF"; break; + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: str = "GEF_SELEKTIVE_AUFMUNITIONIERUNG"; break; + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: str = "GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG"; break; + case GEF_TREFFER_EREIGNIS_DUS_IPS: str = "GEF_TREFFER_EREIGNIS_DUS_IPS"; break; + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: str = "GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS"; break; + case GEF_TAKTISCHER_STATUS: str = "GEF_TAKTISCHER_STATUS"; break; + case GEF_FUNKTIONSRAUM: str = "GEF_FUNKTIONSRAUM"; break; + case GEF_EINTRETEN_FUNKTIONSRAUM: str = "GEF_EINTRETEN_FUNKTIONSRAUM"; break; + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: str = "GEF_DEAKTIVIEREN_FUNKTIONSRAUM"; break; + case GEF_DATENVERKEHR_SRT_TDS: str = "GEF_DATENVERKEHR_SRT_TDS"; break; + case GEF_DATENVERKEHR_TDS_SRT: str = "GEF_DATENVERKEHR_TDS_SRT"; break; + case GEF_DATENVERKEHR_DMF_TDS: str = "GEF_DATENVERKEHR_DMF_TDS"; break; + case GEF_DATENVERKEHR_TDS_DMF: str = "GEF_DATENVERKEHR_TDS_DMF"; break; + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: str = "GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME"; break; + case GEF_NOP: str = "GEF_NOP"; break; + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: str = "GEF_SONDERSENSORIK_BETRIEBSZUSTAND"; break; + case GEF_SONDERSENSORIK_FAHRSPUR: str = "GEF_SONDERSENSORIK_FAHRSPUR"; break; + case GEF_SONDERSENSORIK_DATEN: str = "GEF_SONDERSENSORIK_DATEN"; break; + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: str = "GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN"; break; + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: str = "GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN"; break; + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: str = "GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION"; break; + case GEF_SPRACHAUSWAHL: str = "GEF_SPRACHAUSWAHL"; break; + case GEF_ALLGEMEINE_NACHRICHT: str = "GEF_ALLGEMEINE_NACHRICHT"; break; + case GEF_ECHO_ON_OFF: str = "GEF_ECHO_ON_OFF"; break; + case GEF_ESW_MELDUNG: str = "GEF_ESW_MELDUNG"; break; + case GEF_WF_SAMMELDEAKTIVIERUNG: str = "GEF_WF_SAMMELDEAKTIVIERUNG"; break; + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: str = "GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN"; break; + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: str = "GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM"; break; + case GEF_DATENVERKEHR_GEOP_TDS: str = "GEF_DATENVERKEHR_GEOP_TDS"; break; + case GEF_DATENVERKEHR_TDS_GEOP: str = "GEF_DATENVERKEHR_TDS_GEOP"; break; + case GEF_DATENVERKEHR_TGTC_TDS: str = "GEF_DATENVERKEHR_TGTC_TDS"; break; + case GEF_DATENVERKEHR_TDS_TGTC: str = "GEF_DATENVERKEHR_TDS_TGTC"; break; + case GEF_GERAETEEREIGNIS: str = "GEF_GERAETEEREIGNIS"; break; + case GEF_WAFFENZUORDNUNG: str = "GEF_WAFFENZUORDNUNG"; break; + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: str = "GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE"; break; + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: str = "GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG"; break; + case GEF_AUSLOESUNG_DUS_TREFFER: str = "GEF_AUSLOESUNG_DUS_TREFFER"; break; + case GEF_ANFORDERUNG_SW_VERSION: str = "GEF_ANFORDERUNG_SW_VERSION"; break; + case GEF_SW_VERSIONSMELDUNG: str = "GEF_SW_VERSIONSMELDUNG"; break; + case GEF_TECHNIK_FUNKTIONSRAUM: str = "GEF_TECHNIK_FUNKTIONSRAUM"; break; + case GEF_TEILNEHMERMODE_SETZEN: str = "GEF_TEILNEHMERMODE_SETZEN"; break; + case GEF_TEILNEHMERMODE_MELDUNG: str = "GEF_TEILNEHMERMODE_MELDUNG"; break; + case GEF_TEILNEHMERMODE_ANFORDERN: str = "GEF_TEILNEHMERMODE_ANFORDERN"; break; + case GEF_TEILNEHMER_KONFIG_ANTWORT: str = "GEF_TEILNEHMER_KONFIG_ANTWORT"; break; + case GEF_TEILNEHMER_KONFIG_SETZEN: str = "GEF_TEILNEHMER_KONFIG_SETZEN"; break; + case GEF_TEILNEHMER_KONFIG_ANFORDERN: str = "GEF_TEILNEHMER_KONFIG_ANFORDERN"; break; + case GEF_SANITAETSDIENST_INSTANDSETZUNG: str = "GEF_SANITAETSDIENST_INSTANDSETZUNG"; break; + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: str = "GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN"; break; + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: str = "GEF_BESTANDSMELDUNG_SANITAETSMATERIAL"; break; + case GEF_GEFECHTSFELDTELEGRAMM: str = "GEF_GEFECHTSFELDTELEGRAMM"; break; + } + + Q_ASSERT(str); + if (!str) + str = "Unknown"; + return str + QByteArray(" (") + QByteArray::number(int(telId)) + ")"; +} + +QString wirkfeldTyp2Str(TrainingAreaBase::TetraIcd::AreaEffectSimulationType wirkfeldTyp) +{ + switch(wirkfeldTyp) + { + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::MineArea: + return QLatin1String("MINENSPERRE"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionArea: + return QLatin1String("FLAECHENFEUER"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionSingle: + return QLatin1String("EINZELFEUER"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::NContamination: + return QLatin1String("A_KAMPF"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::CContamination: + return QLatin1String("C_KAMPF"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::FunctionalArea: + return QLatin1String("FUNKTIONS_RAUM"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::TechnicalArea: + return QLatin1String("FUNKTIONS_RAUM_TECHNIK"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::GasPipeDetonation: + return QLatin1String("GAS_PIPE_DETONATION"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::SpecialArea: + return QLatin1String("SPECIAL_AREA"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::Unknown: + return QLatin1String("DUS"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DusSingleMineSimulator: + return QLatin1String("DUS_SINGLE_MINE_SIMULATOR"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::BeStillWarning: + return QLatin1String("BE_STILL_WARNING"); + } + return QStringLiteral("Unknown Wirkfeldtyp <%1>").arg(static_cast(wirkfeldTyp)); +} + +static inline QString wirkfeldTyp2Str(int typ) +{ + return wirkfeldTyp2Str(static_cast(typ)); +} + +void dumpTelegram(NGL::INGLLogger &m_logger, int id, N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const char *prefix) +{ + if(!m_logger.isDebugEnabled()) + return; + + if (!prefix) + prefix = ""; + const QByteArray commonLog(prefix + QByteArray("BC: ") + QByteArray::number(id) + + ", " + telegramId2String(a_radioTelegram->getTelID())); + switch (a_radioTelegram->getTelID()) + { + case GEF_DEAKTIVIERUNG_WIRKFELD: + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + { + uint8_t wirkfeldTyp = a_radioTelegram->getPayloadDataUInt32(5, 1); + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2); + DEBUG_LOG(m_logger) << commonLog + << ", type: " << wirkfeldTyp2Str(wirkfeldTyp) << ", kennung: " + << wirkfeldKennung; + break; + } + case GEF_DEAKTIVIERUNG_EINZELMINE: { + uint32_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(9, 2); + uint32_t minenKennung = a_radioTelegram->getPayloadDataUInt32(11, 2); + DEBUG_LOG(m_logger) << commonLog + << ", kennung: " << wirkfeldKennung << ", mineId: " << minenKennung; + break; + } + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_FUNKTIONSRAUM: + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + { + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + DEBUG_LOG(m_logger) << commonLog << ", kennung: " << wirkfeldKennung; + break; + } + case GEF_TECHNIK_FUNKTIONSRAUM: + { + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + uint8_t funktionsraumtyp = a_radioTelegram->getPayloadDataUInt32(7, 1); + DEBUG_LOG(m_logger) << commonLog + << ", kennung: " << funktionsraumkennung + << " type: " << int(funktionsraumtyp); + break; + } + case GEF_WF_SAMMELDEAKTIVIERUNG: + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + DEBUG_LOG(m_logger) << commonLog << ", Ids: " << dumpSammeldeaktivierung(a_radioTelegram); + break; + case GEF_NOP: + { + uint16_t bcFrom = a_radioTelegram->getPayloadDataUInt32(3, 2); + uint16_t bcTo = a_radioTelegram->getPayloadDataUInt32(5, 2); + DEBUG_LOG(m_logger) << prefix + << commonLog + << ", from BC " << bcFrom << " to " << bcTo; + break; + } + default: + DEBUG_LOG(m_logger) << commonLog; + break; + } +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp new file mode 100644 index 000000000..a8d5db300 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp @@ -0,0 +1,32 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include +#include +#include "tetra_telegram_ids.h" + +namespace N_CoPrtCnv +{ +class CoPrtCnvRadioTelegram; +} + +COPRTCNV_EXPORT QByteArray telegramId2String(gef_telegramm_id_et telId); +COPRTCNV_EXPORT void dumpTelegram(NGL::INGLLogger &m_logger, + int id, + N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, + const char *prefix = nullptr); +COPRTCNV_EXPORT QString wirkfeldTyp2Str(TrainingAreaBase::TetraIcd::AreaEffectSimulationType wirkfeldTyp); diff --git a/TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp b/TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp new file mode 100644 index 000000000..885ca9d99 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp @@ -0,0 +1,52 @@ + + + + + + + + + + + + + +#pragma once + +#include + +namespace N_CoPrtCnv +{ + + + struct CoPrtCnvInjectionHeader + { + + + uint32_t m_Id1; + + + uint32_t m_Id2; + + + enum Destination + { + eUnknown = 0, + eCentral = 1, + eRadio = 2 + } m_Kind; + + + uint16_t m_Size; + + CoPrtCnvInjectionHeader() + : m_Id1(0x12345678), + m_Id2(0x78236239), + m_Kind(eUnknown), + m_Size(0) + {} + + bool isIdCorrect() const { return (m_Id1 == 0x12345678 && m_Id2 == 0x78236239); } + + }; +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp b/TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp new file mode 100644 index 000000000..6da5e4811 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp @@ -0,0 +1,52 @@ + + + + + + + + + + + + + +#pragma once + +#include + +namespace N_CoPrtCnv +{ + + + struct CoPrtCnvLogHeader + { + + + enum E_CoPrtCnvProtocol + { + e_DestProtocolCentral = 0, + e_DestProtocolWls = 1, + e_DestProtocolTetra = 5, + e_DestProtocolMax = 6, + e_DestProtocolMask = 0x0000000F, + e_DestDirectionMask = 0xC0000000, + e_DestReceive = 0x40000000, + e_DestSend = 0xC0000000 + }; + + + short m_Length = 0; + short m_Version = 0; + int m_Priority = 0; + + + int m_Protocol = 0; + + + int m_Reserved = 0; + + + uint64_t m_Time = 0; + }; +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp new file mode 100644 index 000000000..260e87d17 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp @@ -0,0 +1,1793 @@ + + + + + + + + + + + + + + +#include "CoPrtCnvRadioTelegram.hpp" +#include +#include + +using N_CoPrtCnv::CoPrtCnvRadioTelegram; + +using namespace N_CoPrtCnv; + + + +constexpr uint8_t CoPrtCnvRadioTelegram::MAGIC_NUMBER; +constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_WITH_TL_HEADER_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_NO_TL_HEADER_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::PAYLOAD_STATUS_LENGTH; +constexpr uint8_t CoPrtCnvRadioTelegram::MAX_NBR_OF_FRAGMENTS; + +int CoPrtCnvRadioTelegram::s_2ndDelay = 60; +int CoPrtCnvRadioTelegram::s_3rdDelay = 60; +int CoPrtCnvRadioTelegram::s_maxBroadcastSendCnt = 0; +bool CoPrtCnvRadioTelegram::s_etsMode = false; + +static const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_ProtocolIdentifier +s_protocolIdentifier = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_TDSMessageWithoutSDS_TL; + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI) + : m_data(9, Qt::Uninitialized), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + setHeader(m_data, e_RegisterInd); + + setSrcISSI(a_sourceISSI); +} + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, + const std::set &groups) + : m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + uint16_t len = groups.size(); + if (len > 5) + len = 5; + m_data.resize(12 + len * 4); + setHeader(m_data, e_GroupMonitorReq); + + + setSrcISSI(a_sourceISSI); + + uint8_t mode = 1; + set1Byte(m_data, 9, mode); + set2Byte(m_data, 10, len); + std::set::iterator it = groups.begin(); + for (uint16_t i = 0; i < len; i++) + { + set4Byte(m_data, 12 + i * 4, *it); + ++it; + } +} + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, + const E_DeliveryStatusForTL_Report a_delivery) + : m_data(17, Qt::Uninitialized), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + setHeader(m_data, e_ReportIndReq); + + setSrcISSI(a_sourceISSI); + setDestISSI(a_sourceISSI); + set1Byte(m_data, 13, s_protocolIdentifier); + set1Byte(m_data, 14, 0); + set1Byte(m_data, 15, 0); + set1Byte(m_data, 16, a_delivery); +} + + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const QByteArray &a_data) + : m_data(a_data), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ +} + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const gef_telegramm_id_et a_telegramId, const uint16_t a_payloadSize, const uint16_t a_identity) + : m_data(a_payloadSize + DATA_IND_REQ_HEADER_LENGTH, '\0'), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + setHeader(m_data, e_DataIndReq); + fillDataIndReqHeader(m_data); + + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(m_data, m_PayloadIndex++, e_NotFragmented); + + set1Byte(m_data, m_PayloadIndex++, a_telegramId); + set1Byte(m_data, m_PayloadIndex++, 0); + set1Byte(m_data, m_PayloadIndex--, 0); + setIdentity(a_identity); + m_PayloadIndex += 2; +} + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, uint32_t a_issi) + : m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + const bool withGroupIssis = (a_loginTelegramStatus & e_LoginOtherExercise) == e_LoginOtherExercise; + m_data.resize(DATA_IND_REQ_HEADER_LENGTH + (withGroupIssis ? 12 : 3)); + setHeader(m_data, e_DataIndReq); + fillDataIndReqHeader(m_data); + setDestISSI(a_issi); + + + uint16_t size = m_data.size(); + set2Byte(m_data, DATA_IND_REQ_WITH_TL_HEADER_LENGTH, 8 * (size - DATA_IND_REQ_HEADER_LENGTH_WITHOUT_PAYLOAD_HEADER)); + + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(m_data, m_PayloadIndex++, e_NotFragmented + e_LoginTelegram); + + set1Byte(m_data, m_PayloadIndex++, (a_identity >> 8) & 0x00FF); + set1Byte(m_data, m_PayloadIndex++, a_identity & 0x00FF); + set1Byte(m_data, m_PayloadIndex++, a_loginTelegramStatus); +} + +void CoPrtCnvRadioTelegram::setLoginIssis(int hostIssi, int groupIssi1, int groupIssi2) +{ + + + setPayload3Byte(hostIssi); + + setPayload3Byte(groupIssi1); + + setPayload3Byte(groupIssi2); +} + + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const std::shared_ptr &a_bigTelegram, + const uint8_t a_fragmentIndex, + bool &a_error) + : m_data(), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + static const uint16_t MAX_TELEGRAM_SIZE = MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH - PAYLOAD_STATUS_LENGTH; + + const int payloadSize = a_bigTelegram->getSize() - DATA_IND_REQ_HEADER_LENGTH; + const uint8_t nbrOfFragmentedTelegrams = uint8_t((payloadSize - 1) / MAX_TELEGRAM_SIZE); + if (nbrOfFragmentedTelegrams > (MAX_NBR_OF_FRAGMENTS - 1)) + { + ERROR_LOG(m_logger) << "Radio-telegram is too big (" << nbrOfFragmentedTelegrams + 1 + << " fragments). There are max " << MAX_NBR_OF_FRAGMENTS + << " fragments of size=" << MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + << " (=" << MAX_NBR_OF_FRAGMENTS *MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + << " bytes) possible."; + a_error = true; + return; + } + if (nbrOfFragmentedTelegrams == 0) + { + ERROR_LOG(m_logger) << "Radio-telegram is too small for fragmentation. It must have at least a size of " + << (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + 1); + a_error = true; + return; + } + uint8_t payloadStatus = e_FirstFragment | nbrOfFragmentedTelegrams; + + + const uint16_t payloadSizeNormal = uint16_t(payloadSize / (nbrOfFragmentedTelegrams + 1)); + const uint16_t payloadSizeLast = uint16_t(payloadSize - (nbrOfFragmentedTelegrams * payloadSizeNormal)); + + uint16_t size = payloadSizeNormal; + if (0 != a_fragmentIndex) + { + if (nbrOfFragmentedTelegrams != a_fragmentIndex) + { + + payloadStatus = e_MiddleFragment | (nbrOfFragmentedTelegrams - a_fragmentIndex); + } + else + { + + payloadStatus = e_LastFragment; + size = payloadSizeLast; + } + } + size += PAYLOAD_STATUS_LENGTH; + + + m_data.resize(size + DATA_IND_REQ_WITH_TL_HEADER_LENGTH + sizeof(PrtCnvRadioGwHeader)); + setHeader(m_data, e_DataIndReq); + fillDataIndReqHeader(m_data); + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(m_data, m_PayloadIndex++, payloadStatus); + + if (size > 1) + { + const char *srcData = a_bigTelegram->getData() + DATA_IND_REQ_HEADER_LENGTH + a_fragmentIndex * payloadSizeNormal; + const uint8_t *ptr = reinterpret_cast(srcData); + setPayloadData(ptr, size - 1); + } + else + { + + ERROR_LOG(m_logger) << "Internal error: size must be bigger than 1"; + a_error = true; + return; + } + a_error = false; +} + + + +CoPrtCnvRadioTelegram::~CoPrtCnvRadioTelegram() +{ + if (m_BroadcastOnlyTelegram != nullptr) + ERROR_LOG(m_logger) << "Internal error: m_BroadcastOnlyTelegram was not nullptr while deletion of radio-telegram"; +} + + + + + +void CoPrtCnvRadioTelegram::setPayload1Byte(const uint8_t a_value) +{ + set1Byte(m_data, m_PayloadIndex, a_value); + m_PayloadIndex += 1; +} + +void CoPrtCnvRadioTelegram::setPayload2Byte(const uint16_t a_value) +{ + setPayloadData(a_value, 2); +} + +void CoPrtCnvRadioTelegram::setPayload3Byte(const uint32_t a_value) +{ + setPayloadData(a_value, 3); +} + +void CoPrtCnvRadioTelegram::setPayload4Byte(const uint32_t a_value) +{ + setPayloadData(a_value, 4); +} + +void CoPrtCnvRadioTelegram::setPayloadData(uint32_t a_value, const uint8_t a_size) +{ + for (int i = m_PayloadIndex + a_size - 1; i >= m_PayloadIndex; i--) + { + set1Byte(m_data, i, a_value & 0xFF); + a_value >>= 8; + } + m_PayloadIndex += a_size; +} + + + + + +void CoPrtCnvRadioTelegram::setPayloadData(const uint8_t *a_data, const uint16_t a_size) +{ + uint8_t *ptr = reinterpret_cast(m_data.data()); + memcpy(&ptr[m_PayloadIndex], a_data, a_size); + m_PayloadIndex += a_size; +} + + + + +void CoPrtCnvRadioTelegram::fixupTelegramIdForEts(bool convertToEtsId) +{ + if (!s_etsMode) + return; + char *ptr = &m_data.data()[DATA_IND_REQ_HEADER_LENGTH]; + if (convertToEtsId) + ++(*ptr); + else + --(*ptr); +} + +void CoPrtCnvRadioTelegram::setEtsMode(bool bIsEtsMode) +{ + s_etsMode = bIsEtsMode; +} + + + + +gef_telegramm_id_et CoPrtCnvRadioTelegram::getTelID() const +{ + return static_cast(static_cast(m_data.at(DATA_IND_REQ_HEADER_LENGTH))); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::zaehler() const +{ + return static_cast(m_data.at(1)); +} + + + + + +void CoPrtCnvRadioTelegram::setZaehler(const uint8_t a_counter) +{ + set1Byte(m_data, 1, a_counter); +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getPayloadDataUInt32(size_t a_offset, uint16_t a_size) const +{ + uint32_t value = 0; + const uint8_t *ptr = reinterpret_cast(m_data.data()); + uint8_t *ptrValue = reinterpret_cast(&value); + a_offset += DATA_IND_REQ_HEADER_LENGTH; + switch (a_size) + { + case 4: + ptrValue[3] = ptr[a_offset++]; + Q_FALLTHROUGH(); + case 3: + ptrValue[2] = ptr[a_offset++]; + Q_FALLTHROUGH(); + case 2: + ptrValue[1] = ptr[a_offset++]; + Q_FALLTHROUGH(); + case 1: + ptrValue[0] = ptr[a_offset++]; + break; + default: + Q_ASSERT(false); + ERROR_LOG(m_logger) << "a_size must be between 1..4"; + } + + return value; +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getPayloadDataUInt8(size_t a_offset) const +{ + return static_cast(m_data.at(DATA_IND_REQ_HEADER_LENGTH + a_offset)); +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getDestISSI() const +{ + return getUInt32(9); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getIdentity() const +{ + return isLoginTelegram() ? getPayloadDataUInt32(0, 2) : getPayloadDataUInt32(1, 2); +} + + + + + +void CoPrtCnvRadioTelegram::setSrcISSI(const uint32_t a_ISSI) +{ + setSrcISSI_Internal(m_data, a_ISSI); +} + + + + + + +bool CoPrtCnvRadioTelegram::mustBroadcastBeSet() const +{ + + + if (isNormalTelegram()) + return getIdentity() == 0 && getBroadcastIndex() == 0; + + return false; +} + + + + + +void CoPrtCnvRadioTelegram::setBroadcastIndex(const uint16_t a_broadcastIndex) +{ + set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + 3, (a_broadcastIndex >> 8) & 0xFF); + set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + 4, a_broadcastIndex & 0xFF); +} + + + + + +void CoPrtCnvRadioTelegram::setDestISSI(const uint32_t a_ISSI) +{ + setDestISSI_Internal(m_data, a_ISSI); +} + + + + + +CoPrtCnvRadioTelegram::E_PDU_Type CoPrtCnvRadioTelegram::getPDU_Type() const +{ + return static_cast(m_data.at(4)); +} + + + + + +CoPrtCnvRadioTelegram::E_FragmentStatus CoPrtCnvRadioTelegram::getFragmentStatus() const +{ + return static_cast(m_data.at(26) & e_FragmentStatusMask); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getFragmentCounter() const +{ + return static_cast(m_data.at(26) & e_CounterMask); +} + + + + + + + +bool CoPrtCnvRadioTelegram::isCrcOk() const +{ + if ((m_data.at(26) & e_Checksum) == e_Checksum) + { + + uint32_t sum = getProtocolIdentifier(); + for (int i = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; i < m_data.size() - 2; i++) + sum += static_cast(m_data.at(i)); + + uint16_t checksum = getUInt8(m_data.size() - 2) * 256 + getUInt8(m_data.size() - 1); + checksum = ~checksum; + checksum++; + + auto that = const_cast(this); + that->m_data.resize(m_data.size() - 2); + that->m_data[26] = (m_data.at(26) & ~e_Checksum); + + if (sum != checksum) + { + ERROR_LOG(m_logger) << "Checksum of telegram is wrong: " << QString::number(checksum, 16) + << " (expected: " << QString::number(sum, 16) << "), issi: " << getUInt32(5); + return true; + } + } + return true; +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getSrcISSI() const +{ + return getUInt32(5); +} + + + + + +bool CoPrtCnvRadioTelegram::isLoginTelegram() const +{ + if (e_DataIndReq == getPDU_Type()) + return (e_LoginTelegram == ((e_FragmentStatusMask | e_CounterMask) & m_data.at(26))); + return false; +} + + + + + +bool CoPrtCnvRadioTelegram::mustBeFragmented() const +{ + if (e_DataIndReq == getPDU_Type()) + return size_t(getSize()) > (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + DATA_IND_REQ_WITH_TL_HEADER_LENGTH + sizeof(PrtCnvRadioGwHeader)); + return false; +} + + + + + + +const uint8_t *CoPrtCnvRadioTelegram::getPayloadDataPtr(uint16_t a_offset) const +{ + return reinterpret_cast(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH + a_offset]); +} + +uint8_t *CoPrtCnvRadioTelegram::getPayloadDataPtr(uint16_t a_offset) +{ + return reinterpret_cast(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH + a_offset]); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getPayloadSize() const +{ + return static_cast((getPDU_Type() == e_DataIndReq) ? m_data.size() - DATA_IND_REQ_HEADER_LENGTH : 0); +} + + + + + + + + + + +QByteArray CoPrtCnvRadioTelegram::getUnfragmentedData(const std::multimap &a_fragTelegramList) +{ + NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"); + + uint16_t totalSize = 0; + bool first = true; + uint8_t expectedNextFragment = 0; + CoPrtCnvRadioTelegram *firstFragment = nullptr; + std::multimap::const_reverse_iterator rit; + for (rit = a_fragTelegramList.rbegin(); rit != a_fragTelegramList.rend(); ++rit) + { + CoPrtCnvRadioTelegram *fragRadioTelegram = rit->second; + if (first) + { + if (e_FirstFragment == fragRadioTelegram->getFragmentStatus()) + { + totalSize += fragRadioTelegram->getSize(); + expectedNextFragment = fragRadioTelegram->getFragmentCounter() - 1; + firstFragment = fragRadioTelegram; + first = false; + } + else + { + ERROR_LOG(l) << "The fragment with the highest counter is not marked as first fragment"; + return nullptr; + } + } + else + { + if (e_MiddleFragment == fragRadioTelegram->getFragmentStatus() || e_LastFragment == fragRadioTelegram->getFragmentStatus()) + { + if (expectedNextFragment-- == fragRadioTelegram->getFragmentCounter()) + { + if (e_LastFragment == fragRadioTelegram->getFragmentStatus() && 0 != fragRadioTelegram->getFragmentCounter()) + { + ERROR_LOG(l) << "The last fragment must have a counter of 0, but the counter is " << (int)fragRadioTelegram->getFragmentCounter(); + return nullptr; + } + totalSize += fragRadioTelegram->getPayloadSize(); + } + else + { + ERROR_LOG(l) << "The fragmented Radio-Telegram from TNE with id=" << fragRadioTelegram->getIdentity() << " with fragment-counter=" << (expectedNextFragment + 1) << " was lost"; + return nullptr; + } + } + else + { + ERROR_LOG(l) << "A fragment which is not the first one, is not marked as middle or last fragment"; + return nullptr; + } + } + } + + + if (firstFragment + && totalSize <= (DATA_IND_REQ_HEADER_LENGTH + MAX_NBR_OF_FRAGMENTS * (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH - PAYLOAD_STATUS_LENGTH)) + && totalSize > DATA_IND_REQ_HEADER_LENGTH) + { + QByteArray data(totalSize, Qt::Uninitialized); + + setHeader(data, e_DataIndReq); + fillDataIndReqHeader(data); + setSrcISSI_Internal(data, firstFragment->getSrcISSI()); + setDestISSI_Internal(data, firstFragment->getDestISSI()); + uint16_t index = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(data, index++, e_NotFragmented); + + + for (rit = a_fragTelegramList.rbegin(); rit != a_fragTelegramList.rend(); ++rit) + { + CoPrtCnvRadioTelegram *fragRadioTelegram = rit->second; + uint16_t fragSize = fragRadioTelegram->getPayloadSize(); + if (index + fragSize <= totalSize) + { + memcpy(&data.data()[index], fragRadioTelegram->getPayloadDataPtr(0), fragSize); + index += fragSize; + } + else + { + + ERROR_LOG(l) << "Internal error: size of allocated datablock is too small"; + return QByteArray(); + } + } + + return data; + } + + ERROR_LOG(l) << "Internal error while building unfragmented radio-telegram: fragTelegram=" << firstFragment << " totalSize=" << totalSize; + return QByteArray(); +} + + + + + +bool CoPrtCnvRadioTelegram::isTelegramLengthOk(const uint16_t a_lengthWithoutFrame) +{ + return (a_lengthWithoutFrame <= (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + DATA_IND_REQ_HEADER_LENGTH - sizeof(PrtCnvRadioGwHeader) - PAYLOAD_STATUS_LENGTH)); +} + + + + + + +bool CoPrtCnvRadioTelegram::isNormalTelegram() const +{ + return (e_DataIndReq == getPDU_Type() && (e_NormalTelegram == ((e_FragmentStatusMask | e_CounterMask) & m_data.at(26)))); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getPriority() const +{ + if (isNormalTelegram()) + { + switch (getTelID()) + { + case GEF_INIT: + case GEF_DEAKTIVIERUNG_EINZELMINE: + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + return 2; + case GEF_WIRKFELD_EINZELGESCHOSS: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_C_KAMPFMITTEL: + case GEF_DEAKTIVIERUNG_WIRKFELD: + case GEF_REAKTIVIERUNG_DUS_MINE: + case GEF_TECHNIK_FUNKTIONSRAUM: + case GEF_FUNKTIONSRAUM: + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + case GEF_DATENVERKEHR_TDS_GEOP: + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + case GEF_POSITIONS_MELDUNG: + return 3; + case GEF_UMGEBUNGS_MELDUNG2: + case GEF_AUFFORDERUNG_BITE_MELDUNG: + case GEF_LIZENSIERUNG_TNE: + case GEF_TREFFER_AUSLOESUNG: + case GEF_SPRACHAUSWAHL: + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + case GEF_SCHIEDSRICHTERKOMMANDO: + return 4; + case GEF_KONFIGURATION_WIRKMODELL: + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + case GEF_DATENVERKEHR_TDS_SRT: + case GEF_DATENVERKEHR_TDS_DMF: + case GEF_DATENVERKEHR_TDS_TGTC: + case GEF_TEILNEHMERMODE_SETZEN: + case GEF_TEILNEHMER_KONFIG_ANFORDERN: + case GEF_TEILNEHMER_KONFIG_SETZEN: + return 5; + case GEF_ALLGEMEINE_NACHRICHT: + return 6; + case GEF_SW_VERSIONSMELDUNG: + return 7; + + case GEF_NOP: + case GEF_WF_SAMMELDEAKTIVIERUNG: + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + return 99; + default: + ERROR_LOG(m_logger) << "Priority of telegram with telId=" << getTelID() << " not defined."; + +#ifdef DEBUG + abort(); +#endif + } + } + else if (isLoginTelegram()) + return 4; + return 10; +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getBroadcastIndex() const +{ + if (isNormalTelegram() && m_data.size() > (DATA_IND_REQ_HEADER_LENGTH + 4)) + return getPayloadDataUInt32(3, 2); + return 0; +} + + + + + +void CoPrtCnvRadioTelegram::setPayloadDataWithIndex(const uint16_t a_index, const uint32_t a_value, const uint16_t a_size) +{ + + + if (1 == a_size) + set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + a_index, a_value); + else + { + uint16_t savedPayloadIndex = m_PayloadIndex; + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH + a_index; + setPayloadData(a_value, a_size); + m_PayloadIndex = savedPayloadIndex; + } +} + + + + + +void CoPrtCnvRadioTelegram::setPayloadDataComplete(const QByteArray &payload) +{ + m_data.resize(payload.size() + DATA_IND_REQ_HEADER_LENGTH); + setHeader(m_data, getPDU_Type()); + memcpy(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH], payload.data(), payload.size()); +} + + + + + + + + + +void CoPrtCnvRadioTelegram::resetPayloadSize(const uint16_t a_newPayloadSize) +{ + m_data.resize(a_newPayloadSize + DATA_IND_REQ_HEADER_LENGTH); + setHeader(m_data, getPDU_Type()); + + uint16_t size = m_data.size(); + set2Byte(m_data, 22, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH) * 8); + set2Byte(m_data, 24, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH)); +} + + + + + +void CoPrtCnvRadioTelegram::setIdentity(const uint16_t a_identity) +{ + setPayloadDataWithIndex(isLoginTelegram() ? 0 : 1, a_identity, 2); +} + + + + + +void CoPrtCnvRadioTelegram::setProtocolIdentifier(const E_ProtocolIdentifier a_ProtocolIdentifier) +{ + if (e_DataIndReq == getPDU_Type()) + set1Byte(m_data, 13, a_ProtocolIdentifier); +} + + + + + +void CoPrtCnvRadioTelegram::setMessageReference(const uint8_t a_MessageReference) +{ + if (isSDSTL()) + set1Byte(m_data, 14, a_MessageReference); +} + + + + + +bool CoPrtCnvRadioTelegram::isSDSTL() const +{ + return (e_DataIndReq == getPDU_Type() && (e_UsingSDS_TL == (e_UsingSDS_TL & getProtocolIdentifier()))); +} + + + + + + +CoPrtCnvRadioTelegram::E_RegistrationStatus CoPrtCnvRadioTelegram::getRegistrationStatus() const +{ + return static_cast(m_data.at(5)); +} + + + + + + +std::string CoPrtCnvRadioTelegram::getRegistrationStatusAsText() const +{ + switch (getRegistrationStatus()) + { + case e_IssiSuccessfulRegistered: + return "IssiSuccessfulRegistered"; + case e_DuplicateISSI: + return "DuplicateISSI"; + case e_InvalidISSI: + return "InvalidISSI"; + case e_InvalidIpAddress: + return "InvalidIpAddress"; + } + return std::to_string(getRegistrationStatus()); +} + + + + + +CoPrtCnvRadioTelegram::E_ProtocolIdentifier CoPrtCnvRadioTelegram::getProtocolIdentifier() const +{ + return static_cast(m_data.at(13)); +} + + + + + + +std::string CoPrtCnvRadioTelegram::getProtocolIdentifierAsText() const +{ + switch (getProtocolIdentifier()) + { + case e_SimpleTextMessagingWithoutSDS_TL: + return "Simple Text Messaging w/o SDS/TL"; + case e_SimpleGPS_WithoutSDS_TL: + return "Simple GPS w/o SDS/TL"; + case e_TDSMessageWithoutSDS_TL: + return "TDS Message w/o SDS/TL"; + case e_UsingSDS_TL: + return "SDS/TL"; + case e_SimpleTextMessagingUsingSDS_TL: + return "Simple Text Messaging with SDS/TL"; + case e_SimpleGPS_UsingSDS_TL: + return "Simple GPS with SDS/TL"; + case e_LoginTest: + return "Login-Test / Hohenfels"; + } + return std::to_string(getProtocolIdentifier()); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getMessageReference() const +{ + return static_cast(m_data.at(14)); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getAreaSelection() const +{ + return static_cast(m_data.at(15)); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getValidityPeriod() const +{ + return static_cast(m_data.at(16)); +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getForwardAddress() const +{ + return getUInt32(17); +} + + + + + +CoPrtCnvRadioTelegram::E_Flags CoPrtCnvRadioTelegram::getFlags() const +{ + return static_cast(m_data.at(21)); +} + + + + + +std::string CoPrtCnvRadioTelegram::getFlagsAsText() const +{ + switch (getFlags()) + { + case e_FlagsNone: + return "No Flags"; + + case e_StorageAllowed: + return "Storage Allowed"; + + case e_GroupServiceOrOnlyStandardReportAllowed: + return "Group Service or only Standard Report Allowed"; + + case e_ReceivedConfirmationRequested: + return "Received Confirmation Requested"; + + case e_ConsumedConfirmationRequested: + return "Consumed Confirmation Requested"; + + } + std::ostringstream str; + str << getFlags(); + return str.str(); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getLengthInBits() const +{ + return getUInt16(22); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getLengthInBytes() const +{ + return getUInt16(24); +} + + + + +bool CoPrtCnvRadioTelegram::getWithCrc() const +{ + if (getSize() > 26) + return ((m_data.at(26) & e_Checksum) == e_Checksum); + return false; +} + + + + + + +CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report CoPrtCnvRadioTelegram::getDelivery() const +{ + return static_cast(m_data.at(16)); +} + + + + + + +std::string CoPrtCnvRadioTelegram::getDeliveryAsText() const +{ + switch (getDelivery()) + { + case e_SDS_ReceiptAcknowledgedByDestination: + return "SDS receipt acknowledged by destination"; + + case e_SDS_ConsumedByDestination: + return "SDS consumed by destination"; + + case e_SourceIsNotAuthorizedForSDS: + return "Source is not authorized for SDS"; + + case e_DestinationIsNotAuthorizedForSDS: + return "Destination is not authorized for SDS"; + + case e_UnknownDestinationAddress: + return "Unknown destination address"; + + case e_DeliveryFailed: + return "Delivery failed"; + + case e_DestinationNotRegisteredOnSystem: + return "Destination not registered on system"; + + case e_DestinationQueueFull: + return "Destination queue full"; + + case e_MessageTooLong: + return "Message too long"; + + case e_DestinationHostPC_NotConnected: + return "Destination host PC not connected"; + + case e_ProtocolNotSupported: + return "Protocol not supported"; + + case e_DataCodingSchemeNotSupported: + return "Datat coding scheme not supported"; + + case e_DestinationNotReachable: + return "Destination not reachable"; + + } + std::ostringstream str; + str << getDelivery(); + return str.str(); +} + + + + + + +int32_t CoPrtCnvRadioTelegram::getPayloadDataSInt24(uint16_t a_offset) const +{ + uint32_t value = getPayloadDataUInt32(a_offset, 3); + + if (value & 0x800000) + value |= 0xFF800000; + + return value; +} + + + + + +bool CoPrtCnvRadioTelegram::needsLicensing() const +{ + if (isNormalTelegram()) + { + switch (getTelID()) + { + + case GEF_UMGEBUNGS_MELDUNG2: + case GEF_LIZENSIERUNG_TNE: + case GEF_AUFFORDERUNG_BITE_MELDUNG: + case GEF_ALLGEMEINE_NACHRICHT: + return false; + default: + + break; + } + return true; + } + return false; +} + + + + + + + +bool CoPrtCnvRadioTelegram::hasExpired() const +{ + uint32_t expireTime = getExpireTime(); + if (expireTime > 0) + { + uint32_t now = time(nullptr); + return (now >= expireTime); + } + return false; +} + + + + + + +uint32_t CoPrtCnvRadioTelegram::getExpireTime() const +{ + if (isNormalTelegram()) + { + uint32_t wirkBegin = 0; + uint32_t wirkDauer = 0; + switch (getTelID()) + { + case GEF_WIRKFELD_EINZELGESCHOSS: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = 5; + break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 2); + break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + wirkBegin = getPayloadDataUInt32(11, 4); + wirkDauer = getPayloadDataUInt32(15, 2); + break; + case GEF_WIRKFELD_A_KAMPFMITTEL: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 2) * 60 * 10; + break; + case GEF_WIRKFELD_C_KAMPFMITTEL: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 1) * 60; + break; + case GEF_WIRKFELD_MINENSPERRE: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 1) * 60 * 60; + break; + default: + return 0; + } + + if (0 == wirkDauer) + { + return 0; + } + + if (wirkBegin > 0) + return (wirkBegin + wirkDauer); + } + return 0; +} + + + + + + + + + +bool CoPrtCnvRadioTelegram::isContentValid() +{ + if (isNormalTelegram()) + { + uint16_t wirkfeldkennung = 0; + uint8_t wirkfeldtyp = 0; + switch (getTelID()) + { + case GEF_WIRKFELD_EINZELGESCHOSS: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_C_KAMPFMITTEL: + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + wirkfeldkennung = getPayloadDataUInt32(5, 2); + wirkfeldtyp = 3; + Q_FALLTHROUGH(); + case GEF_DEAKTIVIERUNG_WIRKFELD: + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + if (GEF_DEAKTIVIERUNG_WIRKFELD == getTelID() || GEF_WIRKFELD_AENDERUNG_BEZEICHNER == getTelID()) + { + wirkfeldtyp = getPayloadDataUInt8(5); + wirkfeldkennung = getPayloadDataUInt32(6, 2); + } + + if ((wirkfeldtyp >= 1 && wirkfeldtyp <= 5) || (wirkfeldtyp == 8)) + { + if (wirkfeldkennung > 0 && wirkfeldkennung <= 32767) + return true; + ERROR_LOG(m_logger) << "Wirkfeldkennung (" << wirkfeldkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..32768."; + return false; + } + if (GEF_WIRKFELD_AENDERUNG_BEZEICHNER == getTelID() && wirkfeldkennung > 0) + return true; + + + + ERROR_LOG(m_logger) << "Wirkfeldtyp (" << wirkfeldtyp << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..5 or 8."; + return false; + + case GEF_DEAKTIVIERUNG_EINZELMINE: + if (isPayloadLengthOk(13)) + { + wirkfeldkennung = getPayloadDataUInt32(9, 2); + { + if (wirkfeldkennung > 32767) + { + ERROR_LOG(m_logger) << "DeaktivierungEinzelmine: wirkfeldkennung=" << wirkfeldkennung << " too big. Must be 1..32767"; + return false; + } + } + return true; + } + return false; + + case GEF_TECHNIK_FUNKTIONSRAUM: + case GEF_FUNKTIONSRAUM: + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + { + uint32_t funktionsraumkennung = getPayloadDataUInt32(5, 2); + if (funktionsraumkennung > 0) + return true; + + ERROR_LOG(m_logger) << "Funktionsraumkennung (" << funktionsraumkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..65535."; + return false; + } + case GEF_EINTRETEN_FUNKTIONSRAUM: + if (isPayloadLengthOk(15)) + { + uint32_t funktionsraumkennung = getPayloadDataUInt32(13, 2); + if (funktionsraumkennung > 0) + return true; + + ERROR_LOG(m_logger) << "Funktionsraumkennung (" << funktionsraumkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..65535."; + return false; + } + return false; + + case GEF_SPRACHAUSWAHL: + { + uint8_t sprache = getPayloadDataUInt8(5); + if (sprache <= 3) + return true; + + ERROR_LOG(m_logger) << "Sprache (" << sprache << ") of telegram with telId=" << getTelID() << " is invalid. Must be 0..3."; + return false; + } + + + + case GEF_MANIPULATIONSMELDUNG: + return isPayloadLengthOk(12); + + case GEF_BITE_MELDUNG2: + return isPayloadLengthOk(27, 19, 7); + + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + return isPayloadLengthOk(9); + + case GEF_FEHLERMELDUNG_GFD: + return isPayloadLengthOk(9); + + case GEF_POSITIONS_MELDUNG: + return isPayloadLengthOk(14); + + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + return isPayloadLengthOk(15, 14, 2); + + case GEF_POSITIONS_MELDUNG_LFZ: + return isPayloadLengthOk(15); + + case GEF_TREFFER_EREIGNIS_DUS: + return isPayloadLengthOk(23); + + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + return isPayloadLengthOk(22); + + case GEF_SCHIEDSRICHTEREINGRIFF: + return isPayloadLengthOk(16); + + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + return isPayloadLengthOk(8,7,8); + + case GEF_TAKTISCHER_STATUS: + return isPayloadLengthOk(16); + + case GEF_DATENVERKEHR_SRT_TDS: + case GEF_DATENVERKEHR_DMF_TDS: + { + uint16_t length = m_data.size() - DATA_IND_REQ_HEADER_LENGTH; + + const uint16_t MIN_LENGTH = 7; + if (length >= MIN_LENGTH) + return true; + + ERROR_LOG(m_logger) << "The payload-length of telegram with telId=" << getTelID() << " must be at least " << MIN_LENGTH << ", but it is only " << length; + return false; + } + + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + return isPayloadLengthOk(10); + + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + return isPayloadLengthOk(9); + + case GEF_SONDERSENSORIK_FAHRSPUR: + return isPayloadLengthOk(15); + + case GEF_SONDERSENSORIK_DATEN: + return isPayloadLengthOk(17); + + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + return isPayloadLengthOk(24); + + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + return isPayloadLengthOk(25); + + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + return isPayloadLengthOk(16); + + case GEF_DATENVERKEHR_GEOP_TDS: + + return isPayloadLengthOk(15, 14, 1); + + case GEF_DATENVERKEHR_TGTC_TDS: + + return isPayloadLengthOk(8, 7, 1); + + case GEF_GERAETEEREIGNIS: + + return isPayloadLengthOk(25, 24, 1); + + case GEF_WAFFENZUORDNUNG: + + return isPayloadLengthOk(8, 7, 6); + + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + + return isPayloadLengthOk(13, 12, 5); + + case GEF_IPS_POSITIONSDATEN: + + return isPayloadLengthOk(8, 7, 2); + + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + return isPayloadLengthOk({13, 17}); + + case GEF_TEILNEHMERMODE_MELDUNG: + return isPayloadLengthOk(15); + + case GEF_TEILNEHMER_KONFIG_ANTWORT: + return isPayloadLengthOk(27); + + case GEF_DEFINITION_IED: + return isPayloadLengthOk(24); + + case GEF_ZUSTAND_IED: + return isPayloadLengthOk(16); + + case GEF_STATUS_EINZELMINENSIMULATOR: + return isPayloadLengthOk(17); + + default: + + + break; + } + } + return true; +} + + + + + + + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_minLength, + const uint16_t a_dataAmountOffset, + const uint8_t a_variableDataElementSize) const +{ + if (0 == a_variableDataElementSize) + return isPayloadLengthOk(a_minLength); + + const uint16_t length = getPayloadSize(); + if (length >= a_minLength) + { + uint8_t dataAmount = getPayloadDataUInt8(a_dataAmountOffset); + uint16_t dataSize = a_variableDataElementSize * dataAmount; + uint16_t expectedLength = dataSize + a_minLength; + if (expectedLength != length) + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be " << expectedLength + << ", but it is " << length << " (the amount of variable data in telegram was " + << dataAmount << " => " << dataSize << " bytes)"; + return false; + } + } + else + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " << getTelID() + << " must be at least " << a_minLength << ", but it is only " << length; + return false; + } + return true; +} + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_minLength, + uint16_t a_maxLength) const +{ + if (a_maxLength == 0) + return isPayloadLengthOk(a_minLength); + + const uint16_t length = getPayloadSize(); + if (length < a_minLength) + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be greater or equal to " + << a_minLength << ", but it is " << length; + return false; + } + + if (length > a_maxLength) + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be fewer than " + << a_minLength << ", but it is " << length; + return false; + } + return true; +} + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_length) const +{ + const uint16_t length = getPayloadSize(); + if (length == a_length) + return true; + + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be " + << a_length << ", but it is " << length; + return false; +} + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(const std::vector &a_lengths) const +{ + const uint16_t length = getPayloadSize(); + if (std::any_of(a_lengths.begin(), a_lengths.end(), [length](int len) { return len == length;})) + return true; + + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << ", is: " << length; + return false; +} + + + + + +bool CoPrtCnvRadioTelegram::mustBeSentAsBroadcast(time_t a_currentTime, bool &a_wasLastBroadcast, const bool a_updateBroadcastCounter) +{ + a_wasLastBroadcast = false; + + if (m_BroadcastCounter < s_maxBroadcastSendCnt && m_NextSendTime <= a_currentTime) + { + if (a_updateBroadcastCounter) + { + + switch (m_BroadcastCounter) + { + case 0: + if (s_2ndDelay >= 0) + { + m_NextSendTime = time(nullptr) + s_2ndDelay; + INFO_LOG(m_logger) << "1st Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex(); + break; + } + ++m_BroadcastCounter; + Q_FALLTHROUGH(); + case 1: + if (s_3rdDelay >= 0) + { + m_NextSendTime = time(nullptr) + s_3rdDelay; + INFO_LOG(m_logger) << "2nd Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex(); + break; + } + ++m_BroadcastCounter; + Q_FALLTHROUGH(); + default: + INFO_LOG(m_logger) << "3rd Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex(); + m_NextSendTime = 0; + a_wasLastBroadcast = true; + } + ++m_BroadcastCounter; + } + return true; + } + return false; +} + + + + + +void CoPrtCnvRadioTelegram::setBroadcastDelayTimes(int a_2ndDelay, int a_3rdDelay) +{ + s_2ndDelay = a_2ndDelay; + s_3rdDelay = a_3rdDelay; +} + + + + + +void CoPrtCnvRadioTelegram::setMaxBroadcastSendCnt(int a_maxSendCnt) +{ + s_maxBroadcastSendCnt = a_maxSendCnt; +} + + + + + + +bool CoPrtCnvRadioTelegram::isMovedToBroadcastList() const +{ + return (m_BroadcastCounter >= 1); +} + + + + + +void CoPrtCnvRadioTelegram::setBroadcastOnly(const bool a_doSet) +{ + m_IsBroadcastOnly = a_doSet; +} + + + + + +bool CoPrtCnvRadioTelegram::isBroadcastOnly() const +{ + return m_IsBroadcastOnly; +} + + + + + + +void CoPrtCnvRadioTelegram::setBroadcastonlyTelegram(const std::shared_ptr &a_radioTelegram) +{ + if (a_radioTelegram != nullptr && m_BroadcastOnlyTelegram != nullptr) + ERROR_LOG(m_logger) << "Internal error: m_BroadcastOnlyTelegram was not nullptr"; + if (a_radioTelegram != nullptr) + { + INFO_LOG(m_logger) << "Set braodcastonly-telegram: telId=" << a_radioTelegram->getTelID() + << " BC=" << a_radioTelegram->getBroadcastIndex(); + } + m_BroadcastOnlyTelegram = a_radioTelegram; +} + + + + + + +std::shared_ptr CoPrtCnvRadioTelegram::getBroadcastonlyTelegram() const +{ + return m_BroadcastOnlyTelegram; +} + + + + + +void CoPrtCnvRadioTelegram::set1Byte(QByteArray &a_data, uint16_t a_offset, uint8_t a_value) +{ + Q_ASSERT(a_offset < a_data.size()); + uint8_t *ptr = reinterpret_cast(&a_data.data()[a_offset]); + *ptr = a_value; +} + + + + + +void CoPrtCnvRadioTelegram::set2Byte(QByteArray &a_data, uint16_t a_offset, uint16_t a_value) +{ + Q_ASSERT(a_offset < a_data.size()); + uint16_t *ptr = reinterpret_cast(&a_data.data()[a_offset]); + *ptr = a_value; +} + + + + + +void CoPrtCnvRadioTelegram::set4Byte(QByteArray &a_data, uint16_t a_offset, uint32_t a_value) +{ + Q_ASSERT(a_offset < a_data.size()); + uint32_t *ptr = reinterpret_cast(&a_data.data()[a_offset]); + *ptr = a_value; +} + + + + + + + + +uint16_t CoPrtCnvRadioTelegram::getUInt16(const uint16_t a_offset) const +{ + const uint16_t *ptr = reinterpret_cast(&m_data.data()[a_offset]); + return *ptr; +} + + + + + + + + +uint32_t CoPrtCnvRadioTelegram::getUInt32(const uint16_t a_offset) const +{ + const uint32_t *ptr = reinterpret_cast(&m_data.data()[a_offset]); + return *ptr; +} + + + + + + +void CoPrtCnvRadioTelegram::setHeader(QByteArray &data, E_PDU_Type pduType) +{ + + set1Byte(data, 0, MAGIC_NUMBER); + set1Byte(data, 1, 0); + set2Byte(data, 2, data.size() - sizeof(PrtCnvRadioGwHeader)); + set1Byte(data, 4, pduType); +} + + + + + + + + + +void CoPrtCnvRadioTelegram::fillDataIndReqHeader(QByteArray &a_data) +{ + set1Byte(a_data, 4, e_DataIndReq); + setSrcISSI_Internal(a_data, 0); + setDestISSI_Internal(a_data, 0); + + set1Byte(a_data, 13, s_protocolIdentifier); + set1Byte(a_data, 14, 0); + set1Byte(a_data, 15, 0); + set1Byte(a_data, 16, 0); + set1Byte(a_data, 17, 0); + set1Byte(a_data, 18, 0); + set1Byte(a_data, 19, 0); + set1Byte(a_data, 20, 0); + set1Byte(a_data, 21, e_FlagsNone); + + uint16_t size = a_data.size(); + set2Byte(a_data, 22, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH) * 8); + set2Byte(a_data, 24, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH)); +} + + + + + +void CoPrtCnvRadioTelegram::setSrcISSI_Internal(QByteArray &data, const uint32_t issi) +{ + set4Byte(data, 5, issi); +} + + + + + + +uint16_t CoPrtCnvRadioTelegram::getBroadcastCounter() const +{ + return m_BroadcastCounter; +} + + + + + +void CoPrtCnvRadioTelegram::setDestISSI_Internal(QByteArray &data, const uint32_t issi) +{ + set4Byte(data, 9, issi); +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp new file mode 100644 index 000000000..e2f0f02df --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp @@ -0,0 +1,604 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "tetra_telegram_ids.h" + +namespace NGL +{ +class INGLLogger; +} + +namespace N_CoPrtCnv +{ + + +enum class E_LicensingKind +{ + + + Success = 0, + + + Rejected = 1, + + + Unlicense = 2 +}; + + + +enum class E_LicensingErrorCode +{ + Ok = 0, + Selftest = 1, + Battery = 2, + Configuration = 3, + Unlicense = 4, + IdentityDenied = 5 +}; + + + +class COPRTCNV_EXPORT CoPrtCnvRadioTelegram +{ +public: + + + + enum E_Flags + { + e_FlagsNone = 0x00, + e_StorageAllowed = 0x10, + e_GroupServiceOrOnlyStandardReportAllowed = 0x20, + e_ReceivedConfirmationRequested = 0x40, + e_ConsumedConfirmationRequested = 0x80 + }; + + + + enum E_ProtocolIdentifier + { + e_SimpleTextMessagingWithoutSDS_TL = 0x02, + e_SimpleGPS_WithoutSDS_TL = 0x03, + e_TDSMessageWithoutSDS_TL = 0x50, + e_UsingSDS_TL = 0x80, + e_SimpleTextMessagingUsingSDS_TL = 0x82, + e_SimpleGPS_UsingSDS_TL = 0x83, + e_LoginTest = 0x1D + }; + + + + enum E_FragmentStatus + { + e_NotFragmented = 0x00, + e_FirstFragment = 0x40, + e_MiddleFragment = 0xC0, + e_LastFragment = 0x80, + e_FragmentStatusMask = 0xC0, + e_Checksum = 0x20, + e_CounterMask = 0x0F, + e_NormalTelegram = 0x00, + e_LoginTelegram = 0x02, + e_DgpsTelegram = 0x03 + }; + + + + struct PrtCnvRadioGwHeader + { + + + uint8_t m_MagicNumber; + + + uint8_t m_Counter; + + + uint16_t m_Length; + + }; + + + + enum E_PDU_Type + { + e_RegisterInd = 0, + e_RegisterRsp = 1, + e_DataIndReq = 2, + e_ReportIndReq = 3, + e_StatusIndReq = 4, + e_GroupMonitorReq = 6, + e_AirInterfaceLoadReq = 8, + e_AirLoadHyterra = 19 + }; + + + + enum E_RegistrationStatus + { + e_IssiSuccessfulRegistered = 0, + e_DuplicateISSI = 1, + e_InvalidISSI = 2, + e_InvalidIpAddress = 3 + }; + + + + enum E_DeliveryStatusForTL_Report + { + e_SDS_ReceiptAcknowledgedByDestination = 0x00, + e_SDS_ConsumedByDestination = 0x02, + e_SourceIsNotAuthorizedForSDS = 0x43, + e_DestinationIsNotAuthorizedForSDS = 0x44, + e_UnknownDestinationAddress = 0x45, + e_DeliveryFailed = 0x4A, + e_DestinationNotRegisteredOnSystem = 0x4B, + e_DestinationQueueFull = 0x4C, + e_MessageTooLong = 0x4D, + e_DestinationHostPC_NotConnected = 0x4F, + e_ProtocolNotSupported = 0x50, + e_DataCodingSchemeNotSupported = 0x51, + e_DestinationNotReachable = 0x5A + }; + + + + enum E_LoginStatus + { + e_LoginRequest = 0x40, + e_LoginAccept = 0x80, + e_LoginReject = 0xC0, + e_LoginStatusMask = 0xC0, + e_LoginMastering = 0x20, + + + e_LoginNoExerciseAssignment = 0x00, + e_LoginOtherEqId = 0x02, + e_LoginOtherISSI = 0x04, + e_LoginOtherExercise = 0x06, + }; + + + + static constexpr uint8_t MAGIC_NUMBER = 0xA5; + + + static constexpr uint16_t DATA_IND_REQ_WITH_TL_HEADER_LENGTH = 22; + + + static constexpr uint16_t DATA_IND_REQ_HEADER_LENGTH = 27; + + + static constexpr uint16_t DATA_IND_REQ_HEADER_LENGTH_WITHOUT_PAYLOAD_HEADER = DATA_IND_REQ_HEADER_LENGTH -1; + + + static constexpr uint16_t DATA_IND_REQ_NO_TL_HEADER_LENGTH = 14; + + + static constexpr uint16_t MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH = 249; + + + static constexpr uint16_t PAYLOAD_STATUS_LENGTH = 1; + + + static constexpr uint8_t MAX_NBR_OF_FRAGMENTS = 16; + + + + + explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI); + + + + explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, const std::set &groups); + + + + explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, const E_DeliveryStatusForTL_Report a_delivery); + + + + explicit CoPrtCnvRadioTelegram(const QByteArray &a_data); + + + + explicit CoPrtCnvRadioTelegram(const gef_telegramm_id_et a_telegramId, const uint16_t a_payloadSize, const uint16_t a_identity); + + + + explicit CoPrtCnvRadioTelegram(const E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, uint32_t a_issi); + + void setLoginIssis(int hostIssi, int groupIssi1, int groupIssi2); + + + + explicit CoPrtCnvRadioTelegram(const std::shared_ptr &a_bigTelegram, + const uint8_t a_fragmentIndex, bool &a_error); + + + virtual ~CoPrtCnvRadioTelegram(); + + + + void fixupTelegramIdForEts(bool convertToEtsId); + static void setEtsMode(bool bIsEtsMode); + + + + void setPayload1Byte(uint8_t a_value); + void setPayload2Byte(uint16_t a_value); + void setPayload3Byte(uint32_t a_value); + void setPayload4Byte(uint32_t a_value); + void setPayloadData(uint32_t a_value, const uint8_t a_size); + + + + void setPayloadData(const uint8_t a_value) { return setPayload1Byte(a_value); } + + + + void setPayloadData(const uint8_t *a_data, const uint16_t a_size); + + + + const char *getData() const { return m_data.data(); } + char *getData() { return m_data.data(); } + QByteArray data() const { return m_data; } + + + + int getSize() const { return m_data.size(); } + + + + gef_telegramm_id_et getTelID() const; + + + + uint8_t zaehler() const; + + + + void setZaehler(const uint8_t a_counter); + + + + uint32_t getPayloadDataUInt32(size_t a_offset, uint16_t a_size) const; + + + + uint8_t getPayloadDataUInt8(size_t a_offset) const; + + + + uint32_t getDestISSI() const; + + + + uint16_t getIdentity() const; + + + + void setSrcISSI(const uint32_t a_ISSI); + + + + bool mustBroadcastBeSet() const; + + + + void setBroadcastIndex(const uint16_t a_broadcastIndex); + + + + void setDestISSI(const uint32_t a_ISSI); + + + + CoPrtCnvRadioTelegram::E_PDU_Type getPDU_Type() const; + + + + CoPrtCnvRadioTelegram::E_FragmentStatus getFragmentStatus() const; + + + + uint8_t getFragmentCounter() const; + + + + bool isCrcOk() const; + + + + uint32_t getSrcISSI() const; + + + + bool isLoginTelegram() const; + + + + bool mustBeFragmented() const; + + + + const uint8_t *getPayloadDataPtr(uint16_t a_offset) const; + uint8_t *getPayloadDataPtr(uint16_t a_offset); + + + + virtual uint16_t getPayloadSize() const; + + + + static QByteArray getUnfragmentedData(const std::multimap &a_fragTelegramList); + + + + static bool isTelegramLengthOk(const uint16_t a_lengthWithoutFrame); + + + + bool isNormalTelegram() const; + + + + uint8_t getPriority() const; + + + + uint16_t getBroadcastIndex() const; + + + + void setPayloadDataWithIndex(const uint16_t a_index, const uint32_t a_value, const uint16_t a_size); + + + + void setPayloadDataComplete(const QByteArray &payload); + + + + void resetPayloadSize(const uint16_t a_newPayloadSize); + + + + void setIdentity(const uint16_t a_identity); + + + + void setProtocolIdentifier(const E_ProtocolIdentifier a_ProtocolIdentifier); + + + + void setMessageReference(const uint8_t a_MessageReference); + + + + bool isSDSTL() const; + + + + CoPrtCnvRadioTelegram::E_RegistrationStatus getRegistrationStatus() const; + + + + std::string getRegistrationStatusAsText() const; + + + + CoPrtCnvRadioTelegram::E_ProtocolIdentifier getProtocolIdentifier() const; + + + + std::string getProtocolIdentifierAsText() const; + + + + uint8_t getMessageReference() const; + + + + uint8_t getAreaSelection() const; + + + + uint8_t getValidityPeriod() const; + + + + uint32_t getForwardAddress() const; + + + + CoPrtCnvRadioTelegram::E_Flags getFlags() const; + + + + std::string getFlagsAsText() const; + + + + uint16_t getLengthInBits() const; + + + + uint16_t getLengthInBytes() const; + + + + bool getWithCrc() const; + + + + CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report getDelivery() const; + + + + std::string getDeliveryAsText() const; + + + + int32_t getPayloadDataSInt24(uint16_t a_offset) const; + + + + bool needsLicensing() const; + + + + bool hasExpired() const; + + + + uint32_t getExpireTime() const; + + + + bool isContentValid(); + + + + bool mustBeSentAsBroadcast(time_t a_currentTime, bool &a_wasLastBroadcast, const bool a_updateBroadcastCounter = true); + + + + static void setBroadcastDelayTimes(int a_2ndDelay, int a_3rdDelay); + + + + static void setMaxBroadcastSendCnt(int a_maxSendCnt); + + + + bool isMovedToBroadcastList() const; + + + + void setBroadcastOnly(const bool a_doSet = true); + + + + bool isBroadcastOnly() const; + + + + void setBroadcastonlyTelegram(const std::shared_ptr &a_radioTelegram); + + + + std::shared_ptr getBroadcastonlyTelegram() const; + + + + uint16_t getBroadcastCounter() const; + + + + +protected: + + + + QByteArray m_data; + + + + uint16_t m_PayloadIndex; + + + uint16_t m_BroadcastCounter; + + + time_t m_NextSendTime; + + + static int s_2ndDelay; + + + static int s_3rdDelay; + + + static int s_maxBroadcastSendCnt; + + + bool m_IsBroadcastOnly; + + + std::shared_ptr m_BroadcastOnlyTelegram; + + + + static bool s_etsMode; + + + + bool isPayloadLengthOk(uint16_t a_minLength, + const uint16_t a_dataAmountOffset, + const uint8_t a_variableDataElementSize) const; + bool isPayloadLengthOk(uint16_t a_minLength, + uint16_t a_maxLength) const; + bool isPayloadLengthOk(uint16_t a_length) const; + bool isPayloadLengthOk(const std::vector &a_lengths) const; + + + + static void set1Byte(QByteArray &a_data, uint16_t a_offset, uint8_t a_value); + + + + static void set2Byte(QByteArray &a_data, uint16_t a_offset, uint16_t a_value); + + + + static void set4Byte(QByteArray &a_data, uint16_t a_offset, uint32_t a_value); + + + uint8_t getUInt8(const uint16_t a_offset) const { return static_cast(m_data.at(a_offset)); } + uint16_t getUInt16(const uint16_t a_offset) const; + uint32_t getUInt32(const uint16_t a_offset) const; + + + + static void setHeader(QByteArray &data, E_PDU_Type pduType); + + + + static void fillDataIndReqHeader(QByteArray &a_data); + + + + static void setSrcISSI_Internal(QByteArray &data, const uint32_t issi); + + + + static void setDestISSI_Internal(QByteArray &data, const uint32_t issi); + +private: + + + NGL::INGLLogger &m_logger; + +}; + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverter.hpp b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverter.hpp new file mode 100644 index 000000000..49eb1aa75 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverter.hpp @@ -0,0 +1,57 @@ + + + + + + + + + + + + + +#pragma once + +#include + +namespace TrainingAreaBase +{ +namespace TetraIcd +{ +struct TrainingAreaTelegram; +} +} +namespace N_CoPrtCnv +{ +class CoPrtCnvRadioTelegram; +class CoPrtCnvCentralTelegram; + + + + +namespace CoPrtCnvTelegramConverter +{ + + +COPRTCNV_EXPORT CoPrtCnvRadioTelegram *convertToRadio(CoPrtCnvCentralTelegram *a_telegram); +COPRTCNV_EXPORT CoPrtCnvRadioTelegram *convertToRadio(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *a_telegram); + + + +COPRTCNV_EXPORT CoPrtCnvCentralTelegram *convertToCentral(const CoPrtCnvRadioTelegram *a_radioTelegram); +COPRTCNV_EXPORT TrainingAreaBase::TetraIcd::TrainingAreaTelegram *convertToTabTele(const CoPrtCnvRadioTelegram *a_radioTelegram); + + + + +COPRTCNV_EXPORT void setTetraTextCodec(const char *codecName); + + + +COPRTCNV_EXPORT void setUse2BytesForSingleFireDiameter(bool bUse); +COPRTCNV_EXPORT void setUsePvSan(bool bUse); + +} + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverterNewIcd.cpp b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverterNewIcd.cpp new file mode 100644 index 000000000..09fed4816 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverterNewIcd.cpp @@ -0,0 +1,2131 @@ + + + + + + + + + + + + + + +#include "CoPrtCnvTelegramConverter.hpp" + + +#include +#include +#include +#include +#include "CoPrtCnvCentralTelegram.hpp" +#include "CoPrtCnvRadioTelegram.hpp" +#include +#include +#include +#include + +using namespace TrainingAreaBase::TetraIcd; +namespace N_CoPrtCnv +{ + +namespace CoPrtCnvTelegramConverter +{ + +static QTextCodec *s_TetraTextCodec = nullptr; +static bool s_needTextCodec = false; +static bool s_use2BytesForSingleFireDiameter = true; +static bool s_usePvSan = false; + +static inline NGL::INGLLogger &logger() +{ + return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvTelegramConverter"); +} + +template +static inline bool checkBitmask(const T &d, int bitmask) +{ + return ((d & bitmask) == bitmask); +} + +template +void getSpecialSensorData(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t offset, T *tele) +{ + const uint8_t betrZust = a_radioTelegram->getPayloadDataUInt32(offset, 1); + const uint8_t spuerfunktion = a_radioTelegram->getPayloadDataUInt32(offset + 1, 1); + tele->operationalState = betrZust; + tele->airSensor = checkBitmask(spuerfunktion, 0x80); + tele->tireSensor = checkBitmask(spuerfunktion, 0x40); + tele->pointSensor = checkBitmask(spuerfunktion, 0x20); + tele->solidMatterSampleExtractor = checkBitmask(spuerfunktion, 0x10); +} + +int getVitality(uint32_t index) +{ + uint32_t vitalty = (index &= 0xF000); + uint32_t retVitalty = 0; + retVitalty = vitalty >> 12; + if (retVitalty > 0) + { + retVitalty -= 1; + return retVitalty * 10; + } + return UINT16_MAX; +} + +void setVitality(uint16_t &index, uint16_t vitality) +{ + if (vitality == UINT16_MAX) + vitality = 0; + else + { + vitality /= 10; + vitality += 1; + if (vitality > 11) + { + ERROR_LOG(logger()) << "Cant convert Vitality!"; + return; + } + } + for (int i = 0; i <= 3; i++) + { + if (((vitality) & (1 << (i)))) + index |= (1UL << (i + 12)); + } +} +template +void getTaktZustand(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t iOffset, T *tele) +{ + tele->vulnerabilityState = static_cast( + a_radioTelegram->getPayloadDataUInt32(iOffset + 0, 1)); + + const uint32_t teilnehmertyp = a_radioTelegram->getPayloadDataUInt32(iOffset + 1, 1); + const uint32_t index = a_radioTelegram->getPayloadDataUInt32(iOffset + 2, 2); + if (index) + { + uint32_t indexForVulnerabilit = index; + indexForVulnerabilit &= 0x0FFF; + tele->tasVulnerabilityKindId = teilnehmertyp; + tele->tasVulnerabilityKindId <<= 16; + tele->tasVulnerabilityKindId |= indexForVulnerabilit; + tele->tasVitality = getVitality(index); + } + else + tele->tasVulnerabilityKindId = 0; + + + tele->vulnerabilityBits = 0; + int tmp = a_radioTelegram->getPayloadDataUInt32(iOffset + 4, 2); + + if (tmp == 0) + tele->vulnerabilityBits |= 0x1; + else + { + + for (int i = 1; i <= static_cast(VulnerabilityState::CContamination); ++i) + tele->vulnerabilityBits |= ((tmp >> (16 - i)) & 0x1) << (i); + } +} + +static BiteError getBiteError(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t iOffset) +{ + BiteError ret; + ret.canDeviceNumber = a_radioTelegram->getPayloadDataUInt8(iOffset + 0); + ret.subdeviceNumber = a_radioTelegram->getPayloadDataUInt8(iOffset + 1); + ret.uniqueId = a_radioTelegram->getPayloadDataUInt32(iOffset + 2, 4); + ret.errorNumber = a_radioTelegram->getPayloadDataUInt8(iOffset + 6); + + return ret; +} + +static void convertToTetraEncoding(N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegramm, + const std::string &stdString, + const uint16_t a_size) +{ + QByteArray encodedData; + if (s_needTextCodec && s_TetraTextCodec) + { + + const QString str = QString::fromUtf8(stdString.c_str()); + + encodedData = s_TetraTextCodec->fromUnicode(str); + } + else + encodedData = QByteArray(stdString.c_str(), a_size); + + encodedData = encodedData.leftJustified(a_size, '\0', true); + + encodedData[a_size - 1] = '\0'; + + const uint8_t *data = reinterpret_cast(encodedData.data()); + radioTelegramm->setPayloadData(data, a_size); +} + +void setTetraTextCodec(const char *codecName) +{ + if (codecName) + s_TetraTextCodec = QTextCodec::codecForName(codecName); + else + s_TetraTextCodec = nullptr; + s_needTextCodec = (s_TetraTextCodec != nullptr); +} + +void setUse2BytesForSingleFireDiameter(bool bUse) +{ + s_use2BytesForSingleFireDiameter = bUse; +} + +void setUsePvSan(bool bUse) +{ + s_usePvSan = bUse; +} + +template +T fromJson(CoPrtCnvCentralTelegram *radioTelegram) +{ + return T::fromJson(radioTelegram->jsonData()); +} + +template +const T &fromJson(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTelegram) +{ + return static_cast(*tabTelegram); +} + +TrainingAreaBase::TetraIcd::TelegramId getTelegramId(CoPrtCnvCentralTelegram *centralTelegram) +{ + return TrainingAreaBase::TetraIcd::TelegramId(centralTelegram->telegramId()); +} + +TrainingAreaBase::TetraIcd::TelegramId getTelegramId( + const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTelegram) +{ + return tabTelegram->id(); +} + +void convertToSecAndSetTime(int64_t timeStamp, N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram) +{ + radioTelegram->setPayloadData((uint32_t)(timeStamp / 1000), 4); +} + +template +void setCommonAesParams(const T &tele, CoPrtCnvRadioTelegram *radioTelegram) +{ + radioTelegram->setPayloadData((uint32_t) 0, 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + convertToTetraEncoding(radioTelegram, tele.name, 8); + radioTelegram->setPayloadData(tele.partyId, 1); + convertToSecAndSetTime(tele.effectStart, radioTelegram); +} + +template +void setAesPosition(const T &tele, CoPrtCnvRadioTelegram *radioTelegram) +{ + radioTelegram->setPayloadData(tele.relEffectPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetX, 3); +} + + +static inline int compassToMathAngleForSfm(double compassDegree) +{ + int ret = qRound((90.0 - compassDegree) * 100.0); + while (ret < 0) + ret += 36000; + while (ret > 36000) + ret -= 36000; + return ret; +} + + + + + +template +static CoPrtCnvRadioTelegram *convertToRadioInternal(T *a_telegram) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram = nullptr; + switch (getTelegramId(a_telegram)) + { + case Constraints::id(): + { + const Init &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_INIT, 4, tele.header.equipmentNumber); + uint8_t initialisierungsdaten = 0; + initialisierungsdaten |= ((uint8_t(tele.resetVulnerabilityState) & 0x01) << 6); + initialisierungsdaten |= ((uint8_t(tele.restockCharges) & 0x01) << 5); + initialisierungsdaten |= ((uint8_t(tele.resetManipulation) & 0x01) << 0); + initialisierungsdaten |= ((uint8_t(tele.restockSanitationMaterial) & 0x01) << 1); + + + + radioTelegram->setPayloadData(initialisierungsdaten); + break; + } + + case Constraints::id(): + { + const SetVulnerabilityModel &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_KONFIGURATION_WIRKMODELL, + 9, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelMineIed); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelAreaFire); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelOperatingResource); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelAcWeaponry); + break; + } + case Constraints::id(): + { + const DemandEquipmentConfigurationReport &tele( + fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_ANFORDERUNG_KONFIGURATIONSDATEN, + 3, + tele.header.equipmentNumber); + break; + } + case Constraints::id(): + { + const StateChange &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TAKTISCHER_STATUS, + 16, + tele.header.equipmentNumber); + + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityState); + radioTelegram->setPayloadData((uint8_t)(tele.tasVulnerabilityKindId & 0xFF)); + uint16_t vulnerabilityVitalityIndex = 0; + vulnerabilityVitalityIndex = (uint16_t)((tele.tasVulnerabilityKindId >> 16) & 0xFFFF); + setVitality(vulnerabilityVitalityIndex, tele.tasVitality); + radioTelegram->setPayloadData((uint16_t) vulnerabilityVitalityIndex, 2); + + + radioTelegram->setPayloadData((uint16_t) tele.vulnerabilityBits, 2); + + radioTelegram->setPayloadData((uint8_t) tele.originatorId); + radioTelegram->setPayloadData((uint16_t) tele.originatorType, 2); + break; + } + case Constraints::id(): + { + const BiteReport &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_BITE_MELDUNG2, + 27, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData((uint8_t) tele.loginType); + radioTelegram->setPayloadData((uint32_t) tele.biteState, 3); + radioTelegram->setPayloadData((uint8_t) tele.batteryState); + + if (tele.biteErrors.size() > 0) + { + radioTelegram->setPayloadData((uint8_t) tele.biteErrors[0].canDeviceNumber); + radioTelegram->setPayloadData((uint8_t) tele.biteErrors[0].subdeviceNumber); + radioTelegram->setPayloadData((uint32_t) tele.biteErrors[0].uniqueId, 4); + radioTelegram->setPayloadData((uint8_t) tele.biteErrors[0].errorNumber); + radioTelegram->setPayloadData((uint8_t) tele.biteErrors.size() - 1); + } + else + { + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint32_t) 0, 4); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) 0); + } + + radioTelegram->setPayloadData((uint32_t) 0, 3); + radioTelegram->setPayloadData((uint8_t) tele.configError); + radioTelegram->setPayloadData((uint32_t) tele.configState, 3); + + for (const BiteError &be : tele.biteErrors) + { + radioTelegram->setPayloadData((uint8_t) be.canDeviceNumber); + radioTelegram->setPayloadData((uint8_t) be.subdeviceNumber); + radioTelegram->setPayloadData((uint32_t) be.uniqueId, 4); + radioTelegram->setPayloadData((uint8_t) be.errorNumber); + } + break; + } + case Constraints::id(): + { + const ExerciseEnvironmentData &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_UMGEBUNGS_MELDUNG2, + 20, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.exerciseId, 2); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData( + (uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) tele.timeZone); + radioTelegram->setPayloadData((uint8_t) tele.utmZone); + radioTelegram->setPayloadData(tele.utmBand); + radioTelegram->setPayloadData((uint8_t *) tele.grid.c_str(), 2); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint32_t) 0, + 4); + break; + } + case Constraints::id(): + { + const DemandBite &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_AUFFORDERUNG_BITE_MELDUNG, + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.withSelfTest, 1); + break; + } + case Constraints::id(): + { + const PositionReport &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_POSITIONS_MELDUNG, + 14, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData(tele.relPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relPosition.offsetX, 3); + radioTelegram->setPayloadData((uint8_t)(((tele.gpsQuality.moreThan4SatellitesAvailable) ? 0x80 + : 0) + | ((tele.gpsQuality.dgpsModeAvailable) ? 0x40 : 0) + | (tele.gpsQuality.pdopValue & 0x3f)), + 1); + break; + } + case Constraints::id(): + { + const CreateSingleExplosion &tele(fromJson(a_telegram)); + + const int teleSize = s_use2BytesForSingleFireDiameter ? 29 : 28; + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_EINZELGESCHOSS, + teleSize, + tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + setAesPosition(tele, radioTelegram); + if (s_use2BytesForSingleFireDiameter) + { + Q_ASSERT(tele.effectDiameter < 256 * 256 && tele.effectDiameter >= 0); + radioTelegram->setPayloadData(tele.effectDiameter, 2); + } + else + { + Q_ASSERT(tele.effectDiameter < 256 && tele.effectDiameter >= 0); + radioTelegram->setPayloadData(tele.effectDiameter, 1); + } + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + break; + } + case Constraints::id(): + { + const CreateAreaExplosion &tele(fromJson(a_telegram)); +#ifdef GUEZ_MODE + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER, + 44 + tele.mhPoints.size() * 6, + tele.header.equipmentNumber); +#else + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER, + 36, + tele.header.equipmentNumber); +#endif + + setCommonAesParams(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectDuration / 1000, 2); + + + + + + + + + + + + + + + + + radioTelegram->setPayloadData(tele.relCorner.offsetY, 3); + radioTelegram->setPayloadData(tele.relCorner.offsetX, 3); + radioTelegram->setPayloadData(tele.width / 5, 1); + radioTelegram->setPayloadData(tele.height / 5, 1); + radioTelegram->setPayloadData( + compassToMathAngleForSfm(tele.rotationAngle + 90.0), + 2); + +#ifdef GUEZ_MODE + + radioTelegram->setPayloadData(tele.mhpWidth / 5, 1); + radioTelegram->setPayloadData(tele.mhpLength / 5, 1); + + radioTelegram->setPayloadData( + compassToMathAngleForSfm(tele.mhpRotation + 90.0), + 2); +#endif + radioTelegram->setPayloadData(tele.impactCount, 2); +#ifdef GUEZ_MODE + radioTelegram->setPayloadData(tele.impactRadius, 2); +#else + radioTelegram->setPayloadData(tele.impactEdgeLength, 1); +#endif + radioTelegram->setPayloadData(tele.chargeTypeId, 1); +#ifdef GUEZ_MODE + + radioTelegram->setPayloadData((tele.hazardDistance / 5), 1); + radioTelegram->setPayloadData((uint8_t) 0); + + radioTelegram->setPayloadData(tele.mhPoints.size(), 1); + for(auto pos : qAsConst(tele.mhPoints)) + { + radioTelegram->setPayloadData(pos.offsetY, 3); + radioTelegram->setPayloadData(pos.offsetX, 3); + } +#endif + + break; + } + case Constraints::id(): + { + const PauseEffectSimulation &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP, + 7, + 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + break; + } + case Constraints::id(): + { + const ResumeEffectSimulation &tele(fromJson(a_telegram)); + radioTelegram + = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN, + 17, + 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.sequelNumber, 2); + radioTelegram->setPayloadData(tele.nextImpact, 2); + convertToSecAndSetTime(tele.resumeTime, radioTelegram); + radioTelegram->setPayloadData(tele.remainDuration / 1000, 2); + break; + } + case Constraints::id(): + { + const CreateMineArea &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_MINENSPERRE, 5 + 22 + tele.segments.size() * 12, tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + + radioTelegram->setPayloadData(tele.effectDuration / (1000 * 60 * 60), 1); + + + + radioTelegram->setPayloadData(qRound(tele.layingDepth), 1); + radioTelegram->setPayloadData(qRound(tele.layingDensity * 100), 1); + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + + double length =0; + for (const MineAreaSegment &ms : tele.segments) + { + length+= QLineF(ms.relStart.offsetX, ms.relStart.offsetY, ms.relEnd.offsetX, ms.relEnd.offsetY).length(); + } + int minecount = qRound(length*tele.layingDensity); + if (minecount > 1200) + minecount = 1200; + radioTelegram->setPayloadData((uint32_t)minecount, 2); + radioTelegram->setPayloadData(tele.segments.size(), 1); + for (const MineAreaSegment &ms : tele.segments) + { + radioTelegram->setPayloadData(ms.relStart.offsetY, 3); + radioTelegram->setPayloadData(ms.relStart.offsetX, 3); + radioTelegram->setPayloadData(ms.relEnd.offsetY, 3); + radioTelegram->setPayloadData(ms.relEnd.offsetX, 3); + } + break; + } + case Constraints::id(): + { + const MineAreaSingleMineState &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_STATUS_MINENSPERRE, + 5 + 4 + tele.mineState.size(), + 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.mineCount, 2); + radioTelegram->setPayloadData((uint8_t *)(tele.mineState.data()), tele.mineState.size()); + break; + } + case Constraints::id(): + { + const CreateNContamination &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_A_KAMPFMITTEL, + 38, + tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectDuration / (1000 * 60), 2); + setAesPosition(tele, radioTelegram); + radioTelegram->setPayloadData(tele.innerRadius, 2); + radioTelegram->setPayloadData(tele.borderLengthInner, 2); + radioTelegram->setPayloadData(tele.borderLengthOuter, 2); + radioTelegram->setPayloadData(qRound(tele.spanAngle * 100), 2); + radioTelegram->setPayloadData(compassToMathAngleForSfm(tele.rotationAngle), + 2); + break; + } + case Constraints::id(): + { + const CreateCContamination &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_C_KAMPFMITTEL, + 45, + tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectDuration / (1000 * 60), 1); + setAesPosition(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectRadius, 2); + radioTelegram->setPayloadData(qRound(tele.expansionFactor * 100), 1); + radioTelegram->setPayloadData(compassToMathAngleForSfm(tele.propagationDirection), + 2); + radioTelegram->setPayloadData(tele.windSpeed, 1); + convertToSecAndSetTime(tele.validityTimeWind, radioTelegram); + radioTelegram->setPayloadData(tele.relPositionValidityTimeWind.offsetY, 3); + radioTelegram->setPayloadData(tele.relPositionValidityTimeWind.offsetX, 3); + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + radioTelegram->setPayloadData((uint8_t) tele.volatility, 1); + break; + } + case Constraints::id(): + { + const DeactivateEffectSimulation &tele(fromJson(a_telegram)); + if (tele.aesType == AreaEffectSimulationType::FunctionalArea) + { + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DEAKTIVIEREN_FUNKTIONSRAUM, 7, 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + } + else + { + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DEAKTIVIERUNG_WIRKFELD, 8, 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.aesType, 1); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + } + break; + } + case Constraints::id(): + { + const ModifyAreaEffectSimulationName &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_AENDERUNG_BEZEICHNER, 16, 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.aesType, 1); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + convertToTetraEncoding(radioTelegram, tele.name, 8); + break; + } + case Constraints::id(): + { + const MineTriggered &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DEAKTIVIERUNG_EINZELMINE, + 13, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData(tele.mineAreaId, 2); + radioTelegram->setPayloadData(tele.mineIndex, 2); + break; + } + case Constraints::id(): + { + const DusMineReactivation &tele(fromJson(a_telegram)); + + const size_t cnt = tele.dusSerialNumbers.size() > 500 ? 500 : tele.dusSerialNumbers.size(); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_REAKTIVIERUNG_DUS_MINE, + 3 + 2 + 2 + 2 * cnt, + tele.header.equipmentNumber); + radioTelegram->setPayload2Byte(0); + radioTelegram->setPayload2Byte(cnt); + for (size_t i = 0; i < cnt; i++) + radioTelegram->setPayload2Byte(tele.dusSerialNumbers.at(i)); + break; + } + case Constraints::id(): + { + const CreateDusSingleMine &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_EINZELMINENSIMULATOR, + 21, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.partyId, 1); + radioTelegram->setPayloadData(tele.mineId, 2); + convertToSecAndSetTime(tele.effectStart, radioTelegram); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetX, 3); + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + break; + } + case Constraints::id(): + { + const DemandVulnerabilityStateChange &tele(fromJson(a_telegram)); +#ifdef GUEZ_MODE + if (s_usePvSan) + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_AUSLOESUNG, + 10, + tele.header.equipmentNumber); + else + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_AUSLOESUNG, + 8, + tele.header.equipmentNumber); +#else + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_AUSLOESUNG, + 8, + tele.header.equipmentNumber); +#endif + + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData((uint8_t) tele.reqestedState, 1); + +#ifdef GUEZ_MODE + if (s_usePvSan) + radioTelegram->setPayloadData((uint16_t) tele.vulnerabilityVitalityIndex, 2); +#endif + + break; + } + case Constraints::id(): + { + const TechnicalArea &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TECHNIK_FUNKTIONSRAUM, + 34, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.taType, 1); + convertToTetraEncoding(radioTelegram, tele.name, 8); + radioTelegram->setPayloadData(tele.relCorner.offsetY, 3); + radioTelegram->setPayloadData(tele.relCorner.offsetX, 3); + radioTelegram->setPayloadData(tele.width, 2); + radioTelegram->setPayloadData(tele.height, 2); + radioTelegram->setPayloadData((uint32_t) 0, 4); + radioTelegram->setPayloadData((uint32_t) 0, 4); + break; + } + case Constraints::id(): + { + const CreateFunctionalArea &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_FUNKTIONSRAUM, + 30, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + convertToTetraEncoding(radioTelegram, tele.name, 8); + radioTelegram->setPayloadData(tele.partyId, 1); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetX, 3); + radioTelegram->setPayloadData(tele.width / 5, 1); + radioTelegram->setPayloadData(tele.height / 5, 1); + radioTelegram->setPayloadData((uint8_t) tele.deconMode, 1); + radioTelegram->setPayloadData(tele.deconTimeout / 1000 / 60 / 10, + 1); + radioTelegram->setPayloadData((uint8_t) tele.maintenanceMode, 1); + radioTelegram->setPayloadData(tele.maintenanceTimeout / 1000 / 60 / 10, + 1); + radioTelegram->setPayloadData((uint8_t) tele.medicalMode, 1); + radioTelegram->setPayloadData(tele.medicalTimeout / 1000 / 60 / 10, + 1); + break; + } + case Constraints::id(): + { + const LanguageSelection &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SPRACHAUSWAHL, + 6, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.languageSelection, 1); + break; + } + case Constraints::id(): + { + + const EquipmentMessage &tele(fromJson(a_telegram)); + + + + + int len = 0; + int messageLength = (tele.message.size() > 81) + ? 81 + : tele.message.size(); + if (tele.msgId == -1) + len = messageLength + 6; + + + else + len = 9; + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_ALLGEMEINE_NACHRICHT, + len, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + if (tele.msgId != -1) + { + + + radioTelegram->setPayloadData(3, 1); + + + + radioTelegram->setPayloadData((uint32_t) 0, 1); + radioTelegram->setPayloadData(tele.msgId, 2); + + + + } + else + { + radioTelegram->setPayloadData(tele.message.size(), 1); + radioTelegram->setPayloadData((uint8_t *)(tele.message.c_str()), messageLength); + } + break; + } + case Constraints::id(): + { + const OpaquePayloadDataOut &tele(fromJson(a_telegram)); + switch (tele.payloadType) + { + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::FireSmokeMarker: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_DMF, + tele.payload.size() + 3, + tele.header.equipmentNumber); + break; + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::Geopairing: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_GEOP, + tele.payload.size() + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.payload.size(), 1); + break; + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::Target: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_TGTC, + tele.payload.size() + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.payload.size(), 1); + break; + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::OC: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_SRT, + tele.payload.size() + 3, + tele.header.equipmentNumber); + break; + } + + radioTelegram->setPayloadData((uint8_t *)(tele.payload.data()), tele.payload.size()); + break; + } + + case Constraints::id(): + { + const CesHitInformation &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_AUSLOESUNG_DUS_TREFFER, + 16, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData(tele.chargeTasCodeDirect, 2); + radioTelegram->setPayloadData(tele.directionDegree, 2); + radioTelegram->setPayloadData(tele.distance, 2); + radioTelegram->setPayloadData(tele.effectPercent, 1); + radioTelegram->setPayloadData(tele.originatorEquipmentNumber, 2); + break; + } + + case Constraints::id(): + { + const ParticipantSwVersionsRequest &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_ANFORDERUNG_SW_VERSION, + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.equipmentFunctionId, 1); + break; + } + + case Constraints::id(): + { + const ParticipantMode &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMERMODE_SETZEN, + 13, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.language, 1); + radioTelegram->setPayloadData((uint8_t) tele.operationMode, 1); + radioTelegram->setPayloadData(tele.reactivationDetoxication / 10, 1); + radioTelegram->setPayloadData(tele.reactivationMaintenance / 10, 1); + radioTelegram->setPayloadData(tele.reactivationMedic / 10, 1); + unsigned char wph_mode = 0; + wph_mode |= ((uint8_t) tele.modeHelmet & 0x03); + wph_mode |= ((uint8_t) tele.modeVest & 0x03) << 2; + wph_mode |= ((uint8_t) tele.personellProtectionMode & 0x07) << 4; + radioTelegram->setPayloadData(wph_mode, 1); + + unsigned char protection_mode = 0; + protection_mode |= ((uint8_t) tele.protectionLevel & 0x07); + protection_mode |= ((uint8_t) tele.abcProtectionMode & 0x03) << 3; + radioTelegram->setPayloadData(protection_mode, 1); + + unsigned char specialFunction = 0; + specialFunction |= ((uint8_t) tele.handgrenadeSearchMode & 0x03); + specialFunction |= ((uint8_t) tele.internationalMode & 0x03) << 2; + specialFunction |= ((uint8_t) tele.abcProtectionMode & 0x03) << 3; + radioTelegram->setPayloadData(specialFunction, 1); + break; + } + case Constraints::id(): + { + const DemandParticipantMode &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMERMODE_ANFORDERN, + 3, + tele.header.equipmentNumber); + break; + } + case Constraints::id(): + { + const ParticipantConfiguration &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMER_KONFIG_SETZEN, + 25, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.positionIntervallVehicle, 2); + radioTelegram->setPayloadData(tele.positionIntervallPersonell, 2); + radioTelegram->setPayloadData(tele.positionIntervallAircraft, 2); + radioTelegram->setPayloadData(tele.positionTransmissionIntervall, 2); + radioTelegram->setPayloadData(tele.heightbarrier, 2); + unsigned char tmp = ((uint8_t) tele.faultPositionHandling & 0x03) << 6; + tmp |= ((uint8_t) tele.switchingPositionIntervall & 0x03); + radioTelegram->setPayloadData(tmp, 1); + radioTelegram->setPayloadData(tele.waittimeAdditionalBroadcastDemand, 2); + radioTelegram->setPayloadData(tele.factorWaittimeIncreaseAtHighload, 1); + radioTelegram->setPayloadData(tele.waittimeAutomaticVulnerabilityIncreaseLevel1, 1); + radioTelegram->setPayloadData(tele.waittimeAutomaticVulnerabilityIncreaseLevel2, 1); + radioTelegram->setPayloadData(tele.waittimeAutomaticVulnerabilityIncreaseLevel3, 1); + radioTelegram->setPayloadData((uint8_t) tele.opticalCode, 1); + radioTelegram->setPayloadData(tele.vulnerabilityModel, 1); + radioTelegram->setPayloadData(tele.validTimeOps, 1); + break; + } + case Constraints::id(): + { + const DemandParticipantConfiguration &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMER_KONFIG_ANFORDERN, + 3, + tele.header.equipmentNumber); + break; + } + case Constraints::id(): + { + const SanitationRepair &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SANITAETSDIENST_INSTANDSETZUNG, + 19, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + + radioTelegram->setPayload1Byte(uint8_t(tele.originatorType)); + radioTelegram->setPayload2Byte(tele.equipmentNumberOrigin); + radioTelegram->setPayload1Byte(uint8_t(tele.stateStart)); + + unsigned int bitfield1 = 0; + if (tele.timeOfTreatment) + bitfield1 |= 0x7F; + if (tele.triage) + bitfield1 |= 0x80; + radioTelegram->setPayload1Byte(bitfield1); + + radioTelegram->setPayload1Byte(tele.tyeOfDamage); + + unsigned int bitfield2 = 0; + bitfield2 |= (uint8_t(tele.stateResult) | 0x0F); + bitfield2 |= ((uint8_t(tele.treatmentResult) | 0x30) << 4); + bitfield2 |= (0xC0 << 6); + radioTelegram->setPayload1Byte(bitfield2); + + radioTelegram->setPayload1Byte(tele.fullState); + radioTelegram->setPayloadData(tele.timeOfTreatment, 2); + radioTelegram->setPayloadData(tele.timeOfRecovery, 2); + break; + } + case Constraints::id(): + { + const SanitaryMaterialStockReport &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_BESTANDSMELDUNG_SANITAETSMATERIAL, + 15 + tele.sanitaryMaterialCount, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayload4Byte(tele.uniqueId); + radioTelegram->setPayload2Byte(tele.originatorEquipmentNumber); + radioTelegram->setPayload1Byte((uint8_t) tele.qualification); + + radioTelegram->setPayload1Byte(tele.sanitaryMaterialCount); + + for (const auto stock : tele.sanitaryMaterialStock) + radioTelegram->setPayloadData(stock, 1); + + break; + } + case Constraints::id(): + { + const Sanitation &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN, + 23, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + + int p1 = tele.proceduresTaken & 0xFFFFFFFF; + int p2 = tele.proceduresTaken >> 32; + + radioTelegram->setPayloadData(p2, 4); + radioTelegram->setPayloadData(p1, 4); + radioTelegram->setPayloadData(tele.uniqeId, 4); + radioTelegram->setPayloadData(tele.originatorEquipmentNumber, 2); + radioTelegram->setPayloadData((uint8_t) tele.qualification, 1); + + quint8 sanResultAndEvaluation = (((uint8_t) tele.sanitationEvaluation & 0x03) << 6) + + ((uint8_t) tele.sanitationResult & 0x3f); + radioTelegram->setPayloadData(sanResultAndEvaluation, 1); + + break; + } + case Constraints::id(): + { + const CesHitRequest &tele(fromJson(a_telegram)); + + + + + + + + + + + + + + int chargeTasCode = tele.chargeTasCodeDirect; + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG, + 17, + tele.header.equipmentNumber); + const bool insideBuilding = (tele.roomId > 0 && tele.buildingId > 0); + int remainEffectOrTasCodeDirect = 0; + int reserve1 = tele.mineId; + int reserve2 = 0; + int gpsZeit = tele.header.timeStamp ; + switch (tele.aesType) + { + case AreaEffectSimulationType::Unknown: + + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + if (remainEffectOrTasCodeDirect == 100) + { + remainEffectOrTasCodeDirect = 49; + } + break; + case AreaEffectSimulationType::FunctionalArea: + + + + + + + + + + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + + + + chargeTasCode = tele.chargeTasCodeIndirect; + reserve1 = tele.reserve1; + reserve2 = tele.reserve2; + break; + case AreaEffectSimulationType::AirSupport: + case AreaEffectSimulationType::NContamination: + case AreaEffectSimulationType::MineArea: + case AreaEffectSimulationType::CContamination: + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + chargeTasCode = tele.chargeTasCodeIndirect; + break; + case AreaEffectSimulationType::DangerZoneExplosion: + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + chargeTasCode = tele.chargeTasCodeIndirect; + reserve1 = tele.reserve1; + break; + case AreaEffectSimulationType::ExplosionArea: + case AreaEffectSimulationType::ExplosionSingle: + if (insideBuilding) + { + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + } + else + { + + remainEffectOrTasCodeDirect = 255; + chargeTasCode = tele.chargeTasCodeIndirect; + } + break; + case AreaEffectSimulationType::GasPipeDetonation: + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + break; + default: + + remainEffectOrTasCodeDirect = tele.remainEffectPercent; + chargeTasCode = tele.chargeTasCodeIndirect; + break; + } + + radioTelegram->setPayloadData((uint32_t) gpsZeit, 4); + radioTelegram->setPayload2Byte(chargeTasCode); + if (tele.aesDdsId != 0) + radioTelegram->setPayload2Byte(tele.aesDdsId); + else + radioTelegram->setPayload2Byte(tele.originatorEquipmentNumber); + + radioTelegram->setPayload1Byte(uint8_t(tele.aesType)); + radioTelegram->setPayload1Byte(remainEffectOrTasCodeDirect); + radioTelegram->setPayload2Byte(reserve1); + radioTelegram->setPayload2Byte(reserve2); + DEBUG_LOG(logger()) << "Reserve1 of CesHitRequest: " << reserve1 << " Reserve2: " << reserve2; + + break; + } + case Constraints::id(): + { + const SelectiveReammunition &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SELEKTIVE_AUFMUNITIONIERUNG, + 8 + tele.reammunitions.size() * 8, + tele.header.equipmentNumber); + radioTelegram->setPayload4Byte(tele.gearId); + radioTelegram->setPayload1Byte(tele.reammunitions.size()); + for (const auto &reammunition : tele.reammunitions) + { + radioTelegram->setPayload2Byte(reammunition.chargeTypeId); + radioTelegram->setPayload1Byte(reammunition.location); + radioTelegram->setPayload2Byte(reammunition.newStock); + radioTelegram->setPayload2Byte(reammunition.newDefaultStock); + radioTelegram->setPayload1Byte(reammunition.tracerRatio); + } + break; + } + case Constraints::id(): + { + const OcCommand &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SCHIEDSRICHTERKOMMANDO, + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.action, 1); + break; + } + default: + { + ERROR_LOG(logger()) << "Conversion of Central-Telegram to Radio-Telegram with telId=" + << getTelegramId(a_telegram) << " not implemented!"; + } + + + } + return radioTelegram; +} + +CoPrtCnvRadioTelegram *convertToRadio(CoPrtCnvCentralTelegram *a_telegram) +{ + return convertToRadioInternal(a_telegram); +} + +CoPrtCnvRadioTelegram *convertToRadio( + const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *a_telegram) +{ + return convertToRadioInternal(a_telegram); +} + +static inline Header getHeader(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t tsOffset) +{ + Header hdr; + hdr.equipmentNumber = a_radioTelegram->getIdentity(); + hdr.timeStamp = a_radioTelegram->getPayloadDataUInt32(tsOffset, 4) * 1000LL; + return hdr; +} + +static inline RelativePosition getRelativePosition(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offset) +{ + RelativePosition pos; + pos.offsetY = a_radioTelegram->getPayloadDataSInt24(offset); + pos.offsetX = a_radioTelegram->getPayloadDataSInt24(offset + 3); + return pos; +} + +static inline GpsQuality getGpsQuality(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t offset) +{ + const uint8_t gps = a_radioTelegram->getPayloadDataUInt8(offset); + GpsQuality ret; + ret.moreThan4SatellitesAvailable = ((gps & 0x80) == 0x80); + ret.dgpsModeAvailable = ((gps & 0x40) == 0x40); + ret.pdopValue = (gps & 0x3f); + return ret; +} + +static inline OpsPosition getOpsPosition(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offset, + size_t *newOffset = nullptr) +{ + const uint8_t opsLen = a_radioTelegram->getPayloadDataUInt8(offset); + offset += 1; + OpsPosition pos; + pos.opsId = -1; + if (opsLen > 0) + { + std::vector opse; + opse.reserve(opsLen); + for (uint32_t i = 0; i < opsLen; i++) + { + opse.push_back(a_radioTelegram->getPayloadDataUInt32(offset, 2)); + offset += 2; + } + pos.opsId = opse.at(opse.size() - 1); + } + if (newOffset) + *newOffset = offset; + return pos; +} + +static inline std::vector getPayload(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offsetData) +{ + int payloadLen = a_radioTelegram->getPayloadSize(); + payloadLen -= offsetData; + if (payloadLen <= 0) + { + ERROR_LOG(logger()) << "Radio-Telegram Datenverkehr SRT-TDS contains too less data: " + << payloadLen; + return {}; + } + std::vector ret; + ret.resize(payloadLen); + memcpy(ret.data(), a_radioTelegram->getPayloadDataPtr(offsetData), payloadLen); + return ret; +} + +static inline std::vector getPayload(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offsetLen, + size_t offsetData) +{ + int payloadLen = a_radioTelegram->getPayloadDataUInt8(offsetLen); + if (payloadLen <= 0) + { + ERROR_LOG(logger()) << "Radio-Telegram Datenverkehr SRT-TDS contains too less data: " + << payloadLen; + return {}; + } + std::vector ret; + ret.resize(payloadLen); + memcpy(ret.data(), a_radioTelegram->getPayloadDataPtr(offsetData), payloadLen); + return ret; +} + +static N_CoPrtCnv::CoPrtCnvCentralTelegram *toCentral( + const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *data) +{ + QJsonObject obj; + obj[QStringLiteral("data")] = data->toJson(); + obj[QStringLiteral("type")] = data->type(); + obj[QStringLiteral("typeId")] = data->id(); + const QByteArray ba = QJsonDocument(obj).toJson(QJsonDocument::Compact); + return new N_CoPrtCnv::CoPrtCnvCentralTelegram(ba, + static_cast( + data->id())); +} + +template +void fixupEnum(T lowerBound, T upperBound, T defaultVal, T &valToFixup) +{ + if (valToFixup >= lowerBound && valToFixup <= upperBound) + return; + valToFixup = defaultVal; +} + + + + + + +static bool isPayloadLengthOk(const CoPrtCnvRadioTelegram *tele, uint16_t a_length) +{ + const uint16_t length = tele->getPayloadSize(); + if (length >= a_length) + return true; + + WARNING_LOG(logger()) << "The payload-length of telegram with telId: " << tele->getTelID() + << " must be " << a_length << ", but it is " << length; + return false; +} + +static bool isPayloadLengthOk(const CoPrtCnvRadioTelegram *tele, + uint16_t a_minLength, + const uint16_t a_dataAmountOffset, + const uint8_t a_variableDataElementSize, + bool useHalf = false) +{ + if (0 == a_variableDataElementSize) + return isPayloadLengthOk(tele, a_minLength); + + const uint16_t length = tele->getPayloadSize(); + if (length >= a_minLength) + { + uint8_t dataAmount = tele->getPayloadDataUInt8(a_dataAmountOffset); + uint16_t dataSize = a_variableDataElementSize * dataAmount; + if (useHalf) + { + if ((dataAmount % 2) == 1) + dataSize = a_variableDataElementSize * ((dataAmount / 2.0) + 0.5); + else + dataSize = a_variableDataElementSize * (dataAmount / 2); + } + uint16_t expectedLength = dataSize + a_minLength; + if (expectedLength != length) + { + WARNING_LOG(logger()) << "The payload-length of telegram with telId: " << tele->getTelID() + << " must be " << expectedLength << ", but it is " << length + << " (the amount of variable data in telegram was " << dataAmount + << " => " << dataSize << " bytes)"; + return false; + } + } + else + { + WARNING_LOG(logger()) << "The payload-length of telegram with telId: " << tele->getTelID() + << " must be at least " << a_minLength << ", but it is only " << length; + return false; + } + return true; +} + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *convertToCentral(const CoPrtCnvRadioTelegram *a_radioTelegram) +{ + auto tab = convertToTabTele(a_radioTelegram); + if (!tab) + return nullptr; + auto ret = toCentral(tab); + delete tab; + return ret; +} + +TrainingAreaTelegram *convertToTabTele(const CoPrtCnvRadioTelegram *a_radioTelegram) +{ + switch (a_radioTelegram->getTelID()) + { + case GEF_MANIPULATIONSMELDUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 12)) + return nullptr; + + auto tele = new ManipulationReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->isManipulation = a_radioTelegram->getPayloadDataUInt32(7, 1); + tele->equipmentFunctionId = a_radioTelegram->getPayloadDataUInt32(8, 1); + + + + + return tele; + } + + case GEF_BITE_MELDUNG2: + { + + if (!isPayloadLengthOk(a_radioTelegram, 27, 19, 7)) + return nullptr; + + auto tele = new BiteReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->loginType = static_cast(a_radioTelegram->getPayloadDataUInt8(7)); + + uint32_t ergebnisCAN = a_radioTelegram->getPayloadDataUInt32(8, 3); + tele->biteState = ergebnisCAN; + + uint8_t ergebnisAusstattung = a_radioTelegram->getPayloadDataUInt8(11); + tele->batteryState = ergebnisAusstattung; + + const auto nonDynamic = getBiteError(a_radioTelegram, 12); + if (nonDynamic.errorNumber != 0 || nonDynamic.canDeviceNumber != 0 + || nonDynamic.subdeviceNumber != 0 || nonDynamic.uniqueId != 0) + tele->biteErrors.push_back(nonDynamic); + + const uint8_t fehlerLen = a_radioTelegram->getPayloadDataUInt8(19); + tele->biteErrors.reserve(tele->biteErrors.size() + fehlerLen); + for (uint8_t i = 0; i < fehlerLen; ++i) + { + const uint8_t iPos = 27 + i * 7; + tele->biteErrors.push_back(getBiteError(a_radioTelegram, iPos)); + } + a_radioTelegram->getPayloadDataUInt32(20, 3); + + tele->configError = a_radioTelegram->getPayloadDataUInt8(23); + uint32_t aktuelleKonfiguration = a_radioTelegram->getPayloadDataUInt32(24, 3); + tele->configState = aktuelleKonfiguration; + return tele; + } + + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 18)) + return nullptr; + + auto tele = new EquipmentGearEvent; + tele->header = getHeader(a_radioTelegram, 3); + tele->charge.gearSerialNumber = a_radioTelegram->getPayloadDataUInt32(7, 4); + tele->charge.gearTasCode = a_radioTelegram->getPayloadDataUInt8(11); + tele->charge.chargeTypeId = a_radioTelegram->getPayloadDataUInt32(12, 2); + tele->chargeAmount = a_radioTelegram->getPayloadDataUInt32(14, 2); + const short remain = a_radioTelegram->getPayloadDataUInt32(16, 2); + tele->charge.remain = remain; + return tele; + } + + case GEF_SW_VERSIONSMELDUNG: + { + + if (!isPayloadLengthOk(a_radioTelegram, 8, 7, 8)) + return nullptr; + + auto tele = new ParticipantSwVersions; + tele->header = getHeader(a_radioTelegram, 3); + + const uint8_t versionsliste_len = a_radioTelegram->getPayloadDataUInt8(7); + tele->equipments.reserve(versionsliste_len); + for (uint32_t i = 0; i < versionsliste_len; i++) + { + const uint8_t iPos = 8 + i * 8; + EquipmentSwVersion ver; + ver.equipmentFunctionId = a_radioTelegram->getPayloadDataUInt8(iPos); + ver.subDeviceId = a_radioTelegram->getPayloadDataUInt8(iPos + 1); + ver.uniqueId = a_radioTelegram->getPayloadDataUInt32(iPos + 2, 4); + ver.swVersion = a_radioTelegram->getPayloadDataUInt32(iPos + 6, 2); + } + return tele; + } + + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 19)) + return nullptr; + + auto tele = new SanitationRepair; + tele->header = getHeader(a_radioTelegram, 3); + tele->originatorType = static_cast( + a_radioTelegram->getPayloadDataUInt8(7)); + tele->equipmentNumberOrigin = a_radioTelegram->getPayloadDataUInt32(8, 2); + tele->stateStart = static_cast( + a_radioTelegram->getPayloadDataUInt8(10)); + unsigned int bitfield1 = a_radioTelegram->getPayloadDataUInt8(11); + tele->typeOfTreatment = bitfield1 & 0x7F; + tele->triage = (bitfield1 & 0x80) >> 7; + tele->tyeOfDamage = a_radioTelegram->getPayloadDataUInt8(12); + unsigned int bitfield2 = a_radioTelegram->getPayloadDataUInt8(13); + tele->stateResult = static_cast( + bitfield2 & 0x0F); + tele->treatmentResult + = static_cast( + (bitfield2 & 0x30) >> 4); + tele->triagePriority = ((bitfield2 & 0xC0) >> 6); + tele->fullState = a_radioTelegram->getPayloadDataUInt8(14); + tele->timeOfTreatment = a_radioTelegram->getPayloadDataUInt32(15, 2); + tele->timeOfRecovery = a_radioTelegram->getPayloadDataUInt32(17, 2); + return tele; + } + + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + { + if (!isPayloadLengthOk(a_radioTelegram, 15, 14, 1)) + return nullptr; + + auto tele = new SanitaryMaterialStockReport; + tele->header = getHeader(a_radioTelegram, 3); + + tele->uniqueId = a_radioTelegram->getPayloadDataUInt32(7, 4); + tele->originatorEquipmentNumber = a_radioTelegram->getPayloadDataUInt32(11, 2); + tele->qualification = static_cast(a_radioTelegram->getPayloadDataUInt8(13)); + + const uint16_t sanitaryMaterialCount = a_radioTelegram->getPayloadDataUInt8(14); + + tele->sanitaryMaterialCount = sanitaryMaterialCount; + double size = sanitaryMaterialCount; + + + if (tele->sanitaryMaterialCount != 0) + { + int pos = 15; + std::vector stock; + stock.reserve(sanitaryMaterialCount); + for (int i = 0; i < size; i++) + { + + unsigned int in = a_radioTelegram->getPayloadDataUInt8(pos++); + stock.emplace_back(in); + } + + tele->sanitaryMaterialStock = stock; + } + else + tele->sanitaryMaterialStock = std::vector(); + return tele; + } + + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + { + if (!isPayloadLengthOk(a_radioTelegram, 23)) + return nullptr; + auto tele = new Sanitation; + tele->header = getHeader(a_radioTelegram, 3); + + qint64 proceduresP1 = a_radioTelegram->getPayloadDataUInt32(7, 4); + qint64 proceduresP2 = a_radioTelegram->getPayloadDataUInt32(11, 4); + + tele->proceduresTaken = (proceduresP1 << 32) + proceduresP2; + + tele->uniqeId = a_radioTelegram->getPayloadDataUInt32(15, 4); + tele->originatorEquipmentNumber = a_radioTelegram->getPayloadDataUInt32(19, 2); + tele->qualification = static_cast(a_radioTelegram->getPayloadDataUInt8(21)); + quint8 enumByte = a_radioTelegram->getPayloadDataUInt8(22); + tele->sanitationEvaluation = static_cast((enumByte & 0xc0) >> 6); + tele->sanitationResult = static_cast(enumByte & 0x3f); + return tele; + } + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 9)) + return nullptr; + + auto tele = new EquipmentOperationalState; + tele->header = getHeader(a_radioTelegram, 3); + + + + + + + + uint8_t abcSchutz = a_radioTelegram->getPayloadDataUInt8(8); + + tele->nbcProtectionActive = checkBitmask(abcSchutz, 0x40); + return tele; + } + case GEF_FEHLERMELDUNG_GFD: + { + if (!isPayloadLengthOk(a_radioTelegram, 9)) + return nullptr; + + auto tele = new CtaDataError; + tele->header = getHeader(a_radioTelegram, 3); + tele->reason = static_cast(a_radioTelegram->getPayloadDataUInt8(7)); + tele->originTelegramId = a_radioTelegram->getPayloadDataUInt8(8); + return tele; + } + case GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT: + { + if (!isPayloadLengthOk(a_radioTelegram, 31)) + return nullptr; + + auto tele = new RestoreRadioReadiness; + + tele->header = getHeader(a_radioTelegram, 3); + tele->readinessLossPosition = getRelativePosition(a_radioTelegram, 7); + tele->readinessLossTime = a_radioTelegram->getPayloadDataUInt32(13, 4); + tele->readinessRestorePosition = getRelativePosition(a_radioTelegram, 17); + tele->readinessRestoreTime = a_radioTelegram->getPayloadDataUInt32(23, 4); + + return tele; + } + case GEF_POSITIONS_MELDUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 14)) + return nullptr; + + auto tele = new PositionReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->gpsQuality = getGpsQuality(a_radioTelegram, 13); + return tele; + } + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + { + + if (!isPayloadLengthOk(a_radioTelegram, 15, 14, 2)) + return nullptr; + + auto tele = new PositionReportWithMountedEquipments; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + const uint8_t gps = a_radioTelegram->getPayloadDataUInt8(13); + tele->gpsQuality.moreThan4SatellitesAvailable = ((gps & 0x80) == 0x80); + tele->gpsQuality.dgpsModeAvailable = ((gps & 0x40) == 0x40); + tele->gpsQuality.pdopValue = (gps & 0x3f); + + const uint8_t aufgesessene_teilnehmer_len = a_radioTelegram->getPayloadDataUInt8(14); + tele->mountedEquipments.reserve(aufgesessene_teilnehmer_len); + + for (uint8_t i = 0; i < aufgesessene_teilnehmer_len; i++) + { + int eqId = a_radioTelegram->getPayloadDataUInt32(15 + 2 * i, 2); + tele->mountedEquipments.push_back(eqId); + } + return tele; + } + + + case GEF_DEAKTIVIERUNG_EINZELMINE: + { + if (!isPayloadLengthOk(a_radioTelegram, 13)) + return nullptr; + + auto tele = new MineTriggered; + tele->header = getHeader(a_radioTelegram, 5); + tele->mineAreaId = a_radioTelegram->getPayloadDataUInt32(9, 2); + tele->mineIndex = a_radioTelegram->getPayloadDataUInt32(11, 2); + return tele; + } + case GEF_DEFINITION_IED: + { + if (!isPayloadLengthOk(a_radioTelegram, 24)) + return nullptr; + + auto tele = new DefinitionIed; + tele->header = getHeader(a_radioTelegram, 3); + tele->iedId = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->iedType = static_cast(a_radioTelegram->getPayloadDataUInt8(9)); + tele->trigger = a_radioTelegram->getPayloadDataUInt8(10); + tele->explosiveForce = a_radioTelegram->getPayloadDataUInt8(11); + tele->relPosition = getRelativePosition(a_radioTelegram, 12); + tele->partyId = a_radioTelegram->getPayloadDataUInt8(18); + tele->pairingState = static_cast(a_radioTelegram->getPayloadDataUInt8(19)); + tele->pairedId = a_radioTelegram->getPayloadDataUInt32(20, 2); + tele->tacticalState = static_cast(a_radioTelegram->getPayloadDataUInt8(22)); + tele->statePyrotechnics = a_radioTelegram->getPayloadDataUInt8(23); + + + fixupEnum(IedType::SuicideIed, IedType::IedBigPyro, IedType::SuicideIed, tele->iedType); + fixupEnum(IedPairingState::NotPaired, + IedPairingState::PairedToOps, + IedPairingState::NotPaired, + tele->pairingState); + fixupEnum(IedTacticalState::NotActive, + IedTacticalState::TriggeredByControlDevice, + IedTacticalState::Unknown, + tele->tacticalState); + return tele; + } + case GEF_ZUSTAND_IED: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new StateIed; + tele->header = getHeader(a_radioTelegram, 3); + tele->iedId = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->tacticalState = static_cast(a_radioTelegram->getPayloadDataUInt8(9)); + tele->statePyrotechnics = a_radioTelegram->getPayloadDataUInt8(10); + tele->batteryWarnings = a_radioTelegram->getPayloadDataUInt8(11); + tele->errorStateElectronics = static_cast(a_radioTelegram->getPayloadDataUInt8(12)); + tele->errorStatePyrotechnics1 = static_cast(a_radioTelegram->getPayloadDataUInt8(13)); + tele->errorStatePyrotechnics2 = static_cast(a_radioTelegram->getPayloadDataUInt8(14)); + tele->errorStatePyrotechnics3 = static_cast(a_radioTelegram->getPayloadDataUInt8(15)); + + + fixupEnum(IedTacticalState::NotActive, + IedTacticalState::TriggeredByControlDevice, + IedTacticalState::Unknown, + tele->tacticalState); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStateElectronics); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStatePyrotechnics1); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStatePyrotechnics2); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStatePyrotechnics3); + return tele; + } + case GEF_STATUS_EINZELMINENSIMULATOR: + { + if (!isPayloadLengthOk(a_radioTelegram, 17)) + return nullptr; + + auto tele = new DusSingleMineState; + tele->header = getHeader(a_radioTelegram, 3); + tele->mineId = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->relPosition = getRelativePosition(a_radioTelegram, 9); + tele->chargeTypeId = a_radioTelegram->getPayloadDataUInt8(15); + tele->state = a_radioTelegram->getPayloadDataUInt8(16); + tele->effectStart = tele->header.timeStamp; + return tele; + } + case GEF_TREFFER_EREIGNIS_DUS: + { + if (!isPayloadLengthOk(a_radioTelegram, 23)) + return nullptr; + + auto tele = new StateChangeDirect; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + getTaktZustand(a_radioTelegram, 13, tele); + tele->chargeTypeId = a_radioTelegram->getPayloadDataUInt32(19, 2); + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(21, 2); + return tele; + } + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + { + if (!isPayloadLengthOk(a_radioTelegram, 22)) + return nullptr; + + auto tele = new StateChangeIndirect; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + getTaktZustand(a_radioTelegram, 13, tele); + + + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(20, 2); + return tele; + } + case GEF_SCHIEDSRICHTEREINGRIFF: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new OperatorAction; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->action = a_radioTelegram->getPayloadDataUInt8(13); + tele->operatorId = a_radioTelegram->getPayloadDataUInt32(14, 2); + return tele; + } + case GEF_TREFFER_EREIGNIS_DUS_IPS: + { + + if (!isPayloadLengthOk(a_radioTelegram, 18, 17, 2)) + return nullptr; + + auto tele = new StateChangeDirect; + tele->header = getHeader(a_radioTelegram, 3); + getTaktZustand(a_radioTelegram, 7, tele); + tele->chargeTypeId = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(15, 2); + + size_t iPos = 17; + tele->opsPosition = getOpsPosition(a_radioTelegram, iPos); + return tele; + } + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: + { + + if (!isPayloadLengthOk(a_radioTelegram, 17, 16, 2)) + return nullptr; + + auto tele = new StateChangeIndirect; + tele->header = getHeader(a_radioTelegram, 3); + getTaktZustand(a_radioTelegram, 7, tele); + + + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(14, 2); + size_t iPos = 16; + tele->opsPosition = getOpsPosition(a_radioTelegram, iPos); + tele->isSecondaryEffect = true; + return tele; + } + case GEF_TAKTISCHER_STATUS: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new StateChange; + tele->header = getHeader(a_radioTelegram, 3); + getTaktZustand(a_radioTelegram, 7, tele); + + tele->originatorType = static_cast( + a_radioTelegram->getPayloadDataUInt8(13)); + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(14, 2); + return tele; + } + + case GEF_EINTRETEN_FUNKTIONSRAUM: + { + if (!isPayloadLengthOk(a_radioTelegram, 15)) + return nullptr; + + auto tele = new FunctionalAreaEntry; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->aesDdsId = a_radioTelegram->getPayloadDataUInt32(13, 2); + return tele; + } + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + { + if (!isPayloadLengthOk(a_radioTelegram, 9)) + return nullptr; + + auto tele = new SpecialSensorData; + tele->header = getHeader(a_radioTelegram, 3); + getSpecialSensorData(a_radioTelegram, 7, tele); + return tele; + } + case GEF_SONDERSENSORIK_FAHRSPUR: + { + if (!isPayloadLengthOk(a_radioTelegram, 15)) + return nullptr; + + auto tele = new SpecialSensorData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + getSpecialSensorData(a_radioTelegram, 13, tele); + return tele; + } + case GEF_SONDERSENSORIK_DATEN: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new SpecialSensorData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->type = a_radioTelegram->getPayloadDataUInt32(13, 1); + getSpecialSensorData(a_radioTelegram, 14, tele); + tele->nbcType = a_radioTelegram->getPayloadDataUInt32(16, 1); + return tele; + } + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + { + if (!isPayloadLengthOk(a_radioTelegram, 24)) + return nullptr; + + auto tele = new MinelayerTrailerData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->barrierId = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->layingDensity = a_radioTelegram->getPayloadDataUInt32(15, 1); + tele->effectStart = a_radioTelegram->getPayloadDataUInt32(16, 4) * 1000LL; + tele->effectDuration = a_radioTelegram->getPayloadDataUInt32(20, 1); + tele->indirectChargeTasCode = a_radioTelegram->getPayloadDataUInt32(21, 1); + tele->mineCount = a_radioTelegram->getPayloadDataUInt32(22, 2); + return tele; + } + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + { + if (!isPayloadLengthOk(a_radioTelegram, 25)) + return nullptr; + + auto tele = new MinelayerThrowerData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->barrierId = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->layingDensity = a_radioTelegram->getPayloadDataUInt32(15, 1); + tele->effectStart = a_radioTelegram->getPayloadDataUInt32(16, 4) * 1000LL; + tele->effectDuration = a_radioTelegram->getPayloadDataUInt32(20, 1); + tele->indirectChargeTasCode = a_radioTelegram->getPayloadDataUInt32(21, 1); + tele->throwingType = static_cast( + a_radioTelegram->getPayloadDataUInt32(22, 2)); + tele->mineCount = a_radioTelegram->getPayloadDataUInt32(23, 2); + return tele; + } + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new MinelayerTrailerPosition; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->dusSerialNo = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->indirectChargeTasCode = a_radioTelegram->getPayloadDataUInt32(15, 1); + return tele; + } + case GEF_DATENVERKEHR_SRT_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 7)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->payloadType = OpaquePayloadDataBase::Type::OC; + tele->payload = getPayload(a_radioTelegram, 7); + return tele; + } + case GEF_DATENVERKEHR_DMF_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 7)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->payloadType = OpaquePayloadDataBase::Type::FireSmokeMarker; + tele->payload = getPayload(a_radioTelegram, 7); + return tele; + } + case GEF_DATENVERKEHR_GEOP_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 14)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->gpsQuality = getGpsQuality(a_radioTelegram, 13); + tele->payloadType = OpaquePayloadDataBase::Type::Geopairing; + tele->payload = getPayload(a_radioTelegram, 14, 15); + return tele; + } + case GEF_DATENVERKEHR_TGTC_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 7)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->payloadType = OpaquePayloadDataBase::Type::Target; + tele->payload = getPayload(a_radioTelegram, 7, 8); + return tele; + } + case GEF_GERAETEEREIGNIS: + { + if (!isPayloadLengthOk(a_radioTelegram, 24)) + return nullptr; + + auto tele = new EquipmentEvent; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->equipmentFunctionId = a_radioTelegram->getPayloadDataUInt8(13); + tele->subDeviceId = a_radioTelegram->getPayloadDataUInt8(14); + tele->uniqueId = a_radioTelegram->getPayloadDataUInt32(15, 4); + tele->code = a_radioTelegram->getPayloadDataUInt8(23); + tele->payload = getPayload(a_radioTelegram, 24, 25); + return tele; + } + + case GEF_WAFFENZUORDNUNG: + { + + if (!isPayloadLengthOk(a_radioTelegram, 8, 7, 6)) + return nullptr; + + auto tele = new EquipmentGearAssignment; + tele->header = getHeader(a_radioTelegram, 3); + + const uint8_t waffen_len = a_radioTelegram->getPayloadDataUInt8(7); + tele->gears.reserve(waffen_len); + for (uint32_t i = 0; i < waffen_len && i < 10; i++) + { + const uint8_t iPos = 8 + i * 6; + + Gear gear; + gear.gearSerialNumber = a_radioTelegram->getPayloadDataUInt32(iPos, 4); + gear.gearTasCode = a_radioTelegram->getPayloadDataUInt8(iPos + 4); + gear.chargeCounting = a_radioTelegram->getPayloadDataUInt8(iPos + 5) != 0; + tele->gears.push_back(std::move(gear)); + } + return tele; + } + case GEF_IPS_POSITIONSDATEN: + { + + if (!isPayloadLengthOk(a_radioTelegram, 8, 7, 2)) + return nullptr; + + auto tele = new PositionReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->header.timeStamp + += 1; + size_t iPos = 7; + tele->opsPosition = getOpsPosition(a_radioTelegram, iPos); + if (tele->opsPosition.opsId == -1) + { + delete tele; + tele = nullptr; + } + return tele; + } + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + { + + constexpr int varSize = 5; + + if (!isPayloadLengthOk(a_radioTelegram, 13, 12, varSize)) + return nullptr; + + auto tele = new EquipmentGearChargeState; + tele->header = getHeader(a_radioTelegram, 3); + GearCharge gc; + gc.gearSerialNumber = a_radioTelegram->getPayloadDataUInt32(7, 4); + gc.gearTasCode = a_radioTelegram->getPayloadDataUInt8(11); + const uint8_t munitionsliste_len = a_radioTelegram->getPayloadDataUInt8(12); + tele->charges.reserve(munitionsliste_len); + for (uint32_t i = 0; i < munitionsliste_len; i++) + { + int iPos = 13; + const int offset = 5 * i; + gc.location = a_radioTelegram->getPayloadDataUInt8(iPos + offset); + iPos++; + short munitionsmenge = a_radioTelegram + ->getPayloadDataUInt32(iPos + offset, + 2); + iPos += 2; + gc.remain = munitionsmenge < 0 ? -1 : munitionsmenge; + gc.chargeTypeId = a_radioTelegram->getPayloadDataUInt32(iPos + offset, 2); + tele->charges.push_back(gc); + } + return tele; + } + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 13)) + return nullptr; + + auto tele = new CesHitRequest; + tele->header = getHeader(a_radioTelegram, 3); + tele->chargeTasCodeDirect = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->aesDdsId = a_radioTelegram->getPayloadDataUInt32(9, 2); + tele->aesType = static_cast(a_radioTelegram->getPayloadDataUInt8(11)); + tele->remainEffectTasCodeDirect = a_radioTelegram->getPayloadDataUInt8(12); + return tele; + } + case GEF_TEILNEHMERMODE_MELDUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 15)) + return nullptr; + + auto tele = new ParticipantModeReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->language = static_cast(a_radioTelegram->getPayloadDataUInt8(7)); + tele->operationMode = static_cast( + a_radioTelegram->getPayloadDataUInt8(8)); + tele->reactivationDetoxication = a_radioTelegram->getPayloadDataUInt8(9) + * 10; + tele->reactivationMaintenance = a_radioTelegram->getPayloadDataUInt8(10) + * 10; + tele->reactivationMedic = a_radioTelegram->getPayloadDataUInt8(11) * 10; + unsigned char wph_mode = a_radioTelegram->getPayloadDataUInt8(12); + tele->modeHelmet = static_cast(wph_mode & 0x03); + tele->modeVest = static_cast((wph_mode >> 2) & 0x03); + tele->personellProtectionMode = static_cast((wph_mode >> 4) & 0x07); + + unsigned char protection_mode = a_radioTelegram->getPayloadDataUInt8(13); + tele->protectionLevel = static_cast(protection_mode & 0x06); + tele->abcProtectionMode = static_cast((protection_mode >> 3) & 0x03); + + unsigned char specialFunction = a_radioTelegram->getPayloadDataUInt8( + 14); + tele->handgrenadeSearchMode = static_cast( + specialFunction & 0b11); + tele->internationalMode = static_cast( + (specialFunction >> 2) & 0b11); + return tele; + } + case GEF_TEILNEHMER_KONFIG_ANTWORT: + { + if (!isPayloadLengthOk(a_radioTelegram, 27)) + return nullptr; + + auto tele = new ParticipantConfigurationReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->positionIntervallVehicle = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->positionIntervallPersonell = a_radioTelegram->getPayloadDataUInt32(9, 2); + tele->positionIntervallAircraft = a_radioTelegram->getPayloadDataUInt32(11, 2); + tele->positionTransmissionIntervall = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->heightbarrier = a_radioTelegram->getPayloadDataUInt32(15, 2); + unsigned char tmp = a_radioTelegram->getPayloadDataUInt8(17); + tele->faultPositionHandling = static_cast( + (tmp >> 6) & 0x03); + tele->switchingPositionIntervall + = static_cast( + tmp & 0x03); + tele->waittimeAdditionalBroadcastDemand = a_radioTelegram->getPayloadDataUInt32(18, 2); + tele->factorWaittimeIncreaseAtHighload = a_radioTelegram->getPayloadDataUInt8(20); + tele->waittimeAutomaticVulnerabilityIncreaseLevel1 = a_radioTelegram->getPayloadDataUInt8(21); + tele->waittimeAutomaticVulnerabilityIncreaseLevel2 = a_radioTelegram->getPayloadDataUInt8(22); + tele->waittimeAutomaticVulnerabilityIncreaseLevel3 = a_radioTelegram->getPayloadDataUInt8(23); + tele->opticalCode = static_cast( + a_radioTelegram->getPayloadDataUInt8(24)); + tele->vulnerabilityModel = a_radioTelegram->getPayloadDataUInt8(25); + tele->validTimeOps = a_radioTelegram->getPayloadDataUInt8(26); + return tele; + } + case GEF_ESW_MELDUNG: + + return nullptr; + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + { + if (!isPayloadLengthOk(a_radioTelegram, 10)) + return nullptr; + + auto tele = new RequestBroadcastTelegrams; + tele->header = getHeader(a_radioTelegram, 3); + tele->resetCounter = a_radioTelegram->getPayloadDataUInt8(7); + tele->broadcastIndex = a_radioTelegram->getPayloadDataUInt32(8, 2); + return tele; + } + case GEF_LASER_TARGET_DESIGNATOR_UPDATE: + { + auto tele = new ApacheLaserDesignation; + + tele->header = getHeader(a_radioTelegram, 3); + tele->code = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->outputPower = a_radioTelegram->getPayloadDataUInt8(9); + tele->gearId = a_radioTelegram->getPayloadDataUInt32(10, 4); + + return tele; + } + default: + { + ERROR_LOG(logger()) << "Conversion of Radio-Telegram to Central-Telegram with telId=" + << a_radioTelegram->getTelID() << " not implemented."; + } + } + return nullptr; +} + +} + +} diff --git a/TetraIF/CoPrtCnv/tetra_telegram_ids.h b/TetraIF/CoPrtCnv/tetra_telegram_ids.h new file mode 100644 index 000000000..f2a03acf8 --- /dev/null +++ b/TetraIF/CoPrtCnv/tetra_telegram_ids.h @@ -0,0 +1,116 @@ + + + +#pragma once + +enum gef_telegramm_id_et +{ + GEF_BESTAETIGUNG = 0, + + GEF_INIT = 1, + GEF_MANIPULATIONSMELDUNG = 2, + GEF_UMGEBUNGS_MELDUNG2 = 203, + GEF_AUFFORDERUNG_BITE_MELDUNG = 4, + GEF_BITE_MELDUNG2 = 205, + + GEF_LIZENSIERUNG_TNE = 6, + GEF_BETRIEBSZUSTAND_AUSSTATTUNG = 7, + GEF_KONFIGURATION_WIRKMODELL = 9, + GEF_ANFORDERUNG_KONFIGURATIONSDATEN = 10, + GEF_KONFIGURATIONSMELDUNG = 11, + GEF_FEHLERMELDUNG_GFD = 12, + GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT = 13, + + GEF_POSITIONS_MELDUNG = 21, + GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER = 22, + GEF_POSITIONS_MELDUNG_LFZ = 23, + GEF_IPS_POSITIONSDATEN = 201, + + GEF_SCHIEDSRICHTERKOMMANDO = 25, + + GEF_WIRKFELD_EINZELGESCHOSS = 31, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER = 32, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP = 33, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN = 34, + GEF_WIRKFELD_MINENSPERRE = 35, + GEF_WIRKFELD_STATUS_MINENSPERRE = 36, + GEF_WIRKFELD_A_KAMPFMITTEL = 37, + GEF_WIRKFELD_C_KAMPFMITTEL = 38, + GEF_DEAKTIVIERUNG_WIRKFELD = 39, + GEF_WIRKFELD_AENDERUNG_BEZEICHNER = 40, + GEF_DEAKTIVIERUNG_EINZELMINE = 41, + GEF_REAKTIVIERUNG_DUS_MINE = 42, + GEF_DEFINITION_IED = 43, + GEF_ZUSTAND_IED = 44, + GEF_STATUS_EINZELMINENSIMULATOR = 45, + GEF_WIRKFELD_EINZELMINENSIMULATOR = 46, + GEF_SELEKTIVE_AUFMUNITIONIERUNG = 56, + + GEF_TREFFER_EREIGNIS_DUS = 52, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION = 53, + GEF_TREFFER_AUSLOESUNG = 54, + GEF_SCHIEDSRICHTEREINGRIFF = 55, + + GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG = 218, + GEF_TREFFER_EREIGNIS_DUS_IPS = 228, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS = 229, + + GEF_TAKTISCHER_STATUS = 61, + GEF_FUNKTIONSRAUM = 62, + GEF_EINTRETEN_FUNKTIONSRAUM = 63, + GEF_DEAKTIVIEREN_FUNKTIONSRAUM = 64, + + GEF_DATENVERKEHR_SRT_TDS = 71, + GEF_DATENVERKEHR_TDS_SRT = 72, + GEF_DATENVERKEHR_DMF_TDS = 73, + GEF_DATENVERKEHR_TDS_DMF = 74, + + GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME = 82, + GEF_NOP = 83, + + GEF_SONDERSENSORIK_BETRIEBSZUSTAND = 91, + GEF_SONDERSENSORIK_FAHRSPUR = 92, + GEF_SONDERSENSORIK_DATEN = 93, + GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN = 95, + GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN = 96, + GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION = 97, + + GEF_SPRACHAUSWAHL = 101, + GEF_ALLGEMEINE_NACHRICHT = 102, + GEF_ECHO_ON_OFF = 103, + GEF_ESW_MELDUNG = 104, + + GEF_WF_SAMMELDEAKTIVIERUNG = 105, + GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN = 106, + GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM = 107, + + GEF_DATENVERKEHR_GEOP_TDS = 181, + GEF_DATENVERKEHR_TDS_GEOP = 182, + + GEF_DATENVERKEHR_TGTC_TDS = 183, + GEF_DATENVERKEHR_TDS_TGTC = 184, + GEF_GERAETEEREIGNIS = 185, + + GEF_WAFFENZUORDNUNG = 200, + GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE = 202, + GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG = 210, + GEF_AUSLOESUNG_DUS_TREFFER = 211, + GEF_ANFORDERUNG_SW_VERSION = 212, + GEF_SW_VERSIONSMELDUNG = 213, + GEF_TECHNIK_FUNKTIONSRAUM = 219, + + GEF_TEILNEHMERMODE_SETZEN = 230, + GEF_TEILNEHMERMODE_MELDUNG = 231, + GEF_TEILNEHMERMODE_ANFORDERN = 232, + GEF_TEILNEHMER_KONFIG_ANTWORT = 233, + GEF_TEILNEHMER_KONFIG_SETZEN = 234, + GEF_TEILNEHMER_KONFIG_ANFORDERN = 235, + + GEF_SANITAETSDIENST_INSTANDSETZUNG = 240, + GEF_BESTANDSMELDUNG_SANITAETSMATERIAL = 241, + GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN = 242, + + GEF_LASER_TARGET_DESIGNATOR_UPDATE = 214, + + GEF_GEFECHTSFELDTELEGRAMM = 300 +}; diff --git a/TetraIF/LogView/CMakeLists.txt b/TetraIF/LogView/CMakeLists.txt new file mode 100644 index 000000000..bd3ee7067 --- /dev/null +++ b/TetraIF/LogView/CMakeLists.txt @@ -0,0 +1,104 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# +ADD_SUBDIRECTORY(Console) +SET(my_SRCS + IntegerCalculator.cpp + IntegerCalculator.hpp + logger.cpp + logger.h + LogViewBooleanEdit.cpp + LogViewBooleanEdit.hpp + LogViewDateTimeEdit.cpp + LogViewDateTimeEdit.hpp + LogViewEnumEdit.cpp + LogViewEnumEdit.hpp + LogViewField.cpp + LogViewField.hpp + LogViewGui.cpp + LogViewGui.hpp + LogViewInjectionThread.cpp + LogViewInjectionThread.hpp + LogViewMain.cpp + LogViewModels.cpp + LogViewModels.hpp + LogViewOptionDialog.cpp + LogViewOptionDialog.hpp + LogViewSpinBox.cpp + LogViewSpinBox.hpp + LogViewTableWidget.cpp + LogViewTableWidget.hpp + LogViewTabWidget.cpp + LogViewTabWidget.hpp + LogViewTelegram.cpp + LogViewTelegramDialog.cpp + LogViewTelegramDialog.hpp + LogViewTelegramEdit.cpp + LogViewTelegramEdit.hpp + LogViewTelegramEditModel.cpp + LogViewTelegramEditModel.hpp + LogViewTelegram.hpp + LogViewTelegramSelectionDialog.cpp + LogViewTelegramSelectionDialog.hpp + LogViewTetraTelegramsParser.cpp + LogViewTetraTelegramsParser.hpp + LogViewTextEdit.cpp + LogViewTextEdit.hpp + LogViewValueEdit.cpp + LogViewValueEdit.hpp + LogViewWidget.cpp + LogViewWidget.hpp + LogViewXdrElement.cpp + LogViewXdrElement.hpp + LogViewXdrParser.cpp + LogViewXdrParser.hpp + LogViewXdrStandardType.cpp + LogViewXdrStandardType.hpp + LogViewXdrStruct.cpp + LogViewXdrStruct.hpp + LogViewXdrType.cpp + LogViewXdrType.hpp + LogViewXdrValue.cpp + LogViewXdrValue.hpp + zsksxd_tetraForLogView.x +) + +QT5_ADD_RESOURCES(my_SRCS LogViewResources.qrc) +NGL_ADD_TOOL_ICON(my_SRCS) +NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION LogView ${my_SRCS}) + +NGL_TARGET_LINK_LIBRARIES(LogView + Qt5::Core + Qt5::Gui + Qt5::Network + CoPrtCnv + nglwidgets + NGLLogger + nglapplication + ngltools +) +NGL_INSTALL_TARGET(LogView) +NGL_INSTALL(AAR SV FILES LogView_log4cxx.props DESTINATION bin) + + + +# install on RPM build and copy for local builds so that LogView automatically finds the zsksxd_tetraForLogView.x file +if (BUILD_RPM) + add_custom_target(zsksxd_tetraForLogView.x_bin) # empty target so that LogView still builds on RPM build + NGL_INSTALL(AAR SV FILES zsksxd_tetraForLogView.x DESTINATION bin) +else() + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zsksxd_tetraForLogView.x ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/zsksxd_tetraForLogView.x + COMMENT "[Local build] Copy zsksxd_tetraForLogView.x for LogView into bin/" + ) + add_custom_target(zsksxd_tetraForLogView.x_bin DEPENDS ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x) +endif() + +if (TARGET LogView) + add_dependencies(LogView zsksxd_tetraForLogView.x_bin training_area_telegrams.h_bin) +endif() + diff --git a/TetraIF/LogView/Console/CMakeLists.txt b/TetraIF/LogView/Console/CMakeLists.txt new file mode 100644 index 000000000..a2a9e61f2 --- /dev/null +++ b/TetraIF/LogView/Console/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(console_SRCS + main.cpp +) + +NGL_ADD_TOOL_ICON(console_SRCS) +NGL_ADD_EXECUTABLE(AAR SV LogView_console ${console_SRCS}) +NGL_INSTALL_TARGET(LogView_console) +NGL_TARGET_LINK_LIBRARIES(LogView_console + CoPrtCnv + NGLLogger +) diff --git a/TetraIF/LogView/Console/main.cpp b/TetraIF/LogView/Console/main.cpp new file mode 100644 index 000000000..fcdac2bc6 --- /dev/null +++ b/TetraIF/LogView/Console/main.cpp @@ -0,0 +1,201 @@ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static QSet s_eqIds; +template +bool validEqId(const T &tele) +{ + if (!s_eqIds.isEmpty() && !s_eqIds.contains(tele.header.equipmentNumber)) + return false; + return true; +} + +QByteArray formatTime(quint64 t) +{ + const quint64 secs = t >> 32; + const quint64 usecs = t & 0xFFFFFFFF; + const quint64 msecs = usecs / 1000; + return QDateTime::fromMSecsSinceEpoch(secs * 1000 + msecs).toString(QLatin1String("yy-MM-dd hh:mm:ss.zzz")).toUtf8(); +} + +int main(int argc, char **argv) +{ + using namespace TrainingAreaBase::TetraIcd; + + QCoreApplication app(argc, argv); + + + NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx_tetra.props", false); + + NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()); + + if (app.arguments().count() < 3) + { + ERROR_LOG(logger) << "Usage: " << app.arguments().at(0) + << " "; + return 1; + } + + QFile telegramFile(app.arguments().at(1)); + if (!telegramFile.open(QIODevice::ReadOnly)) + { + ERROR_LOG(logger) << "Error opening " << telegramFile.fileName() + << " for reading: " << telegramFile.errorString(); + return 2; + } + bool bOk; + int telIdToSearch = app.arguments().at(2).toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Error reading telId - not a (valid) number: " + << app.arguments().at(2); + return 3; + } + s_eqIds.clear(); + for (int i = 3; i < app.arguments().size(); ++i) + { + int eqId = app.arguments().at(i).toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Error reading equipId - not a (valid) number: " + << app.arguments().at(i); + return 4; + } + s_eqIds += eqId; + } + + + while (true) + { + + N_CoPrtCnv::CoPrtCnvLogHeader lh; + if (sizeof(lh) == telegramFile.read((char *)&lh, sizeof(lh))) + { + if (lh.m_Version == 3) + { + + qint64 telegramLength = lh.m_Length - sizeof(lh); + QByteArray telegramData(telegramLength, Qt::Uninitialized); + if (telegramLength == telegramFile.read(telegramData.data(), telegramLength)) + { + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol dest = (N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol) + (lh.m_Protocol & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask); + + switch (dest) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + { + const QJsonObject obj = QJsonDocument::fromJson(telegramData).object(); + int telId = obj.value(QStringLiteral("typeId")).toInt(); + if (telIdToSearch != telId) + continue; + + const QJsonObject objData = obj.value(QStringLiteral("data")).toObject(); + + const QByteArray tBA = formatTime(lh.m_Time); + const char *timeStr = tBA.constData(); + + switch (telId) + { + case Constraints::id(): + { + const CreateFunctionalArea tele(CreateFunctionalArea::fromJson(objData)); + if (!validEqId(tele)) + break; + fprintf(stdout, "%s, FUNKTIONSRAUM: '%s', %d, %d\n", + timeStr, + tele.name.c_str(), + tele.aesDdsId, + tele.header.equipmentNumber + ); + break; + } + case Constraints::id(): + { + const DeactivateEffectSimulation tele(DeactivateEffectSimulation::fromJson(objData)); + fprintf(stdout, "%s, DEAKTIVIERUNG_WIRKFELD: typ: %d - kennung: %d\n", + timeStr, + int(tele.aesType), + tele.aesDdsId + ); + break; + } + case Constraints::id(): + { + const PositionReport tele(PositionReport::fromJson(objData)); + if (!validEqId(tele)) + break; + if (tele.opsPosition.opsId == 0) + break; + fprintf(stdout, "%s, IPS_POSITIONSDATEN: %d - OPS: %d\n", + timeStr, + tele.header.equipmentNumber, + tele.opsPosition.opsId + ); + break; + } + case BESTAETIGUNG: + case UMGEBUNGS_MELDUNG2: + break; + default: + fprintf(stderr, "Printing telegram with id %d not implemented\n", telId); + break; + + } + break; + } + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: + { + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(telegramData); + gef_telegramm_id_et telId = radioTelegram.getTelID(); + if (telId == GEF_UMGEBUNGS_MELDUNG2) + { + const QByteArray tBA = formatTime(lh.m_Time); + const char *timeStr = tBA.constData(); + static uint16_t bci = 0xFFFF; + if (bci != radioTelegram.getBroadcastIndex()) + { + if (bci > radioTelegram.getBroadcastIndex() && bci != 0xFFFF) + { + fprintf(stdout, "BCI reset in %s at %s!\n", + qPrintable(telegramFile.fileName()), + timeStr); + } + fprintf(stdout, "BCI: %d\n", radioTelegram.getBroadcastIndex()); + bci = radioTelegram.getBroadcastIndex(); + } + } + break; + } + default: + break; + } + } + } + else + { + ERROR_LOG(logger) << "Wrong LogHeader version: " << lh.m_Version; + return 4; + } + } + else + break; + } + return 0; +} diff --git a/TetraIF/LogView/IntegerCalculator.cpp b/TetraIF/LogView/IntegerCalculator.cpp new file mode 100644 index 000000000..a31e417e0 --- /dev/null +++ b/TetraIF/LogView/IntegerCalculator.cpp @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + +#include "IntegerCalculator.hpp" + +#include +#include + +namespace N_SST +{ +IntegerCalculator::IntegerCalculator() + : m_OperationList({{"*", 6},{"/", 6},{"%", 6},{"+", 5},{"-", 5},{"<<", 4},{">>", 4}}) + , m_AdditionalErrorText() + , m_ParanthesisCount(0) + , m_Error(IntegerCalculator::e_Ok) +{ +} + + + + + + + + +int64_t IntegerCalculator::calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText) +{ + std::string calcText = a_calcText; + + for (auto iter = m_OperationList.begin(); iter != m_OperationList.end(); ++iter) + replace(calcText, iter->first, " "+iter->first+" "); + + + replace(calcText, "(", " ( "); + replace(calcText, ")", " ) "); + + + + m_ParanthesisCount = 0; + m_Error = e_Ok; + m_AdditionalErrorText = ""; + size_t pos = 0; + bool dummy; + int64_t value = calc(calcText, pos, dummy, "", 0, "+"); + + + + if (m_Error == e_Ok) + { + if (m_ParanthesisCount > 0) + { + m_Error = e_MissingRightParanthesis; + } + else if (m_ParanthesisCount < 0) + { + m_Error = e_MissingLeftParanthesis; + } + else if (pos != calcText.length()) + { + m_Error = e_UnknownError; + } + } + + + a_error = m_Error; + if (a_error != e_Ok) + { + value = 0; + if (a_addErrorText) + { + *a_addErrorText = m_AdditionalErrorText; + } + } + return value; +} + + + + +void IntegerCalculator::addVariable(const std::string& a_name, const int64_t a_value) +{ + std::map::iterator iter = m_VariableList.find(a_name); + if (iter != m_VariableList.end()) + removeVariable(a_name); + m_VariableList.insert(std::make_pair(a_name, a_value)); +} + + + + + +void IntegerCalculator::removeVariable(const std::string& a_name) +{ + std::map::iterator iter = m_VariableList.find(a_name); + if (iter != m_VariableList.end()) + m_VariableList.erase(iter); +} + + + + + +int64_t IntegerCalculator::calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis, + const std::string& a_prevOp, const int64_t a_prevValue, + const std::string& a_initOp) +{ + std::string operation = a_initOp; + int64_t value1 = a_prevValue; + bool isNegative = false; + std::string calcText = a_calcText; + a_IsEndParanthesis = false; + + while (a_pos < calcText.length()) + { + if (' ' == calcText[a_pos]) + { + a_pos++; + } + else if ('(' == calcText[a_pos]) + { + m_ParanthesisCount++; + bool dummy; + int64_t value2 = calcSign(calc(calcText, ++a_pos, dummy), isNegative); + value1 = doOperation(value1, operation, value2); + + + size_t tmpPos = a_pos; + std::string nextOp = getToken(a_calcText, tmpPos); + if (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp)) + { + + return value1; + } + + operation = ""; + } + else if (')' == calcText[a_pos]) + { + m_ParanthesisCount--; + a_pos++; + a_IsEndParanthesis = true; + return value1; + } + else if (isDigit(calcText[a_pos])) + { + + + int64_t value2 = calcSign(convertValue(calcText, a_pos), isNegative); + if (calcWithPriority(calcText, a_pos, value1, operation, value2, a_prevOp)) return value1; + } + else + { + + + std::string oldOperation = operation; + operation = getToken(calcText, a_pos); + + + if (!isOperation(operation)) + { + int64_t value2 = 0; + if (getVariableValue(operation, value2)) + { + value2 = calcSign(value2, isNegative); + if (calcWithPriority(calcText, a_pos, value1, oldOperation, value2, a_prevOp)) return value1; + operation = ""; + } + else + { + + m_Error = e_UnknownOperationOrVariable; + m_AdditionalErrorText = operation; + } + } + else + { + + if (oldOperation != "") + { + if (operation == "+") + { + operation = oldOperation; + } + else if (operation == "-") + { + isNegative = !isNegative; + operation = oldOperation; + } + else + { + m_Error = e_NoOperandBetweenOperators; + m_AdditionalErrorText = oldOperation + " " + operation; + return 0; + } + } + } + } + } + return value1; +} + + + + + + +bool IntegerCalculator::calcWithPriority(const std::string& a_calcText, size_t& a_pos, int64_t& a_value1, std::string& a_operation, int64_t a_value2, const std::string& a_prevOp) +{ + bool isParaEnd = false; + + size_t tmpPos = a_pos; + std::string nextOp = getToken(a_calcText, tmpPos); + if (isOperation(a_operation) && isOperation(nextOp) && isOperationPriorityHigher(nextOp, a_operation)) + { + + a_value2 = calc(a_calcText, a_pos, isParaEnd, a_operation, a_value2); + } + a_value1 = doOperation(a_value1, a_operation, a_value2); + if (isParaEnd || (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp))) + { + + return true; + } + a_operation = ""; + return false; +} + + + + + + + + +int64_t IntegerCalculator::calcSign(const int64_t a_value, bool& a_isNegative) +{ + if (a_isNegative) + { + a_isNegative = false; + return -a_value; + } + return a_value; +} + + + + + + +int64_t IntegerCalculator::convertValue(const std::string &a_valueText, size_t& a_pos) +{ + std::string valueText = a_valueText.substr(a_pos); + int base = 10; + size_t startpos = 0; + + bool isHex = (0 == valueText.find("0X")) || (0 == valueText.find("0x")); + bool isBin = (0 == valueText.find("0B")) || (0 == valueText.find("0b")); + if (isHex) + { + base = 16; + startpos = 2; + } + else if (isBin) + { + base = 2; + startpos = 2; + } + + size_t i; + for (i=startpos; i i && valueText[i] != ' ') + { + m_Error = e_InvalidOperand; + int spacePos = valueText.find(' '); + m_AdditionalErrorText = valueText.substr(0, spacePos); + } + a_pos += i; + + int64_t value = 0; + std::stringstream stream; + stream.str(valueText.substr(startpos, i-startpos)); + if (2 == base) + { + + const std::string binValueAsText = stream.str(); + for (const char c : binValueAsText) + { + value = value << 1; + if (c == '1') + value += 1; + } + } + else + { + stream << std::setbase(base); + stream >> value; + } + return value; +} + + + + + + +std::string IntegerCalculator::getToken(const std::string &a_calcText, size_t& a_pos) +{ + + while (a_pos < a_calcText.length()) + { + if (a_calcText[a_pos] == ' ') a_pos++; + else break; + } + + + size_t startPos = a_pos; + while (a_pos < a_calcText.length()) + { + if (' ' == a_calcText[a_pos]) break; + a_pos++; + } + return a_calcText.substr(startPos, a_pos-startPos); +} + + + + + +bool IntegerCalculator::isOperation(const std::string& a_operation) const +{ + std::map::const_iterator iter = m_OperationList.find(a_operation); + return (iter != m_OperationList.end()); +} + + + + + + +int64_t IntegerCalculator::doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2) +{ + + if (("+" == a_operation) || a_operation.empty()) + { + return a_value1 + a_value2; + } + else if ("-" == a_operation) + { + return a_value1 - a_value2; + } + else if ("*" == a_operation) + { + return a_value1 * a_value2; + } + else if ("/" == a_operation) + { + if (0 == a_value2) + { + m_Error = e_DivisionByZero; + } + else + { + return a_value1 / a_value2; + } + } + else if ("%" == a_operation) + { + if (0 == a_value2) + { + m_Error = e_DivisionByZero; + } + else + { + return a_value1 % a_value2; + } + } + else if ("<<" == a_operation) + { + return a_value1 << a_value2; + } + else if (">>" == a_operation) + { + return a_value1 >> a_value2; + } + else + { + m_Error = e_UnknownOperationOrVariable; + m_AdditionalErrorText = a_operation; + } + return 0; +} + + + + + + +bool IntegerCalculator::isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const +{ + return (getPriority(a_operation1) > getPriority(a_operation2)); +} + + + + + + + + + +bool IntegerCalculator::getVariableValue(const std::string& a_variableName, int64_t& a_value) const +{ + auto iter = m_VariableList.find(a_variableName); + if (iter != m_VariableList.end()) + { + a_value = iter->second; + return true; + } + + + return false; +} + + + + + + + +bool IntegerCalculator::isDigit(const char a_char, const bool a_isHex, const bool a_isBin) +{ + if (a_isHex) + { + + return (a_char >= '0' && a_char <= '9') || (a_char >= 'A' && a_char <= 'F') || (a_char >= 'a' && a_char <= 'f'); + } + else if (a_isBin) + { + + return (a_char >= '0' && a_char <= '1'); + } + + return (a_char >= '0' && a_char <= '9'); +} + + + + + + +int16_t IntegerCalculator::getPriority(const std::string& a_operation) const +{ + std::map::const_iterator iter = m_OperationList.find(a_operation); + if (iter != m_OperationList.end()) + return iter->second; + + return -1; +} + + + + + + +void IntegerCalculator::replace(std::string& a_haystack, const std::string &a_searchText, const std::string &a_replaceText) +{ + std::string::size_type searchSize = a_searchText.length(); + std::string::size_type replaceSize = a_replaceText.length(); + + std::string::size_type pos = a_haystack.find(a_searchText, 0); + while (std::string::npos != pos) + { + a_haystack.replace(pos, searchSize, a_replaceText); + pos += replaceSize; + pos = a_haystack.find(a_searchText, pos); + } +} + +} diff --git a/TetraIF/LogView/IntegerCalculator.hpp b/TetraIF/LogView/IntegerCalculator.hpp new file mode 100644 index 000000000..22fbf2db7 --- /dev/null +++ b/TetraIF/LogView/IntegerCalculator.hpp @@ -0,0 +1,143 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include + +namespace N_SST +{ + + + class IntegerCalculator + { + public: + + + + enum E_Error + { + + + e_Ok, + + + e_DivisionByZero, + + + e_UnknownOperationOrVariable, + + + e_NoOperandBetweenOperators, + + + e_InvalidOperand, + + + e_MissingLeftParanthesis, + + + e_MissingRightParanthesis, + + + e_UnknownError + }; + + + IntegerCalculator(); + virtual ~IntegerCalculator() = default; + + + + int64_t calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText = nullptr); + + + + void addVariable(const std::string& a_name, const int64_t a_value); + + + + void removeVariable(const std::string& a_name); + + protected: + + + + const std::map m_OperationList; + + + std::map m_VariableList; + + + std::string m_AdditionalErrorText; + + + int32_t m_ParanthesisCount; + E_Error m_Error; + + + + + int64_t calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis, + const std::string& a_prevOp = std::string(), const int64_t a_prevValue = 0, + const std::string& a_initOp = std::string()); + + + + bool calcWithPriority(const std::string& a_calcText, size_t& a_pos, int64_t& a_value1, + std::string& a_operation, int64_t a_value2, const std::string& a_prevOp); + + + + static int64_t calcSign(const int64_t a_value, bool& a_isNegative); + + + + int64_t convertValue(const std::string& a_valueText, size_t& a_pos); + + + + static std::string getToken(const std::string& a_calcText, size_t& a_pos); + + + + bool isOperation(const std::string& a_operation) const; + + + + int64_t doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2); + + + + bool isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const; + + + + virtual bool getVariableValue(const std::string& a_variableName, int64_t& a_value) const; + + + + static bool isDigit(const char a_char, const bool a_isHex = false, const bool a_isBin = false); + + + + int16_t getPriority(const std::string& a_operation) const; + + + + static void replace(std::string& a_haystack, const std::string& a_searchText, const std::string& a_replaceText); + + }; + +} diff --git a/TetraIF/LogView/LogViewBooleanEdit.cpp b/TetraIF/LogView/LogViewBooleanEdit.cpp new file mode 100644 index 000000000..4b3ec1b6b --- /dev/null +++ b/TetraIF/LogView/LogViewBooleanEdit.cpp @@ -0,0 +1,36 @@ + + + +#include "LogViewBooleanEdit.hpp" +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ + + +LogViewBooleanEdit::LogViewBooleanEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly) + : QCheckBox (a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) +{ + const QString valueText = a_field->value(0); + + setChecked(valueText.toInt() == 1); + setEnabled(!a_readonly); +} + + +bool LogViewBooleanEdit::saveContent(LogViewTelegram* a_telegram) +{ + if (m_Valid) + { + if (a_telegram->isJsonTelegram()) + a_telegram->setJsonValue(m_Field->jsonPath(), isChecked()); + else + a_telegram->setUIntX(getSize(), isChecked()); + return true; + } + return false; +} + +} diff --git a/TetraIF/LogView/LogViewBooleanEdit.hpp b/TetraIF/LogView/LogViewBooleanEdit.hpp new file mode 100644 index 000000000..abcba5c04 --- /dev/null +++ b/TetraIF/LogView/LogViewBooleanEdit.hpp @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + class LogViewBooleanEdit : public QCheckBox, public LogViewWidget + { + Q_OBJECT + public: + LogViewBooleanEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly); + bool saveContent(LogViewTelegram* a_telegram) override; + }; + +} diff --git a/TetraIF/LogView/LogViewDateTimeEdit.cpp b/TetraIF/LogView/LogViewDateTimeEdit.cpp new file mode 100644 index 000000000..b3af104e4 --- /dev/null +++ b/TetraIF/LogView/LogViewDateTimeEdit.cpp @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + +#include "LogViewDateTimeEdit.hpp" +#include +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ + + +LogViewDateTimeEdit::LogViewDateTimeEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly) + : QDateTimeEdit(a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) +{ + if (a_readonly) + { + setReadOnly(true); + setAlignment(a_field->isRightAligned() ? Qt::AlignRight : Qt::AlignLeft); + } + + + qint64 unixTime = 0; + if (a_field->hasContent()) + { + if (a_field->isMSecsField()) + unixTime = a_field->value(0, true).toLongLong(); + else + unixTime = a_field->value(0, true).toInt() * 1000LL; + } + + if (0 == unixTime && !a_readonly) + unixTime = ::time(nullptr) * 1000LL; + + + setDateTime(QDateTime::fromMSecsSinceEpoch(unixTime)); + setDisplayFormat(QLatin1String("dd MMM yyyy hh:mm:ss")); + setCalendarPopup(true); + updateToolTip(QString::number(unixTime)); + + + + connect(this, &LogViewDateTimeEdit::editingFinished, + this, &LogViewDateTimeEdit::checkAndOvertakeContent); +} + + + +void LogViewDateTimeEdit::checkAndOvertakeContent() +{ + updateToolTip(QString::number(dateTime().toMSecsSinceEpoch() / 1000)); +} + + + + + + +bool LogViewDateTimeEdit::saveContent(LogViewTelegram* a_telegram) +{ + if (a_telegram->isJsonTelegram()) + { + a_telegram->setJsonValue(m_Field->jsonPath(), dateTime().toMSecsSinceEpoch()); + } + else + { + a_telegram->setNextFieldAsGpsTimeField(); + a_telegram->setUIntX(getSize(), dateTime().toMSecsSinceEpoch() / 1000); + } + return true; +} + +} + diff --git a/TetraIF/LogView/LogViewDateTimeEdit.hpp b/TetraIF/LogView/LogViewDateTimeEdit.hpp new file mode 100644 index 000000000..a77b3b562 --- /dev/null +++ b/TetraIF/LogView/LogViewDateTimeEdit.hpp @@ -0,0 +1,40 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + + + class LogViewDateTimeEdit : public QDateTimeEdit, public LogViewWidget + { + Q_OBJECT + public: + + + LogViewDateTimeEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly); + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + public slots: + void checkAndOvertakeContent(); + + }; + +} diff --git a/TetraIF/LogView/LogViewEnumEdit.cpp b/TetraIF/LogView/LogViewEnumEdit.cpp new file mode 100644 index 000000000..8f8da7b96 --- /dev/null +++ b/TetraIF/LogView/LogViewEnumEdit.cpp @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + +#include "LogViewEnumEdit.hpp" +#include "LogViewXdrStruct.hpp" +#include "LogViewXdrValue.hpp" +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + + +namespace N_LogView +{ + + + +LogViewEnumEdit::LogViewEnumEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly, const int a_index) + : QComboBox(a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) +{ + QString value = a_field->value(a_index); + + + setToolTip(a_field->toolTipText()); + + + bool bCurrentIndexSet = false; + int i = 0; + while (LogViewXdrValue* child = (static_cast(a_field->xdrElement()))->getChildAsValue(i++)) + { + QString enumText = LogViewField::makeClean(child->getName()); + if (!a_readonly || enumText == value) + { + addItem(QStringLiteral("%1 (%2)").arg(enumText).arg(child->getValue()), QVariant::fromValue(child->getValue())); + if (a_readonly) + bCurrentIndexSet = true; + } + + if (enumText == value) + { + setCurrentIndex(a_readonly ? 0 : i - 1); + bCurrentIndexSet = true; + if (!a_readonly || (0 != a_index)) + updateToolTip(itemData(currentIndex()).toString()); + } + } + + if (!bCurrentIndexSet) + { + addItem(value); + setCurrentIndex(findText(value)); + } + + + connect(this, QOverload::of(&LogViewEnumEdit::currentIndexChanged), + this, &LogViewEnumEdit::checkAndOvertakeContent); +} + + + +uint16_t LogViewEnumEdit::getSize() const +{ + + const LogViewXdrStruct* xdrStruct = static_cast(m_Field->xdrElement()); + return xdrStruct->getEnumSize(); +} + + + +void LogViewEnumEdit::checkAndOvertakeContent() +{ + updateToolTip(itemData(currentIndex()).toString()); +} + + + + + + +bool LogViewEnumEdit::saveContent(LogViewTelegram* a_telegram) +{ + bool ok; + int value = itemData(currentIndex()).toInt(&ok); + if (ok) + { + if (a_telegram->isJsonTelegram()) + a_telegram->setJsonValue(m_Field->jsonPath(), value); + else + a_telegram->setUIntX(getSize(), value); + return true; + } + return false; +} + +} diff --git a/TetraIF/LogView/LogViewEnumEdit.hpp b/TetraIF/LogView/LogViewEnumEdit.hpp new file mode 100644 index 000000000..6198720e1 --- /dev/null +++ b/TetraIF/LogView/LogViewEnumEdit.hpp @@ -0,0 +1,43 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + + + class LogViewEnumEdit : public QComboBox, public LogViewWidget + { + Q_OBJECT + public: + + + LogViewEnumEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly, const int a_index); + + + uint16_t getSize() const override; + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + protected slots: + void checkAndOvertakeContent(); + + }; + +} diff --git a/TetraIF/LogView/LogViewField.cpp b/TetraIF/LogView/LogViewField.cpp new file mode 100644 index 000000000..4646f018f --- /dev/null +++ b/TetraIF/LogView/LogViewField.cpp @@ -0,0 +1,275 @@ + + + + + + + + + + + + + +#include "LogViewField.hpp" +#include +#include "LogViewXdrElement.hpp" +#include "LogViewXdrStandardType.hpp" + +namespace N_LogView +{ + + +LogViewField::LogViewField(const QString& a_name, const E_FieldKind a_kind, const LogViewXdrElement* a_xdrElement) + : m_Name(a_name), + m_IsRightAligned(false), + m_Offset(0), + m_Size(0), + m_MaxArraySize(0), + m_IsDynamicArray(false), + m_HasContent(true), + m_bDeleteXdr(false), + m_Kind(a_kind), + m_XdrElement(a_xdrElement), + m_logger(getLogger("LogViewField")) +{ +} + + +LogViewField::~LogViewField() +{ + for (LogViewField *f : qAsConst(m_Child)) + delete f; + if (m_bDeleteXdr) + delete m_XdrElement; +} + +LogViewField *LogViewField::clone(int arrayIdx) const +{ + LogViewField *f = new LogViewField(*this); + f->m_Child.clear(); + f->m_bDeleteXdr = false; + for (auto * c : m_Child) + { + auto *clonedChild = c->clone(-1); + if (arrayIdx >= 0) + { + QStringList sl = clonedChild->jsonPath(); + if (sl.size() > 1 && sl.at(sl.size() - 2).startsWith(QStringLiteral("index: "))) + { + sl[sl.size() - 2] = QStringLiteral("index: %1").arg(arrayIdx); + clonedChild->setJsonPath(sl); + } + } + f->addChild(clonedChild); + } + for (auto &val : f->m_ValueList) + val.clear(); + return f; +} + + + +void LogViewField::addChild(LogViewField* a_child) +{ + if (a_child) + m_Child.push_back(a_child); +} + + +void LogViewField::removeLastChild() +{ + if (m_Child.empty()) + return; + delete m_Child.takeLast(); +} + + + +LogViewField* LogViewField::child(int arrayIdx) +{ + if (m_Child.size() > arrayIdx) + return m_Child.at(arrayIdx); + return nullptr; +} + + +void LogViewField::addValue(const QString &value) +{ + m_ValueList.append(value); +} + + +void LogViewField::addValueBinaryHex(const QString &value) +{ + const QByteArray ba = QByteArray::fromHex(value.toLatin1()); + for (const char c : ba) + m_ValueList.append(QString::number(static_cast(c))); +} + + + + + + + + + +QString LogViewField::value(int arrayIdx, const bool a_doNotMakeSpecialConversions) const +{ + if (m_ValueList.size() > arrayIdx) + { + const QString &ret = m_ValueList.at(arrayIdx); + if (!a_doNotMakeSpecialConversions) + { + if (isDateTimeField()) + return QDateTime::fromMSecsSinceEpoch(ret.toLongLong() * 1000).toString(QStringLiteral("dd.mm.yy hh:mm:ss.zzz")); + if (isMSecsField()) + return QDateTime::fromMSecsSinceEpoch(ret.toLongLong()).toString(QStringLiteral("dd.mm.yy hh:mm:ss.zzz")); + } + return ret; + } + return QString(); +} + + +int64_t LogViewField::getHighestValue() const +{ + switch (m_XdrElement->getKind()) + { + case LogViewXdrElement::e_KindStandardType: + { + int64_t highest = 1; + + uint16_t bitSize = 8*static_cast(m_XdrElement)->getEditSize(); + + if ((0 == m_Name.compare(QLatin1String("utm nordwert"), Qt::CaseInsensitive)) || + (0 == m_Name.compare(QLatin1String("utm ostwert"), Qt::CaseInsensitive))) + bitSize -= 8; + + switch (static_cast(m_XdrElement)->getValueKind()) { + case LogViewXdrStandardType::e_Boolean: + return 1; + case LogViewXdrStandardType::e_Signed: + bitSize--; + Q_FALLTHROUGH(); + case LogViewXdrStandardType::e_Unsigned: + case LogViewXdrStandardType::e_Data: + highest = highest << bitSize; + highest--; + break; + default: + highest = 0; + break; + } + return highest; + } + default: + ERROR_LOG(m_logger) << "Case not implemented"; + } + return 0; +} + + + +int64_t LogViewField::getLowestValue() const +{ + switch (m_XdrElement->getKind()) + { + case LogViewXdrElement::e_KindStandardType: + { + int64_t lowest = 0; + + switch (static_cast(m_XdrElement)->getValueKind()) { + case LogViewXdrStandardType::e_Boolean: + return 0; + case LogViewXdrStandardType::e_Signed: + lowest = getHighestValue() + 1; + lowest = -lowest; + break; + default: + break; + } + return lowest; + } + default: + ERROR_LOG(m_logger) << "Case not implemented"; + break; + } + return 0; +} + + + +void LogViewField::dump(const QString &a_indent) const +{ + INFO_LOG(m_logger) << a_indent << "["; + INFO_LOG(m_logger) << a_indent << "Field[" << m_Name << "]: m_Kind=" << m_Kind << " m_Offset=" << m_Offset << " m_Size=" << m_Size << " m_MaxArraySize=" << m_MaxArraySize << " m_IsRightAligned=" << m_IsRightAligned << " m_IsDynamicArray=" << m_IsDynamicArray << " m_ToolTipText=" << m_ToolTipText; + + for (int i=0; i pos) + { + a_uncleanText[pos] = a_uncleanText[pos].toUpper(); + pos = a_uncleanText.indexOf(QLatin1Char(' '), pos + 1); + if (-1 == pos) + break; + pos++; + } + + return a_uncleanText; +} + + + + + +bool LogViewField::isDateTimeField() const +{ + QString name = m_Name.toLower(); + return name == QLatin1String("gps_zeit"); +} + +bool LogViewField::isMSecsField() const +{ + QString name = m_Name.toLower(); + return (name == QLatin1String("timestamp")) || (name == QLatin1String("effectstart")); +} + + + +void LogViewField::setMaxArraySize(uint16_t newVal, const bool a_isDynamic) +{ + m_MaxArraySize = newVal; + m_IsDynamicArray = a_isDynamic; +} + +} diff --git a/TetraIF/LogView/LogViewField.hpp b/TetraIF/LogView/LogViewField.hpp new file mode 100644 index 000000000..e9c4e8cfe --- /dev/null +++ b/TetraIF/LogView/LogViewField.hpp @@ -0,0 +1,142 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include "logger.h" + +namespace N_LogView +{ + class LogViewXdrElement; + class LogViewField + { + public: + enum E_FieldKind + { + e_FieldKindBorder, + e_FieldKindEdit, + e_FieldKindTab, + e_FieldKindTabChild, + e_FieldKindPodArray, + e_FieldKindPodArrayChild + }; + + + LogViewField(const QString& a_name, const E_FieldKind a_kind, const LogViewXdrElement* a_xdrElement); + virtual ~LogViewField(); + + LogViewField *clone(int arrayIdx) const; + + QString cleanName() const { return makeClean(m_Name); } + QString name() const { return m_Name; } + void setName(const QString &newVal) { m_Name = newVal; } + + + void addChild(LogViewField* a_child); + void removeLastChild(); + LogViewField *child(int arrayIdx); + int childCount() const { return m_Child.size(); } + + QString type() const { return m_type; } + void setType(const QString &type) { m_type = type; } + + LogViewField::E_FieldKind kind() const { return m_Kind; } + + void addValue(const QString &value); + void addValueBinaryHex(const QString &value); + + + + QString value(int arrayIdx, const bool a_doNotMakeSpecialConversions = false) const; + int valueListSize() const { return m_ValueList.size(); } + + + bool isRightAligned() const { return m_IsRightAligned; } + void setIsRightAligned(bool newVal) { m_IsRightAligned = newVal; } + + + QString toolTipText() const { return m_ToolTipText; } + void setToolTipText(const QString &newVal) { m_ToolTipText = newVal; } + + + int64_t getHighestValue() const; + int64_t getLowestValue() const; + + + + void dump(const QString &a_indent = QString()) const; + + + + static QString makeClean(const QString &text); + + + int size() const { return m_Size; } + void setSize(int newVal) { m_Size = newVal; } + + + const LogViewXdrElement* xdrElement() const { return m_XdrElement; } + + + + bool isDateTimeField() const; + bool isMSecsField() const; + + + uint16_t maxArraySize() const { return m_MaxArraySize; } + void setMaxArraySize(uint16_t newVal, const bool a_isDynamic); + + + + bool isDynamicArray() const { return m_IsDynamicArray; } + + + bool hasContent() const { return m_HasContent; } + void setHasContent(bool newVal) { m_HasContent = newVal; } + + void setDeleteXdr(bool bDelete) { m_bDeleteXdr = bDelete; } + + void setJsonPath(const QStringList &path) { m_jsonPath = path; } + QStringList jsonPath() const { return m_jsonPath; } + + protected: + + QString m_Name; + QString m_type; + QStringList m_ValueList; + QStringList m_jsonPath; + bool m_IsRightAligned; + QString m_ToolTipText; + uint16_t m_Offset; + int m_Size; + uint16_t m_MaxArraySize; + + + bool m_IsDynamicArray; + bool m_HasContent; + bool m_bDeleteXdr; + QVector m_Child; + + E_FieldKind m_Kind; + + const LogViewXdrElement *m_XdrElement; + + private: + + + NGL::INGLLogger &m_logger; + + }; +} diff --git a/TetraIF/LogView/LogViewGui.cpp b/TetraIF/LogView/LogViewGui.cpp new file mode 100644 index 000000000..439fa873b --- /dev/null +++ b/TetraIF/LogView/LogViewGui.cpp @@ -0,0 +1,1013 @@ + + + + + + + + + + + + + + +#include "LogViewGui.hpp" + +#include "LogViewTelegram.hpp" +#include "LogViewXdrParser.hpp" +#include "LogViewTelegramDialog.hpp" +#include "LogViewOptionDialog.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LogViewInjectionThread.hpp" +#include "LogViewTelegramEdit.hpp" +#include "LogViewTetraTelegramsParser.hpp" +#include + +namespace N_LogView +{ + + +const QLatin1String LogViewGui::WINDOW_GROUP("MainWindow"); +const QLatin1String LogViewGui::SIZE("Size"); +const QLatin1String LogViewGui::SCREEN("Screen"); +const QLatin1String LogViewGui::POS("Pos"); +const QLatin1String LogViewGui::SPLITTPOS("SplittPos"); +const QLatin1String LogViewGui::TOOLBOXINDEX("ToolBoxIndex"); + + + + + +LogViewGui::LogViewGui(QWidget* a_parent) + : QMainWindow(a_parent) + , RADIO_BUTTON_ICON_SIZE(16, 16) + , m_LogfileSize(0) + , m_DoReload(false) + , m_EditTelegramController(new TelegramEdit(this)) + , m_TailTimer(nullptr) + , m_InjectionThread(nullptr) + , m_replayTimer(new QTimer(this)) + , m_currentReplayRow(-1) + , m_logger(getLogger("LogViewGui")) +{ + setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde_16x16.png"))); + + QSettings settings; + settings.beginGroup(WINDOW_GROUP); + + + m_InjectionStatus = new QLabel(this); + m_InjectionStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addPermanentWidget(m_InjectionStatus); + m_ParticipantStatus = new QLabel(this); + m_ParticipantStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addPermanentWidget(m_ParticipantStatus); + m_TelegramStatus = new QLabel(this); + m_TelegramStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addPermanentWidget(m_TelegramStatus); + + + + QToolBar* toolBar = addToolBar(tr("Datei")); + toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + QString tipText; + QAction* action = new QAction(tr("Neue Log-Datei"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/document-new.png"))); + action->setShortcut(tr("Ctrl+N")); + tipText = tr("Eine neue Telegram-Log-Datei anzeigen (Ctrl-N)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::newTelegramFile); + toolBar->addAction(action); + + action = new QAction(tr("Log-Datei hinzu"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/document-import.png"))); + action->setShortcut(tr("Ctrl+O")); + tipText = tr("Eine weitere Telegramm-Log-Datei anzeigen (Ctrl-O)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::loadTelegramFile); + toolBar->addAction(action); + + m_reloadAction = new QAction(tr("&Reload"), this); + m_reloadAction->setCheckable(true); + m_reloadAction->setChecked(m_DoReload); + m_reloadAction->setIcon(QIcon(QLatin1String(":icons/16x16/edit-redo.png"))); + m_reloadAction->setShortcut(tr("Ctrl+R")); + tipText = tr("Reload des Logfiles ein-/ausschalten (Ctrl-R)"); + m_reloadAction->setStatusTip(tipText); + m_reloadAction->setToolTip(tipText); + connect(m_reloadAction, &QAction::triggered, this, &LogViewGui::reloadOnOff); + toolBar->addAction(m_reloadAction); + + action = new QAction(tr("&Einstellungen"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/configure.png"))); + action->setShortcut(tr("Ctrl+E")); + tipText = tr("Verhalten des Programmes einstellen (Ctrl-E)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::changeSettings); + toolBar->addAction(action); + + toolBar->addSeparator(); + action = new QAction(tr("&Beenden"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/edit-delete.png"))); + action->setShortcut(tr("Alt-F4")); + tipText = tr("LogView beenden (Alt-F4)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::close); + toolBar->addAction(action); + + createCentralSelectionWidget(); + createTetraSelectionWidget(); + createWlsSelectionWidget(); + + + + m_ParticipantTableView = new QTableView(this); + m_participantProxyModel = new QSortFilterProxyModel(this); + m_participantModel = new ParticipantModel(this); + m_participantProxyModel->setSourceModel(m_participantModel); + m_ParticipantTableView->setModel(m_participantProxyModel); + m_ParticipantTableView->setAlternatingRowColors(true); + m_ParticipantTableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_ParticipantTableView->setSelectionMode(QAbstractItemView::MultiSelection); + m_ParticipantTableView->setSortingEnabled(true); + m_ParticipantTableView->setTabKeyNavigation(false); + m_ParticipantTableView->verticalHeader()->hide(); + m_ParticipantTableView->verticalHeader()->setMinimumSectionSize(QApplication::font().pointSize() * 2.5); + m_ParticipantTableView->verticalHeader()->setDefaultSectionSize(QApplication::font().pointSize() * 2.5); + m_ParticipantTableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ParticipantTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + connect(m_ParticipantTableView->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &LogViewGui::selectedParticipantChanged); + QVBoxLayout* participantBox = new QVBoxLayout; + participantBox->addWidget(m_ParticipantTableView); + m_ParticipantSelectionGroup = new QGroupBox(tr("Teilnehmer-Filter &aktivieren"), this); + m_ParticipantSelectionGroup->setCheckable(true); + m_ParticipantSelectionGroup->setChecked(false); + m_ParticipantSelectionGroup->setLayout(participantBox); + connect(m_ParticipantSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::selectedParticipantChanged); + + + m_ToolBox = new QToolBox(this); + m_ToolBox->addItem(m_CentralSelectionGroup, QIcon(QLatin1String(":/image/Central.png")), tr("&Zentral-Telegramm-Filter")); + m_ToolBox->addItem(m_TetraSelectionGroup, QIcon(QLatin1String(":/image/Tetra.png")), tr("TET&RA-Telegramm-Filter")); + m_ToolBox->addItem(m_WlsSelectionGroup, QIcon(QLatin1String(":/image/Wls.png")), tr("&WLS-Telegramm-Filter")); + m_ToolBox->addItem(m_ParticipantSelectionGroup, QIcon(QLatin1String(":/image/TNE.png")), tr("Teilnehmer-&Filter")); + m_ToolBox->addItem(m_EditTelegramController->tableView(), QIcon(QLatin1String(":icons/16x16/document-edit.png")), tr("&Edit && Sende Telegramme")); + m_ToolBox->setCurrentIndex(settings.value(TOOLBOXINDEX).toInt()); + + + + m_logTelegramView = new QTableView(this); + m_logTelegramView->setAlternatingRowColors(true); + m_logTelegramView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_logTelegramView->setSelectionMode(QAbstractItemView::ContiguousSelection); + m_logTelegramView->verticalHeader()->hide(); + m_logTelegramView->verticalHeader()->setMinimumSectionSize(QApplication::font().pointSize() * 2.5); + m_logTelegramView->verticalHeader()->setDefaultSectionSize(QApplication::font().pointSize() * 2.5); + m_logTelegramView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + m_logTelegramView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_logTelegramView, &QTableView::customContextMenuRequested, + this, &LogViewGui::customMenuRequested); + m_telegramModel = new TelegramModel(m_logTelegramView); + m_telegramProxyModel = new TelegramProxyModel(m_logTelegramView); + m_telegramProxyModel->setSourceModel(m_telegramModel); + m_logTelegramView->setModel(m_telegramProxyModel); + connect(m_logTelegramView, &QTableView::doubleClicked, + this, &LogViewGui::onLogTelegramViewDoubleClicked); + m_logTelegramView->horizontalHeader()->setSortIndicatorShown(true); + m_logTelegramView->horizontalHeader()->setSortIndicator(3, Qt::AscendingOrder); + m_logTelegramView->setSortingEnabled(true); + + QVBoxLayout* telegramBox = new QVBoxLayout; + telegramBox->addWidget(m_logTelegramView); + QGroupBox* telegramGroup = new QGroupBox(tr("&Log-Telegramme"), this); + telegramGroup->setLayout(telegramBox); + + + m_Splitter = new QSplitter(Qt::Horizontal, this); + m_Splitter->addWidget(m_ToolBox); + m_Splitter->addWidget(telegramGroup); + const QList splitterSizesAsVariant = settings.value(SPLITTPOS).toList(); + QList splitterSizes; + splitterSizes.reserve(splitterSizesAsVariant.size()); + if (splitterSizesAsVariant.isEmpty()) + { + splitterSizes << 235 << 1000; + } + else + { + for (const QVariant &item : splitterSizesAsVariant) + splitterSizes << item.toInt(); + } + m_Splitter->setSizes(splitterSizes); + setCentralWidget(m_Splitter); + + + + m_CentralSelectionGroup->setChecked(true); + m_ackCentralTelCheckBox->setChecked(true); + m_ackCentralTelCheckBox->setChecked(false); + m_PosCentralTelCheckBox->setChecked(true); + m_PosCentralTelCheckBox->setChecked(false); + m_SentCentralTelCheckBox->setChecked(true); + m_ReceivedCentralTelCheckBox->setChecked(true); + + m_TetraSelectionGroup->setChecked(true); + m_SentTetraTelCheckBox->setChecked(true); + m_ReceivedTetraTelCheckBox->setChecked(true); + m_PosTetraTelCheckBox->setChecked(true); + m_PosTetraTelCheckBox->setChecked(false); + m_FragmentedTetraTelCheckBox->setChecked(true); + m_LoginTetraTelCheckBox->setChecked(true); + m_RegisterTetraTelCheckBox->setChecked(true); + m_ReportTetraTelCheckBox->setChecked(false); + m_AirInterfaceLoadTetraTelCheckBox->setChecked(false); + + m_WlsSelectionGroup->setChecked(true); + m_PosWlsTelCheckBox->setChecked(true); + m_PosWlsTelCheckBox->setChecked(false); + m_SentWlsTelCheckBox->setChecked(true); + m_ReceivedWlsTelCheckBox->setChecked(true); + + + QSize size = settings.value(SIZE, sizeHint()).toSize(); + resize(size.isNull() ? QSize(1280, 768) : size); + move(settings.value(POS, QPoint(0, 0)).toPoint()); + settings.endGroup(); + + connect(m_replayTimer, &QTimer::timeout, this, &LogViewGui::onReplayTimerTimeout); + + QTimer::singleShot(0, this, &LogViewGui::loadSpecificationFiles); + + startInjectionThread(); +} + +void LogViewGui::createCentralSelectionWidget() +{ + + m_SentCentralTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/P2C.png")); + + m_ReceivedCentralTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/C2P.png")); + + m_PosCentralTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/CentralPos.png")); + + m_ackCentralTelCheckBox = createRadioButton(tr("&Bestaetigungstelegramme"), QLatin1String(":/image/CentralAck.png")); + + QVBoxLayout* centralFilterBox = new QVBoxLayout; + centralFilterBox->addWidget(m_SentCentralTelCheckBox); + centralFilterBox->addWidget(m_ReceivedCentralTelCheckBox); + centralFilterBox->addWidget(m_PosCentralTelCheckBox); + centralFilterBox->addWidget(m_ackCentralTelCheckBox); + centralFilterBox->addStretch(1); + + m_CentralSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); + m_CentralSelectionGroup->setCheckable(true); + m_CentralSelectionGroup->setChecked(false); + m_CentralSelectionGroup->setLayout(centralFilterBox); + connect(m_CentralSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); +} + +void LogViewGui::createTetraSelectionWidget() +{ + + m_SentTetraTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/T2P.png")); + + m_ReceivedTetraTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/P2T.png")); + + m_PosTetraTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/TetraPos.png")); + + m_FragmentedTetraTelCheckBox = createRadioButton(tr("&Fragmentierte Meldungen"), QLatin1String(":/image/TetraFragmented.png")); + + m_LoginTetraTelCheckBox = createRadioButton(tr("&Loginmeldungen"), QLatin1String(":/image/TetraLogin.png")); + + m_RegisterTetraTelCheckBox = createRadioButton(tr("&Registermeldungen"), QLatin1String(":/image/TetraRegister.png")); + + m_ReportTetraTelCheckBox = createRadioButton(tr("&Reportmeldungen"), QLatin1String(":/image/TetraReport.png")); + + m_AirInterfaceLoadTetraTelCheckBox = createRadioButton(tr("&Air-Load Meldungen"), QLatin1String(":/image/TetraAirInterface.png")); + + QVBoxLayout* tetraFilterBox = new QVBoxLayout; + tetraFilterBox->addWidget(m_SentTetraTelCheckBox); + tetraFilterBox->addWidget(m_ReceivedTetraTelCheckBox); + tetraFilterBox->addWidget(m_PosTetraTelCheckBox); + tetraFilterBox->addWidget(m_FragmentedTetraTelCheckBox); + tetraFilterBox->addWidget(m_LoginTetraTelCheckBox); + tetraFilterBox->addWidget(m_RegisterTetraTelCheckBox); + tetraFilterBox->addWidget(m_ReportTetraTelCheckBox); + tetraFilterBox->addWidget(m_AirInterfaceLoadTetraTelCheckBox); + tetraFilterBox->addStretch(1); + + m_TetraSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); + m_TetraSelectionGroup->setCheckable(true); + m_TetraSelectionGroup->setChecked(false); + m_TetraSelectionGroup->setLayout(tetraFilterBox); + connect(m_TetraSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); +} + +void LogViewGui::createWlsSelectionWidget() +{ + + m_SentWlsTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/P2W.png")); + + m_ReceivedWlsTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/W2P.png")); + + m_PosWlsTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/WlsPos.png")); + + QVBoxLayout* wlsFilterBox = new QVBoxLayout; + wlsFilterBox->addWidget(m_SentWlsTelCheckBox); + wlsFilterBox->addWidget(m_ReceivedWlsTelCheckBox); + wlsFilterBox->addWidget(m_PosWlsTelCheckBox); + wlsFilterBox->addStretch(1); + + m_WlsSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); + m_WlsSelectionGroup->setCheckable(true); + m_WlsSelectionGroup->setChecked(false); + m_WlsSelectionGroup->setLayout(wlsFilterBox); + connect(m_WlsSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); +} + + + +void LogViewGui::customMenuRequested(const QPoint &pos) +{ + + QMenu menu(this); + menu.addAction(tr("Add Telegram to EditList"), this, &LogViewGui::addTelegramToEdit); + menu.addAction(tr("Show HexData"), this, &LogViewGui::showHexData); + menu.addAction(tr("Export as CSV file"), this, &LogViewGui::exportAsCsv); + menu.addAction(tr("Export as JSon file"), this, &LogViewGui::exportAsJson); +#ifdef LTS_DEBUG + if (m_EditTelegramController && m_EditTelegramController->isInjectionPossible()) + { + const QString str = m_replayTimer->isActive() ? tr("Stop replay") : tr("Start Replay from here"); + menu.addAction(str, this, &LogViewGui::onStartLogReplay); + } +#endif + menu.exec(m_logTelegramView->viewport()->mapToGlobal(pos)); +} + + + +void LogViewGui::addTelegramToEdit() +{ + for (const QModelIndex &orig: m_logTelegramView->selectionModel()->selectedRows()) + { + const QModelIndex idx = m_telegramProxyModel->mapToSource(orig); + QSharedPointer tele = m_telegramModel->telegram(idx.row()); + if (!tele) + continue; + m_EditTelegramController->appendTelegram(tele); + } +} + + + +void LogViewGui::showHexData() +{ + const QModelIndex idx = m_telegramProxyModel->mapToSource(m_logTelegramView->currentIndex()); + QSharedPointer tele = m_telegramModel->telegram(idx.row()); + if (!tele) + return; + + LogViewTelegramDialog* showTelegramDialog = new LogViewTelegramDialog(this, true); + showTelegramDialog->showDataDump(tele, false); +} + + +void LogViewGui::exportAsCsv() +{ + const int idx = m_ActualLogfile.lastIndexOf(QLatin1Char('.')); + const QString suggestion = m_ActualLogfile.left(idx) + QLatin1String(".csv"); + const QString fn = QFileDialog::getSaveFileName(this, tr("Export logdata as CSV"), suggestion, tr("CSV file (*.csv)")); + if (fn.isEmpty()) + return; + QFile f(fn); + if (!f.open(QIODevice::WriteOnly)) + return; + for (int c = 0; c < m_telegramProxyModel->columnCount(); ++c) + { + f.write(m_telegramProxyModel->headerData(c, Qt::Horizontal).toString().toUtf8()); + f.write(";"); + } + f.write("ISSI\n"); + const int rc = m_telegramProxyModel->rowCount(); + for (int r = 0; r < rc; ++r) + { + QSharedPointer tele = m_telegramProxyModel->telegram(r); + if (!tele) + continue; + f.write(QByteArray::number(tele->getDestination())); + f.write(";"); + f.write(tele->getName().toUtf8()); + f.write(";"); + f.write(QByteArray::number(tele->getParticipantId())); + f.write(";"); + f.write(QByteArray::number(tele->getLogTimeMsec())); + f.write(";"); + f.write(QByteArray::number(tele->getGpsTime())); + f.write(";"); + f.write(QByteArray::number(tele->getDelay())); + f.write(";"); + f.write(QByteArray::number(tele->getISSI())); + f.write("\n"); + } + f.close(); +} + +void LogViewGui::exportAsJson() +{ + const int idx = m_ActualLogfile.lastIndexOf(QLatin1Char('.')); + const QString suggestion = m_ActualLogfile.left(idx) + QLatin1String(".csv"); + const QString fn = QFileDialog::getSaveFileName(this, tr("Export logdata as Json"), suggestion, tr("JSon file (*.json)")); + if (fn.isEmpty()) + return; + QFile f(fn); + if (!f.open(QIODevice::WriteOnly)) + return; + QJsonArray arr; + const int rc = m_telegramProxyModel->rowCount(); + for (int r = 0; r < rc; ++r) + { + QSharedPointer tele = m_telegramProxyModel->telegram(r); + if (!tele) + continue; + if (tele->jsonData().isEmpty()) + continue; + arr += tele->jsonData(); + } + f.write(QJsonDocument(arr).toJson(QJsonDocument::Indented)); + f.close(); +} + + +void LogViewGui::onStartLogReplay() +{ +#ifndef LTS_DEBUG + return; +#endif + if (m_replayTimer->isActive()) + { + m_replayTimer->stop(); + return; + } + m_reloadAction->setChecked(false); + m_PosCentralTelCheckBox->setChecked(true); + if (!m_EditTelegramController || !m_EditTelegramController->isInjectionPossible()) + return; + m_currentReplayRow = m_telegramProxyModel->mapToSource(m_logTelegramView->currentIndex()).row(); + if (m_currentReplayRow < 0) + return; + m_replayTimer->start(0); +} + +void LogViewGui::onReplayTimerTimeout() +{ + auto findNextCentralTelegram = [&]() + { + static constexpr auto sendToCentralBits = N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral | + N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend; + auto tele = m_telegramModel->telegram(m_currentReplayRow); + while (tele && (tele->getDestination() != sendToCentralBits || + tele->getTelId() == GEF_BESTAETIGUNG)) + tele = m_telegramModel->telegram(++m_currentReplayRow); + return tele; + }; + + QSharedPointer tele = findNextCentralTelegram(); + auto checkTele = [&]() + { + if (!tele) + { + m_replayTimer->stop(); + m_currentReplayRow = -1; + QMessageBox::information(this, tr("Sending finished"), tr("No more telegrams to send - stopping")); + return false; + } + return true; + }; + + if (!checkTele()) + return; + const uint64_t curSendTime = tele->getLogTimeMsec(); + auto teleCopy = QSharedPointer(new LogViewTelegram(*(tele.data()))); + teleCopy->actualizeGpsTime(); + m_InjectionThread->sendTelegram(teleCopy.data(), true); + ++m_currentReplayRow; + tele = findNextCentralTelegram(); + if (!checkTele()) + return; + + uint64_t nextSendTime = (tele->getLogTimeMsec() - curSendTime); + DEBUG_LOG(m_logger) << "Next SendTime: " << nextSendTime + << ", telId: " << tele->getTelId() + << ", next row: " << m_currentReplayRow + << ", equipNo: " << tele->getParticipantId(); + QModelIndex idx = m_telegramModel->index(m_currentReplayRow, 0, QModelIndex()); + m_logTelegramView->setCurrentIndex(m_telegramProxyModel->mapFromSource(idx)); + m_replayTimer->start(nextSendTime); +} + + +void LogViewGui::loadSpecificationFiles() +{ + QSettings settings; + settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP); + + + QString defString = QCoreApplication::applicationDirPath() + QLatin1String("/training_area_telegrams.h"); + QString filename = settings.value(LogViewOptionDialog::P0_FILENAME, defString).toString(); + INFO_LOG(m_logger) << "Load central-protocol spezification-file: " << filename.toStdString(); + if (!QFile::exists(filename)) + { + QMessageBox::warning(this, tr("LogView"), tr("Die Spezifikations-Datei \'%1\' fuer Zentral-Telegramme existiert nicht!

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

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

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


%3").arg(m_LineNbr).arg(m_Line, a_errorText, m_Filename)); +} + + + +int64_t LogViewXdrParser::calcValue(const QString& a_calcText, bool& a_isOk) +{ + + a_isOk = false; + int64_t value = 0; + if (!a_calcText.startsWith(QLatin1Char('\"'))) + { + N_SST::IntegerCalculator::E_Error error; + std::string errorText; + value = calc(a_calcText.toStdString(), error, &errorText); + + + if (error != N_SST::IntegerCalculator::e_Ok) + { + switch (error) + { + case N_SST::IntegerCalculator::e_DivisionByZero: + showErrorMessage(QObject::tr("Division durch 0 nicht erlaubt!")); + break; + case N_SST::IntegerCalculator::e_InvalidOperand: + showErrorMessage(QObject::tr("Operand %1 ist fehlerhaft!").arg(QString::fromStdString(errorText))); + break; + case N_SST::IntegerCalculator::e_MissingLeftParanthesis: + showErrorMessage(QObject::tr("Es fehlen Klammer Öffnungen (!")); + break; + case N_SST::IntegerCalculator::e_MissingRightParanthesis: + showErrorMessage(QObject::tr("Es fehlen Klammer Schliessungen )!")); + break; + case N_SST::IntegerCalculator::e_NoOperandBetweenOperators: + showErrorMessage(QObject::tr("Zwei Operationen (%1) nacheinander sind nicht erlaubt!").arg(QString::fromStdString(errorText))); + break; + case N_SST::IntegerCalculator::e_UnknownOperationOrVariable: + showErrorMessage(QObject::tr("Operation oder Variable %1 unbekannt!").arg(QString::fromStdString(errorText))); + break; + case N_SST::IntegerCalculator::e_UnknownError: + showErrorMessage(QObject::tr("Unbekannter Fehler!")); + break; + default: + break; + } + ERROR_LOG(m_logger) << "Problem with converting '" << a_calcText << "' to integer"; + } + else + { + a_isOk = true; + } + } + return value; +} + + + +bool LogViewXdrParser::getVariableValue(const std::string& a_variableName, int64_t& a_value) const +{ + return getDefine(QString::fromStdString(a_variableName), a_value); +} + + + + + + + + + + +QString LogViewXdrParser::getTelegramName(int a_telegramId) const +{ + const auto iter = m_TelegramMap.find(a_telegramId); + if (m_TelegramMap.end() != iter) + return iter->second.getName(); + + return QObject::tr("").arg(a_telegramId); +} + + +QString LogViewXdrParser::getStructName(int a_telegramId) const +{ + const auto iter = m_TelegramMap.find(a_telegramId); + if (m_TelegramMap.end() != iter) + return iter->second.getType(); + + return QObject::tr("").arg(a_telegramId); +} + + +bool LogViewXdrParser::getDefine(const QString& a_name, int64_t& a_value) const +{ + const auto iter = m_DefinesMap.find(a_name); + if (iter != m_DefinesMap.end()) + { + a_value = iter->second.getValue(); + return true; + } + return false; +} + + + +const LogViewXdrElement* LogViewXdrParser::getElement(const QString& a_name) const +{ + const auto iter = m_ElementMap.find(a_name); + if (iter != m_ElementMap.end()) + return iter->second; + + showErrorMessage(QObject::tr("Typ \'%1\' nicht definiert!").arg(a_name)); + return nullptr; +} + + + +uint16_t LogViewXdrParser::parseArray(QString& a_name, uint16_t& a_dynArrayMsgOffset) const +{ + a_dynArrayMsgOffset = 0; + QString oldName = a_name; + + + + int pos = a_name.indexOf(QLatin1Char('[')); + if (pos >= 0) + { + int endPos = a_name.indexOf(QLatin1Char(']')); + if (endPos > pos) + { + + QString arraySizeText = a_name.mid(pos+1, endPos-pos-1); + + a_name = a_name.left(pos); + + int64_t arraySizeValue = 1; + + if (!getDefine(arraySizeText, arraySizeValue)) + { + bool ok = false; + arraySizeValue = arraySizeText.toInt(&ok); + if (!ok) + { + showErrorMessage(QObject::tr("%1: [%2] is not a number").arg(oldName, arraySizeText)); + } + } + + return arraySizeValue; + } + else + { + showErrorMessage(QObject::tr("%1: Did not found expected ']'").arg(oldName)); + } + } + else + { + + + + + pos = a_name.indexOf(QLatin1Char('<')); + if (pos >= 0) + { + int endPos = a_name.indexOf(QLatin1Char('>')); + if (endPos > pos) + { + + QString arraySizeText = a_name.mid(pos+1, endPos-pos-1); + + + a_name = a_name.left(pos); + + + int64_t arraySizeValue = 1; + if (!getDefine(arraySizeText, arraySizeValue)) + { + bool ok = false; + arraySizeValue = arraySizeText.toInt(&ok); + if (!ok) + { + showErrorMessage(QObject::tr("%1: \'%2\' is not a number").arg(a_name, arraySizeText)); + } + else + { + + } + } + a_dynArrayMsgOffset = arraySizeValue; + + return 0; + } + else + { + showErrorMessage(QObject::tr("%1: Did not found expected '>'").arg(a_name)); + } + } + } + return 1; +} + + + +bool LogViewXdrParser::isNextWord(const char *a_word, const bool a_doIncrement) +{ + const QString word = QString::fromUtf8(a_word); + bool ok = (m_WordListIndex < m_WordList.size() && + m_WordList.at(m_WordListIndex) == word); + + + if (!ok && a_doIncrement) + { + if (m_WordListIndex > 0) + showErrorMessage(QObject::tr("Erwarte %1 nach \'%2\'!").arg(word, m_WordList.at(m_WordListIndex-1))); + else + showErrorMessage(QObject::tr("Erwarte %1!").arg(word)); + } + + if (a_doIncrement) + m_WordListIndex++; + return ok; +} + + + +void LogViewXdrParser::fillWordList(const QString& a_line) +{ + QString line = a_line; + line.replace(QLatin1Char('('), QLatin1String(" ( ")); + line.replace(QLatin1Char(')'), QLatin1String(" ) ")); + line.replace(QLatin1Char('{'), QLatin1String(" { ")); + line.replace(QLatin1Char('}'), QLatin1String(" } ")); + line.replace(QLatin1Char(':'), QLatin1String(" : ")); + line.replace(QLatin1Char(';'), QLatin1String(" ; ")); + m_WordList = line.split(QLatin1Char(' '), QString::SkipEmptyParts); + m_WordListIndex = 0; + + + + + +} + + + +QString LogViewXdrParser::getNextWord(const char *a_errorText) +{ + QString word; + if (m_WordListIndex < m_WordList.size()) + word = m_WordList.at(m_WordListIndex); + + if (word.isEmpty() && a_errorText) + { + const QString errTxt(QString::fromUtf8(a_errorText)); + if (m_WordListIndex > 0) + showErrorMessage(QObject::tr("Erwarte %1 nach \'%2\'!").arg(errTxt, m_WordList.at(m_WordListIndex-1))); + else + showErrorMessage(QObject::tr("Erwarte %1!").arg(errTxt)); + } + m_WordListIndex++; + return word; +} + + + +QString LogViewXdrParser::getNextType(bool& a_ok) +{ + a_ok = true; + QString type = getNextWord("Typ"); + if (type.isEmpty()) a_ok = false; + if (type == QLatin1String("unsigned") || + type == QLatin1String("signed")) + { + QString type2 = getNextWord("Typ"); + if (type2.isEmpty()) a_ok = false; + type = QStringLiteral("%1 %2").arg(type, type2); + } + return type; +} + + + +QString LogViewXdrParser::getNextEnum(const LogViewXdrStruct*& a_enumStruct) +{ + QString type; + a_enumStruct = nullptr; + if (m_WordListIndex < m_WordList.size()) + { + type = m_WordList.at(m_WordListIndex); + a_enumStruct = static_cast(getElement(type)); + if (a_enumStruct) + { + if (LogViewXdrElement::e_KindEnum != a_enumStruct->getKind()) + { + showErrorMessage(QObject::tr("Typ \'%1\' muss ein Enum sein!").arg(type)); + a_enumStruct = nullptr; + } + } + else + showErrorMessage(QObject::tr("Enum \'%1\' nicht definiert!").arg(type)); + m_WordListIndex++; + } + return type; +} + + + +bool LogViewXdrParser::parseBitfield(const QString& a_fieldText, int16_t& a_firstBit, int16_t& a_lastBit) const +{ + + + a_firstBit = -1; + a_lastBit = -1; + bool isLast = true; + + int doublePointPos = a_fieldText.indexOf(QLatin1String("..")); + if (doublePointPos != -1) + { + QString bitText = a_fieldText.left(doublePointPos); + bool ok; + a_firstBit = bitText.toInt(&ok); + if (ok) + { + + bitText = a_fieldText.mid(doublePointPos+2); + + if (bitText.endsWith(QLatin1Char('!'))) + { + isLast = true; + bitText.chop(1); + } + else + { + isLast = false; + } + a_lastBit = bitText.toInt(&ok); + if (ok) + { + + + } + else + { + showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Zweites Bit (%1) ist keine Zahl!").arg(bitText)); + } + } + else + { + showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Erstes Bit (%1) ist keine Zahl!").arg(bitText)); + } + } + else + { + showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Habe .. nicht gefunden!")); + } + return isLast; +} + + + + + + + + +bool LogViewXdrParser::addToElementMap(const QString& a_name, LogViewXdrElement* a_element) +{ + if (m_ElementMap.find(a_name) == m_ElementMap.end()) + { + m_ElementMap.insert(std::make_pair(a_name, a_element)); + return true; + } + showErrorMessage(QObject::tr("Der Typ '%1' wurde bereits frueher definiert => Bitte ein einem Ort entfernen!").arg(a_name)); + return false; +} + +} + diff --git a/TetraIF/LogView/LogViewXdrParser.hpp b/TetraIF/LogView/LogViewXdrParser.hpp new file mode 100644 index 000000000..9f2472057 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrParser.hpp @@ -0,0 +1,183 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include + +#include "IntegerCalculator.hpp" +#include "logger.h" +#include "LogViewXdrStandardType.hpp" + +namespace N_LogView +{ + class LogViewXdrElement; + class LogViewXdrStruct; + class LogViewField; + class LogViewXdrValue; + class LogViewXdrType; + + + + class LogViewXdrParser : public N_SST::IntegerCalculator + { + public: + + + + enum E_ParseState + { + e_ParseMain, + e_ParseStruct, + e_ParseEnum, + e_ParseUnion + }; + + + LogViewXdrParser(); + ~LogViewXdrParser(); + + + + + void parseX_File(const QString& a_fileName); + + + + QString getTelegramName(int a_telegramId) const; + + + + QString getStructName(int a_telegramId) const; + + + + bool getDefine(const QString& a_name, int64_t& a_value) const; + + + + const LogViewXdrElement* getElement(const QString& a_name) const; + + protected: + + QString m_MessageBoxTitle; + bool m_WithinComment; + QString m_Line; + uint32_t m_LineNbr; + QString m_Filename; + bool m_DoReadUntilSemicolon; + QStringList m_WordList; + int m_WordListIndex; + + + QString m_UnionType; + std::map m_ElementMap; + + LogViewXdrStruct *m_ActElement; + + E_ParseState m_State; + + std::map m_DefinesMap; + + std::map m_TelegramMap; + + + + void addStandardType(const QString& a_name, + const uint16_t a_dataSize, + const uint16_t a_realSize, + const LogViewXdrStandardType::E_ValueKind a_kind, + const LogViewXdrStandardType::E_DynArraySizeMethod a_dynArraySizeMethod = LogViewXdrStandardType::e_DynArrayMsgLength, + const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian); + + + + QString removeComments(const QString& a_line); + + + + void parseTypedef(const QString &a_line); + + + + void parseDefine(const QString &a_line); + + + + void parseEnum(const QString &a_line, const uint16_t a_enumSize = 4); + + + + void parseStruct(const QString &a_line); + + + + void parseUnion(const QString& a_line); + + + + bool parseEnumLine(const QString& a_line, QString& a_name, QString& a_value) const; + + + + void showErrorMessage(const QString& a_errorText) const; + + + + int64_t calcValue(const QString& a_calcText, bool& a_isOk); + + + + bool getVariableValue(const std::string& a_variableName, int64_t& a_value) const override; + + + + uint16_t parseArray(QString& a_name, uint16_t& a_dynArrayMsgOffset) const; + + + + bool isNextWord(const char *a_word, const bool a_doIncrement = true); + + + + void fillWordList(const QString& a_line); + + + + QString getNextWord(const char *a_errorText = nullptr); + + + + QString getNextType(bool& a_ok); + + + + QString getNextEnum(const LogViewXdrStruct*& a_enumStruct); + + + + bool parseBitfield(const QString& a_fieldText, int16_t& a_firstBit, int16_t& a_lastBit) const; + + + + bool addToElementMap(const QString& a_name, LogViewXdrElement* a_element); + + private: + + + NGL::INGLLogger &m_logger; + + }; + +} diff --git a/TetraIF/LogView/LogViewXdrStandardType.cpp b/TetraIF/LogView/LogViewXdrStandardType.cpp new file mode 100644 index 000000000..b5dd4bb3f --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStandardType.cpp @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + +#include "LogViewXdrStandardType.hpp" + +namespace N_LogView +{ + + + + + +LogViewXdrStandardType::LogViewXdrStandardType(const QString& a_name, const int a_valueSize, + const int a_editSize, const E_ValueKind a_valueKind, + const E_DynArraySizeMethod a_dynArraySizeMethod, E_ByteOrder a_byteOrder) + : LogViewXdrElement(a_name, e_KindStandardType, "LogViewXdrStandardType") + , m_ValueSize(a_valueSize) + , m_EditSize(a_editSize) + , m_ValueKind(a_valueKind) + , m_ByteOrder(a_byteOrder) + , m_DynArraySizeMethod(a_dynArraySizeMethod) +{} + + + +uint16_t LogViewXdrStandardType::getValueSize() const +{ + return m_ValueSize; +} + + +LogViewXdrStandardType::E_ValueKind LogViewXdrStandardType::getValueKind() const +{ + return m_ValueKind; +} + + + +void LogViewXdrStandardType::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName() + << "]: kind=" << getKindName() + << " valueKind=" << getValueKind() + << " valueSize=" << getValueSize() + << " editSize=" << getEditSize() + << " dynArrSizeMethod=" << getDynArraySizeMethod() + << " byteOrder=" << getByteOrder(); +} + + +LogViewXdrStandardType::E_DynArraySizeMethod LogViewXdrStandardType::getDynArraySizeMethod() const +{ + return m_DynArraySizeMethod; +} + + + +LogViewXdrStandardType::E_ByteOrder LogViewXdrStandardType::getByteOrder() const +{ + return m_ByteOrder; +} + + + + + + +uint16_t LogViewXdrStandardType::getEditSize() const +{ + return m_EditSize; +} + +} diff --git a/TetraIF/LogView/LogViewXdrStandardType.hpp b/TetraIF/LogView/LogViewXdrStandardType.hpp new file mode 100644 index 000000000..29a75ffa5 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStandardType.hpp @@ -0,0 +1,117 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewXdrElement.hpp" + +namespace N_LogView +{ + + + class LogViewXdrStandardType final : public LogViewXdrElement + { + public: + + + + enum E_ValueKind + { + + + e_Unsigned, + + + e_Signed, + + + e_Float, + + + e_Character, + + + e_Boolean, + + + e_Data + }; + + + + enum E_ByteOrder + { + e_ByteOrderBigEndian, + e_ByteOrderLittleEndian + }; + + + + enum E_DynArraySizeMethod + { + + + e_DynArrayMsgLength, + + + e_DynArrayIndex, + + + e_DynArrayIndexDiv8 + }; + + + + LogViewXdrStandardType(const QString &a_name, + const int a_valueSize, + const int a_editSize, + const E_ValueKind a_valueKind, + const E_DynArraySizeMethod a_dynArraySizeMethod, + E_ByteOrder a_byteOrder); + + + uint16_t getValueSize() const; + + + LogViewXdrStandardType::E_ValueKind getValueKind() const; + + + void dump() const override; + + + LogViewXdrStandardType::E_DynArraySizeMethod getDynArraySizeMethod() const; + + + LogViewXdrStandardType::E_ByteOrder getByteOrder() const; + + + + uint16_t getEditSize() const; + + protected: + + + + int m_ValueSize; + + + int m_EditSize; + E_ValueKind m_ValueKind; + + E_ByteOrder m_ByteOrder; + + E_DynArraySizeMethod m_DynArraySizeMethod; + + }; + +} diff --git a/TetraIF/LogView/LogViewXdrStruct.cpp b/TetraIF/LogView/LogViewXdrStruct.cpp new file mode 100644 index 000000000..b497f4222 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStruct.cpp @@ -0,0 +1,105 @@ + + + + + + + + + + + + + +#include "LogViewXdrStruct.hpp" +#include "LogViewXdrValue.hpp" +#include "LogViewXdrType.hpp" + +namespace N_LogView +{ + + +LogViewXdrStruct::LogViewXdrStruct(const QString& a_name, const LogViewXdrElement::E_ElementKind a_kind, uint16_t enumSize) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrStruct") + , m_EnumSize(enumSize) +{ +} + +LogViewXdrStruct::~LogViewXdrStruct() +{ + for (auto ptr : m_ChildList) + delete ptr; +} + + + +void LogViewXdrStruct::addElement(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast) +{ + m_ChildList.push_back(new LogViewXdrType(a_name, a_type, a_arraySize, a_dynArrayOffset, a_kind, a_firstBit, a_lastBit, a_isLast)); +} + + +void LogViewXdrStruct::addElement(const QString& a_name, const uint32_t a_value, const E_ElementKind a_kind) +{ + m_ChildList.push_back(new LogViewXdrValue(a_name, a_value, a_kind)); +} + + + +LogViewXdrElement* LogViewXdrStruct::getChild(const uint32_t a_childIndex) const +{ + if (m_ChildList.size() > a_childIndex) + return m_ChildList[a_childIndex]; + + return nullptr; +} + + + +LogViewXdrType* LogViewXdrStruct::getChildAsType(const uint32_t a_childIndex) const +{ + return static_cast(getChild(a_childIndex)); +} + + + +LogViewXdrValue* LogViewXdrStruct::getChildAsValue(const uint32_t a_childIndex) const +{ + return static_cast(getChild(a_childIndex)); +} + + + +void LogViewXdrStruct::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName().toStdString() << "]: kind=" << getKindName().toStdString() << " enumSize=" << getEnumSize(); + INFO_LOG(m_logger) << "-------------- childs start -----------------"; + + std::vector::const_iterator iter = m_ChildList.begin(); + while (iter != m_ChildList.end()) + { + (*iter)->dump(); + ++iter; + } + INFO_LOG(m_logger) << "-------------- childs end -----------------"; +} + + +uint32_t LogViewXdrStruct::getChildValue(const QString& a_name, bool* a_error) const +{ + if (a_error) + *a_error = false; + std::vector::const_iterator iter = m_ChildList.begin(); + while (iter != m_ChildList.end()) + { + if ((*iter)->getName() == a_name) + return static_cast(*iter)->getValue(); + ++iter; + } + if (a_error) + *a_error = true; + return 0; +} + +} + diff --git a/TetraIF/LogView/LogViewXdrStruct.hpp b/TetraIF/LogView/LogViewXdrStruct.hpp new file mode 100644 index 000000000..8faa4ed14 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStruct.hpp @@ -0,0 +1,60 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "LogViewXdrElement.hpp" +#include + + +namespace N_LogView +{ + class LogViewXdrValue; +} +namespace N_LogView +{ + class LogViewXdrType; +} + +namespace N_LogView +{ + + + class LogViewXdrStruct final : public LogViewXdrElement + { + public: + LogViewXdrStruct(const QString& a_name, const LogViewXdrElement::E_ElementKind a_kind, uint16_t enumSize = 0); + ~LogViewXdrStruct(); + + void addElement(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit = -1, const int16_t a_lastBit = -1, const bool a_isLast = true); + void addElement(const QString& a_name, const uint32_t a_value, const E_ElementKind a_kind); + + LogViewXdrElement* getChild(const uint32_t a_childIndex) const; + LogViewXdrType* getChildAsType(const uint32_t a_childIndex) const; + LogViewXdrValue* getChildAsValue(const uint32_t a_childIndex) const; + + + void dump() const override; + + uint32_t getChildValue(const QString& a_name, bool* a_error = nullptr) const; + uint16_t getEnumSize() const { return m_EnumSize; } + + protected: + + uint16_t m_EnumSize; + std::vector m_ChildList; + + }; + +} diff --git a/TetraIF/LogView/LogViewXdrType.cpp b/TetraIF/LogView/LogViewXdrType.cpp new file mode 100644 index 000000000..c4a4b05c5 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrType.cpp @@ -0,0 +1,106 @@ + + + + + + + + + + + + + +#include "LogViewXdrType.hpp" + +namespace N_LogView +{ + + +LogViewXdrType::LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrElement") + , m_Type(a_type) + , m_ArraySize(a_arraySize) + , m_MaxArraySize(a_dynArrayOffset) + , m_FirstBit(-1) + , m_LastBit(-1) + , m_IsLast(true) +{ +} + + + +LogViewXdrType::LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrType") + , m_Type(a_type) + , m_ArraySize(a_arraySize) + , m_MaxArraySize(a_dynArrayOffset) + , m_FirstBit(a_firstBit) + , m_LastBit(a_lastBit) + , m_IsLast(a_isLast) +{ +} + + + +void LogViewXdrType::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName() + << "]: kind=" << getKindName() + << " type=" << getType() + << " arraySize=" << getArraySize() + << " maxArraySize=" << getMaxArraySize() + << " firstBit=" << m_FirstBit + << " lastBit=" << m_LastBit + << " isLast=" << m_IsLast; +} + + + +const QString& LogViewXdrType::getType() const +{ + return m_Type; +} + + + + + + +uint16_t LogViewXdrType::getArraySize() const +{ + return m_ArraySize; +} + + + +bool LogViewXdrType::maskValue(uint32_t& a_value, const uint16_t a_size, QString& a_tooltip) const +{ + + if (m_FirstBit != -1 && m_LastBit != -1) + { + DEBUG_LOG(m_logger) << "MaskValue for Element " << m_Name + << " type: " << m_Type + << " size: " << m_ArraySize + << " first:last " << m_FirstBit << ":" << m_LastBit + << " isLast: " << m_IsLast; + uint16_t bitshift = (a_size*8)-m_LastBit-1; + uint32_t mask = (1<<(m_LastBit-m_FirstBit+1))-1; + + a_value = (a_value >> bitshift) & mask; + + a_tooltip.insert(a_tooltip.length()-(a_size*8)+m_FirstBit, QLatin1String("")); + a_tooltip.insert(a_tooltip.length()-(a_size*8)+m_LastBit+1, QLatin1String("")); + return m_IsLast; + } + return true; +} + + + +uint16_t LogViewXdrType::getMaxArraySize() const +{ + return m_MaxArraySize; +} + +} diff --git a/TetraIF/LogView/LogViewXdrType.hpp b/TetraIF/LogView/LogViewXdrType.hpp new file mode 100644 index 000000000..a189f3764 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrType.hpp @@ -0,0 +1,72 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewXdrElement.hpp" + +namespace N_LogView +{ + + + class LogViewXdrType final : public LogViewXdrElement + { + public: + + + + LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind); + + + + LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast); + + + void dump() const override; + + + const QString& getType() const; + + + + uint16_t getArraySize() const; + + + + bool maskValue(uint32_t& a_value, const uint16_t a_size, QString& a_tooltip) const; + + + uint16_t getMaxArraySize() const; + + protected: + + QString m_Type; + + + uint16_t m_ArraySize; + + + uint16_t m_MaxArraySize; + + + int16_t m_FirstBit; + + + int16_t m_LastBit; + + + bool m_IsLast; + }; + +} + diff --git a/TetraIF/LogView/LogViewXdrValue.cpp b/TetraIF/LogView/LogViewXdrValue.cpp new file mode 100644 index 000000000..70e8a2b93 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrValue.cpp @@ -0,0 +1,40 @@ + + + + + + + + + + + + + +#include "LogViewXdrValue.hpp" + + +namespace N_LogView +{ + + +LogViewXdrValue::LogViewXdrValue(const QString& a_name, const int64_t a_value, const LogViewXdrElement::E_ElementKind a_kind) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrValue") + , m_Value(a_value) +{} + + + +void LogViewXdrValue::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName() << "]: kind=" << getKindName() << " value=" << getValue(); +} + + + +int64_t LogViewXdrValue::getValue() const +{ + return m_Value; +} + +} diff --git a/TetraIF/LogView/LogViewXdrValue.hpp b/TetraIF/LogView/LogViewXdrValue.hpp new file mode 100644 index 000000000..db8eec061 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrValue.hpp @@ -0,0 +1,34 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewXdrElement.hpp" + +namespace N_LogView +{ + + + class LogViewXdrValue final : public LogViewXdrElement + { + public: + LogViewXdrValue(const QString& a_name, const int64_t a_value, const LogViewXdrElement::E_ElementKind a_kind); + + void dump() const override; + int64_t getValue() const; + + protected: + + int64_t m_Value; + }; +} diff --git a/TetraIF/LogView/LogView_log4cxx.props b/TetraIF/LogView/LogView_log4cxx.props new file mode 100644 index 000000000..195ca75b0 --- /dev/null +++ b/TetraIF/LogView/LogView_log4cxx.props @@ -0,0 +1,17 @@ +log4j.reset=true +log4j.rootLogger=INFO, C +log4j.rootLogger=INFO, F + +log4j.appender.C=org.apache.log4j.ConsoleAppender + +log4j.appender.F=org.apache.log4j.RollingFileAppender +log4j.appender.F.File=${LOG4QT_LOGDIR}/${LOG4QT_USER}_LogView.log + +log4j.appender.F.MaxFileSize=10MB +# Keep one backup file +log4j.appender.F.MaxBackupIndex=5 + +log4j.appender.C.layout=org.apache.log4j.PatternLayout +log4j.appender.F.layout=org.apache.log4j.PatternLayout +log4j.appender.C.layout.ConversionPattern=%-5p (%-20.20F:%04L) [%d{HH:mm:ss.SSS}] - %m%n +log4j.appender.F.layout.ConversionPattern=%-5p (%-20.20F:%04L) [%d{HH:mm:ss.SSS}] - %m%n diff --git a/TetraIF/LogView/image/C2P.png b/TetraIF/LogView/image/C2P.png new file mode 100644 index 0000000000000000000000000000000000000000..90b92e69fbd45397efa428772e0848cf86c4f5f0 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONaEqslV~B_M+i9l-8x(k4j{dT_*<*TxM}77N zE!jB-9nYpSKdLye`lOwZS>X1crLXNO=CI5BW}o&|lizRCfh`fG38su+9JD-yo%n=Ij@;MH5_lZv!Wej% f$7vgb=w{|=+a1C+zS$-M-Ou3Z>gTe~DWM4f{#0vz literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/Central.png b/TetraIF/LogView/image/Central.png new file mode 100644 index 0000000000000000000000000000000000000000..ba118da38113bf000b7312f2fcba4070e2538f00 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI83?wJF-0KBWYymzYt{n`b|JR+2c^>Ww6yYrJ zh%9Dc5Gny-#(Qb<6+l7u5>H=O_Qz~2JZdZx`{k8@LOz}@jv*Y^lYjjG|DUn#|9rVS!dqU_M?un0LCRlII#5YENJ%C{Ste9PCR{}}LRBtOO)gqZ zK2}{mPF*2ELm^R9Az4!~OgpwLo93&_J!&K)uvZz063X z!bqdqShL1Nv(8kj-c-BMOuNZkr`cSm)k3%3Qn$lWugglm*IK{N#$bYt!9-ibDRxFP z9gOEVn#^@FUEplC$i;lAtNAiFi`5>M>pZPDdE4#wx8Lh;zc0XHf1vY$5YI!A-iM=o z4#xx?O$LZ~ZUVi{SQ6wH%;50sMjDXAS>O>_%)r1c48n{I zv*t(u1=&kHeO=ifv$61K%DpcAH618)*VDx@MB;LC!UE=m6egw;M>S7t{dj+A&NPw0 zH16_R&qTx6@M5u)z+m=3c6)hsUPWo|Z~7?W6|V{cJu{&W1Q2ym|QW z(SttC{;u<-)y_OpP|8Zm%*Y7MN?TNHI?J?cQ99q_C6I2H4PDc zTAK26;-ABs`K#70Ted7!<8ww&9Dykug(@9}D;LI48C`C%8K(yF4hpJSo6EDZ)M~!#*m-KP$#RE66}A%0Mj3K`hNd zEzm+Q(nT@SMmEz+IMYly)J{CrQ9jjDK-E-1)>TE;SW4GjP1s*g*kMxHWK-H@SK4S; z+iG3hZerbYX5Dsg;C^%9fpp=6c;SY7;)#9Yih|>hgXEBi<&=-+nwsgQqPe`x00001 zbW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA00(qQO+^Re1_TT#BrSO(B>(^b z&`Cr=R2b8}k;x8%KoCR~6c-l3R)%Ro95+zJUDQ!r|No!V1Grs{b?M}#)2XV?Wd5M+ zLtn7AJe=b>2yavv@B6h%wZ}v8l?IU!T}~UO&At2+s~e49ujk#Op{^8`(0ssf8^=5v zG1=*t5-di#F`P_7&jqzIO|J-RO$Uk=fT3&C)Mai42AG5p^FD{^cDdaGlTxJAgoXnN zUMXRnpzYX5>b`tT4azv6*knzlT}ye%Q=mcDb={6wEEhkz;vfkU@Si^A Y2G~v%eu0zQq5uE@07*qoM6N<$f;iif8y9DFncr!)AfH%)Nt zXk%4mcFLbLjm7iWo#ux&krP;zRJ|SI6=dEpYB4TM5DXET)ZDq={EI2mBJMBlv&vWP z>by|PYBI&+P)^axsMkyKcIA~$^V%|Rn#b*kE8Ab43QxZ&Hi!M+T_g9Mz3g@u%nXg{ S61D@~%;4$j=d#Wzp$Py@hh@6} literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/P2T.png b/TetraIF/LogView/image/P2T.png new file mode 100644 index 0000000000000000000000000000000000000000..55ad4fd229865f0dc3484b8c87387285b8dcd744 GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONaI2?_V~B@$@||Bk-|U%X8IK8aYhp+J9d7QTeF2hoh>S| zDaWifSa#o`2{RrXT+XKYLc_F2;_rtAi(A)EIP21>oE6oUC+3#4pe^;rnFF(4X>8<~ z9yjOYY?;$1R-JOx>=Zf8u~KzLBB!Lonr4nDmlFy}GE7Fy`NiDPZY@*0k3=yTH>Y%W fXtHit$;hCTWU2UK3Exhj2N*nE{an^LB{Ts5VK`-O literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/P2W.png b/TetraIF/LogView/image/P2W.png new file mode 100644 index 0000000000000000000000000000000000000000..025c2a1f08aa0414de449ea06c9be0e53afce4e4 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI83?wJF-0KBWYymzYt_(u|J68U`v-svopa^Gy zM`SSrgHQUln~ zOZ+qVAnY%bz_5sojg6gy@mW(RJ5LY0gq?wbe8P`|2lzsH%>LOo+fK+>!7jw!5ccms dk5a=lW`+=66UBJuh76#g44$rjF6*2UngCLbHWL5< literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/RedLamp.png b/TetraIF/LogView/image/RedLamp.png new file mode 100644 index 0000000000000000000000000000000000000000..e91a5d68cee7168c84d3c9695ca0992e07931365 GIT binary patch literal 801 zcmV++1K#|JP)~&uNN1w7Z=JA5yuh|vKSc06BEl462}x2 z%M%mF6&24E6v-AA$rl&P7Z=DF7}6FN&lniV8XB`8Akr8Z&lwrAAtAFNA=MZd))*Mj z8XB}BBGwrh*BKeg9Ua&k8`>Ki+#DR;9Ua&oAKo4w$Rs4!AtBx%AlV`!;UFO5ARx*o zC*mO?%qJ(%CMM${A><(;)Fvj$DJje;Ddr<1&?za%EG*3{E9fL7)G8|JB_--6Cg>+8 z)+{X0FE7q8FrGaoYv**ZGm zI5^%qI@dox=Q}&mK|$j^JU)*M9-)3gZY;4V!Z0d!JMQvg8b*k%9# z010qNS#tmY3ljhU3ljkVnw%H_000McNliru;|2r_C=-m|w`%|Z0OCnRK~xyiV_={I zU}R-tWkwfdF{|sJ)K_i9jv~rY+LL6ds+-tV$b}@zUeK)7JY`~AlyXfPKSEfcRk3T@ z)XCkoe)9FQ(J)b-{3wt1-rkPJqDZNrWKozfXOo6zc3F8zYKV@UdL=JRn5{)cP2bVk z&caw*O{szvCd^%Bs%>sHjWDsccX4;Iw>I$!G=vE^NEch#y7~wE zyV_c1h);k!P|`Qc$tyG_)Y~b+K?cb`LT-8S;bGx%=?;P@z897V$jnLc6cI)Xt4<>U fHUYg(szwR`%6>ES|2H@p00000NkvXXu0mjfDHJ%1 literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/ShowSend.png b/TetraIF/LogView/image/ShowSend.png new file mode 100644 index 0000000000000000000000000000000000000000..77e048608ac22e23a9bfe5f0c2bb8ff7068930c0 GIT binary patch literal 382 zcmV-^0fGLBP)OVY$o(#28J#ZuG8RMW;* z)yP`a$zImVU)IWDjn)|`00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA z00(qQO+^Re1_TT#7y=ewq5uE@j7da6R4C82k=qi2AP|Pp#XJ;+qJrDO%FOqFLmgD0 z8M)}f?{dGHJ^h620)S5(sYeVPJYo>=+k1w7@4a*lygr)#-C(DvD{iQ1CY~5s(dyE| z17jnub?Ja=odfdBEQLyqC>@c@#4H9yHIq+uaj*-A3sf-9qpi#Ng>8Nd*va#&Ec`Q% cV4wWS2p*OS{$8+3?*IS*07*qoM6N<$f*%W`w*UYD literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/T2P.png b/TetraIF/LogView/image/T2P.png new file mode 100644 index 0000000000000000000000000000000000000000..3cb53c5c3bfb60a4c081e951f239f8db07d68fd6 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONaJ8q4V~B@$a>%V0pXWF7HFSnptIdu}VMq*O zRNiQJD7E5UX6>RkDyQ6k)Htkp&k^O)<9KAn!E8Z8wgZQHCq&H=6TH-+oAlx3!7M?` zX#$@l+gztaG@UmR>0Xh@sdxH;Sm0%$oN0nS_gtR3DTy@dE^5ucQ0p2mFBlysDCi{N zm5}yWC*&lrUrgV!{0kF>RhGPx{3^IokuBU_s^kj4Rgo8WO;tx;-o&?}E8H0N8JJiu Td8ii+bT)&htDnm{r-UW|4b)&I literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/TNE.png b/TetraIF/LogView/image/TNE.png new file mode 100644 index 0000000000000000000000000000000000000000..52f583bf33e5dc637541af271b4133d9dc0994ee GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONaFVBsV~B@$@|?=gSL@lh9Dbdwm)Mm)%Q&$k zu}dIR^8{0hw?o@uodao>H^mO#Y0hEv;F+E8@F*pcrPxr<+40efeM+a5lAOfv3Yu)@ zxNBIlxkGT;o{dXIoE%%U`!>8}{@o$t&0(2zps6pf&?HN6WhTSAI+GV}&3Pt<6XvqD tRbQAG)Tp?<&Vw_cg4erCt>_99!>^U9-G8E190j_L!PC{xWt~$(696A4Rx$tp literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/Tetra.png b/TetraIF/LogView/image/Tetra.png new file mode 100644 index 0000000000000000000000000000000000000000..9dc5412a866da55dead1d0599ea4a44a4ced3b1f GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTON@Pwy}V~B_M+iAOb8w_|{n5zw#MUxGAHyf~u zdT(IUa8(h?xo^23#AVT;eaC+aUtD{nmN-sejqeP}6-H^EFu( zLnoge&Lozgy8&ysoH~P&*T@KlFgu=;TVO80J*{zHLxw?d|DJ^Gi literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/image/Wls.png b/TetraIF/LogView/image/Wls.png new file mode 100644 index 0000000000000000000000000000000000000000..61410b000604442c8df9af559985d99dc31a5432 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI83?wJF-0KBWYymzYt_(u|J68U`v-svopa^Gy zM`SSrgHQAKDxLGaTk;`^L;8FENAPz$PJ~#p{8}0j~pH2X7riMSQUaPTDyQxXLxml;RRj0jOx1&S1t4pu9SHG`Mf5HTVi4zT`Ofj4} z(`e2d6D8XODC znI;mL#$8_PnP?arUM!Xp7|b5XZZEISt0>J}*0P~t@`CJ!{p)A1oz!5vpUr2=*%0T0 zHxC~^deEoY-*vvU+L=cRN?A#nnRzSJ^b~TAvYFos^l*vsa}0BG3URr>_0B6Sn=_Cz zQ&LhglQXbTc*k6uS+9gH6@BXZRCGzmOY4zAVs%}yrX*{sXez6urgB{V4(3YH-lw9W zrXiwFOH+PM{Bu|{f7RM$%a)~ToNjzntrwT79Bk_b8kdhyglpmFsAeWgSnVTS|sU)eZB&@C_uCOJsvnI2(CbqaIx4I{}yeGT8 zD8Rxg!Ne)V$129jD#*$!%g!s!&n(Z6+>4o$2bI>Fc2C>!j=Kr|j*l?(eh@XKz9P z0004WQchC z0002iNklbVR)w_8=c$>%6}s<~5PlFjEu8dDoD^rrQPgDDSu0D^mqCZ)av0v=<`146TACVClx z$GPC#gF!@VF0G=^f-njL)=$yC35djui=i9}KJl%KeY!j!$8r3c`o`7vCJNI$5y-r` hl>$REsQTBZ`~tS~6>iLQ-9rEX002ovPDHLkV1m3a2%!J~ literal 0 HcmV?d00001 diff --git a/TetraIF/LogView/logger.cpp b/TetraIF/LogView/logger.cpp new file mode 100644 index 000000000..8790cc277 --- /dev/null +++ b/TetraIF/LogView/logger.cpp @@ -0,0 +1,32 @@ + + + +#include "logger.h" + +#include + +namespace N_LogView +{ + +LOGGER_T getLogger(const char *name) +{ + static const char ns[] = "LogView."; + std::string loggerName; + const size_t len = strlen(name); + loggerName.reserve(sizeof(ns) + len); + loggerName.append(ns, sizeof(ns) - 1); + loggerName.append(name, len); + + try + { + return NGL::NGLLoggerBootstrap::getNGLRootLogger(). + getNGLLogger(loggerName); + } + catch (const std::exception &ex) + { + fprintf(stderr, "Error retrieving logger: %s", ex.what()); + abort(); + } +} + +} diff --git a/TetraIF/LogView/logger.h b/TetraIF/LogView/logger.h new file mode 100644 index 000000000..8baf71f9f --- /dev/null +++ b/TetraIF/LogView/logger.h @@ -0,0 +1,17 @@ + + + +#pragma once + +#include + +namespace N_LogView +{ +typedef NGL::INGLLogger &LOGGER_T; + +LOGGER_T getLogger(const char *name); +inline LOGGER_T getLogger(const QString &loggerName) +{ + return getLogger(loggerName.toUtf8().constData()); +} +} diff --git a/TetraIF/LogView/zsksxd_tetraForLogView.cpp b/TetraIF/LogView/zsksxd_tetraForLogView.cpp new file mode 120000 index 000000000..e088a4ab5 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView.cpp @@ -0,0 +1 @@ +zsksxd_tetraForLogView.x \ No newline at end of file diff --git a/TetraIF/LogView/zsksxd_tetraForLogView.x b/TetraIF/LogView/zsksxd_tetraForLogView.x new file mode 100644 index 000000000..49504acd8 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView.x @@ -0,0 +1,1834 @@ +/* +const MAX_LAENGE_GEFECHTSFELDTELEGRAMM = 2000; +*/ + +/*-------------------------------*/ +/* Telegramm-ID's */ +/*-------------------------------*/ + +enum8 gef_telegramm_id_et { + + GEF_BESTAETIGUNG = 0, + + GEF_INIT = 1, + GEF_MANIPULATIONSMELDUNG = 2, + GEF_UMGEBUNGS_MELDUNG = 3, + GEF_UMGEBUNGS_MELDUNG2 = 203, + GEF_AUFFORDERUNG_BITE_MELDUNG = 4, + GEF_BITE_MELDUNG = 5, + GEF_BITE_MELDUNG2 = 205, + + GEF_LIZENSIERUNG_TNE = 6, + GEF_BETRIEBSZUSTAND_AUSSTATTUNG = 7, + GEF_KONFIGURATION_TEILNEHMER = 8, + GEF_KONFIGURATION_WIRKMODELL = 9, + GEF_ANFORDERUNG_KONFIGURATIONSDATEN = 10, + GEF_KONFIGURATIONSMELDUNG = 11, + GEF_FEHLERMELDUNG_GFD = 12, + + GEF_POSITIONS_MELDUNG = 21, + GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER = 22, + GEF_POSITIONS_MELDUNG_LFZ = 23, + GEF_POSITIONSKORREKTURDATEN = 24, + + GEF_WIRKFELD_EINZELGESCHOSS = 31, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER = 32, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP = 33, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN = 34, + GEF_WIRKFELD_MINENSPERRE = 35, + GEF_WIRKFELD_STATUS_MINENSPERRE = 36, + GEF_WIRKFELD_A_KAMPFMITTEL = 37, + GEF_WIRKFELD_C_KAMPFSTOFF = 38, + GEF_DEAKTIVIERUNG_WIRKFELD = 39, + GEF_WIRKFELD_AENDERUNG_BEZEICHNER = 40, + GEF_DEAKTIVIERUNG_EINZELMINE = 41, + GEF_REAKTIVIERUNG_DUS_MINE = 42, + GEF_DEFINITION_IED = 43, + GEF_ZUSTAND_IED = 44, + GEF_STATUS_EINZELMINENSIMULATOR = 45, + GEF_WIRKFELD_EINZELMINENSIMULATOR = 46, + + GEF_FEUER_EREIGNIS = 51, + GEF_TREFFER_EREIGNIS_DUS = 52, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION = 53, + GEF_TREFFER_AUSLOESUNG = 54, + GEF_SCHIEDSRICHTEREINGRIFF = 55, + GEF_SELEKTIVE_AUFMUNITIONIERUNG = 56, + + GEF_TREFFER_EREIGNIS_DUS_IPS = 228, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS = 229, + + GEF_TAKTISCHER_STATUS = 61, + GEF_FUNKTIONSRAUM = 62, + GEF_EINTRETEN_FUNKTIONSRAUM = 63, + GEF_DEAKTIVIEREN_FUNKTIONSRAUM = 64, + + GEF_DATENVERKEHR_SRT_TDS = 71, + GEF_DATENVERKEHR_TDS_SRT = 72, + GEF_DATENVERKEHR_DMF_TDS = 73, + GEF_DATENVERKEHR_TDS_DMF = 74, + + GEF_STEUERUNG_VERKEHRSAUFKOMMEN = 81, + GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME = 82, + GEF_NOP = 83, + + GEF_SONDERSENSORIK_BETRIEBSZUSTAND = 91, + GEF_SONDERSENSORIK_FAHRSPUR = 92, + GEF_SONDERSENSORIK_DATEN = 93, + GEF_SONDERSENSORIK_TREFFER_AUFGES_TLN = 94, + GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN = 95, + GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN = 96, + GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION = 97, + + GEF_SPRACHAUSWAHL = 101, + GEF_ALLGEMEINE_NACHRICHT = 102, + GEF_ECHO_ON_OFF = 103, + GEF_ESW_MELDUNG = 104, + + GEF_WF_SAMMELDEAKTIVIERUNG = 105, + GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN = 106, + GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM = 107, + + GEF_DATENVERKEHR_GEOP_TDS = 181, + GEF_DATENVERKEHR_TDS_GEOP = 182, + + GEF_DATENVERKEHR_TGTS_TDS = 183, + GEF_DATENVERKEHR_TDS_TGTS = 184, + GEF_GERAETEEREIGNIS = 185, + + GEF_WAFFENZUORDNUNG = 200, + GEF_IPS_POSITIONSDATEN = 201, + GEF_STANDORTBESTIMMUNG = 25, + GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE = 202, + GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG = 210, + GEF_AUSLOESUNG_DUS_TREFFER = 211, + GEF_ANFORDERUNG_SW_VERSION = 212, + GEF_SW_VERSIONSMELDUNG = 213, + + GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG = 218, + GEF_TECHNIK_FUNKTIONSRAUM = 219, + GEF_ANFORDERUNG_KONFIG_ZEG = 220, + GEF_KONFIGURATION_IPS = 221, + GEF_KONFIGURATION_ZEG = 222, + GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG = 223, + GEF_TREFFEREREIGNIS_GEBAEUDE = 224, + + GEF_TEILNEHMERMODE_SETZEN = 230, + GEF_TEILNEHMERMODE_MELDUNG = 231, + GEF_TEILNEHMERMODE_ANFORDERN = 232, + GEF_TEILNEHMER_KONFIG_ANTWORT = 233, + GEF_TEILNEHMER_KONFIG_SETZEN = 234, + GEF_TEILNEHMER_KONFIG_ANFORDERN = 235, + + GEF_SANITAETSDIENST_INSTANDSETZUNG = 240, + GEF_BESTANDSMELDUNG_SANITAETSMATERIAL = 241, + GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN = 242, + + GEF_GEFECHTSFELDTELEGRAMM = 300, + GEF_UEBERLAST_WARNUNG_ENTWARNUNG = 301, + GEF_DATENFUNK_INIT = 302, + GEF_DATENFUNK_EXIT = 303, + GEF_DATENFUNK_EXIT_ACKNOWLEDGE = 304, + GEF_ZUORDNUNG_GRUPPENRUFADRESSE = 305, + GEF_NOTRUF = 1120, + GEF_LASER_TARGET_DESIGNATOR_UPDATE = 214 + +}; + + +/*==============================================================*/ +/* Strukturtypen, die mehrfach verwendet werden */ +/*==============================================================*/ + +/*---------------------------------------*/ +/* Identifikation */ +/*---------------------------------------*/ + +typedef UInt16 gef_ausstattungs_id_t; + + +/*---------------------------------------*/ +/* Header */ +/*---------------------------------------*/ + +struct gef_header_rt { + gef_ausstattungs_id_t identitaet; +}; + + +/*---------------------------------------*/ +/* GPS-Zeit */ +/*---------------------------------------*/ + +struct gef_gps_zeit_rt { + u_int GPS_zeit; +}; + + +/*---------------------------------------*/ +/* GPS-Position */ +/*---------------------------------------*/ + +struct gef_gps_position_rt { + SInt24 nordwert; + SInt24 ostwert; +}; + + +/*---------------------------------------*/ +/* Lastzustand Datenfunk */ +/*---------------------------------------*/ + +enum8 gef_lastzustand_datenfunk_et { + Normallast = 0, + Hochlast = 1, + Ueberlast = 2 +}; + + +/*==============================================================*/ +/* Beschreibung der speziellen TETRA-Telegramme */ +/*==============================================================*/ + +struct TETRA_register_indication_rt { + UInt32LE ISSI_ext_host; +}; + +enum8 TETRA_registration_status_et { + ISSI_successful_registered = 0, + Duplicate_ISSI = 1, + Invalid_ISSI = 2, + Invalid_IP_address = 3 +}; + +struct TETRA_register_response_rt { + TETRA_registration_status_et registration_status; +}; + +enum8 TETRA_login_status_et { + Login_Request = 1, + Login_Accept = 2, + Login_Reject = 3 +}; + +enum8 TETRA_login_mastering_et { + No_Mastering = 0, + Mastering = 1 +}; + +enum8 TETRA_reject_cause_et { + Reserved = 0, + EqIdAlreadyAssigned = 1, + IssiAlreadyAssigned = 2, + EqIdAssignedInOtherExercise = 3 +}; + +struct TETRA_login_telegram_rt { + gef_header_rt header; + TETRA_login_status_et:0..1 login_status; + TETRA_login_mastering_et:2..2 login_mastering; + TETRA_reject_cause_et:3..6! reject_cause; +}; + +enum8 TETRA_telegram_type_et { + NotFragmented = 0, + FirstFragment = 1, + MiddleFragment = 3, + LastFragment = 2 +}; + +enum8 TETRA_fragment_counter_et { + 0 = 0, + 1 = 1, + 2 = 2, + 3 = 3, + 4 = 4, + 5 = 5, + 6 = 6, + 7 = 7, + 8 = 8, + 9 = 9, + 10 = 10, + 11 = 11, + 12 = 12, + 13 = 13, + 14 = 14, + 15 = 15 +}; + +struct TETRA_first_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + gef_telegramm_id_et telegram_id; + opaque data<28>; /* 28 => dyn.-array-offset */ +}; + +struct TETRA_middle_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_last_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_air_interface_load_report_rt { + UInt8 network_index; + UInt16LE base_station_ID; + UInt8 channel_ID; + UInt8 queue_length; +}; + +struct TETRA_status_ind_req_rt { + UInt32LE ISSI_host; + UInt32LE ISSI_destination; + UInt32LE status; +}; + +enum8 TETRA_monitor_et { + No_Monitoring = 0, + Monitoring = 1 +}; + +struct TETRA_group_monitoring_ind_rt { + UInt32LE ISSI_host; + TETRA_monitor_et monitor; + UInt16LEIdx count_gssi; + UInt32LE gssi<5>; +}; + +struct TETRA_air_interface_load_req_rt { + UInt16LEIdx number_of_reports; + TETRA_air_interface_load_report_rt air_interface_load_report<4>; +}; + +struct TETRA_unknown_PDU_rt { + UInt8 magic_number; + UInt8 counter; + UInt16LE length; + UInt8 PDU_Type; + opaque data<5>; /* 5 => dyn.-array-offset */ +}; + + +/*==============================================================*/ +/* Beschreibung der Telegramme */ +/*==============================================================*/ + +/*----------------------------------------------------------------*/ +/* Automatische Conversion */ +/*----------------------------------------------------------------*/ +/* +Alle TETRA-Meldungen, die mit der Klasse CoPrtCnvTelegramConverter in +eine Zentral-Meldung konvertiert werden, müssen trotzdem in der TETRA- +union definiert werden, damit die Telegramme Namen bekommen. +*/ + +struct gef_automatic_conversion_rt { + gef_header_rt header; + UInt8 fehler_diese_meldung_sollte_automatisch_konvertiert_werden; +}; + + + +/*----------------------------------------------------------------*/ +/* Init-Meldung */ +/* INIT_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_tln_aufmunitionieren_et { + tln_am_nein = 0, + tln_am_ja = 1 +}; + +enum8 gef_tln_zuruecksetzen_et { + tln_zs_nein = 0, + tln_zs_ja = 1 +}; + +enum8 gef_tln_manipulation_et { + tln_mp_nein = 0, + tln_mp_reset = 1 +}; + +enum8 gef_tln_medizinische_vorraete_auffuellen_et { + tln_mv_nein = 0, + tln_mv_reset = 1 +}; + +/* MSB = 0 ... */ +struct gef_initialisierungsdaten_rt { + gef_tln_aufmunitionieren_et:2..2 tln_aufmunitionieren; + gef_tln_zuruecksetzen_et:1..1 tln_zuruecksetzen; + gef_tln_manipulation_et:7..7 tln_manipulation; + gef_tln_medizinische_vorraete_auffuellen_et:6..6 tln_mediziniesche_vorraete_auffuellen; +}; + +struct gef_init_meldung_rt { + gef_header_rt header; + gef_initialisierungsdaten_rt initialisierungsdaten; +}; + + +/*----------------------------------------------------------------*/ +/* Umgebungs-Meldung */ +/* UMGEBUNGS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_uebungspause_et { + KEINE_UEBUNGSPAUSE = 0, + B_MIT_TEST = 1 +}; + +enum8 gef_inhbit_time_et { + IH_UNDEFINED = 0, + IH_1_SEKUNDE = 1, + IH_2_SEKUNDEN = 2, + IH_3_SEKUNDEN = 3, + IH_4_SEKUNDEN = 4, + IH_5_SEKUNDEN = 5, + IH_6_SEKUNDEN = 6, + IH_7_SEKUNDEN = 7, + IH_8_SEKUNDEN = 8, + IH_9_SEKUNDEN = 9, + IH_10_SEKUNDEN = 10, + IH_11_SEKUNDEN = 11, + IH_12_SEKUNDEN = 12, + IH_13_SEKUNDEN = 13, + IH_14_SEKUNDEN = 14, + IH_15_SEKUNDEN = 15, + IH_16_SEKUNDEN = 16, + IH_17_SEKUNDEN = 17, + IH_18_SEKUNDEN = 18, + IH_19_SEKUNDEN = 19, + IH_20_SEKUNDEN = 20, + IH_21_SEKUNDEN = 21, + IH_22_SEKUNDEN = 22, + IH_23_SEKUNDEN = 23, + IH_24_SEKUNDEN = 24, + IH_25_SEKUNDEN = 25, + IH_26_SEKUNDEN = 26, + IH_27_SEKUNDEN = 27, + IH_28_SEKUNDEN = 28, + IH_29_SEKUNDEN = 29, + IH_30_SEKUNDEN = 30, + IH_31_SEKUNDEN = 31 +}; + +struct gef_betriebszustaende_gefechtsfeld_rt { + gef_uebungspause_et:0..0 uebungspause; + gef_inhbit_time_et:1..5 pos_inhibit_time; + gef_lastzustand_datenfunk_et:6..7! lastzustand_datenfunk; +}; + +struct gef_basiskoordinate_zur_positionsbestimmung_rt { + UInt8 zone; + string band; + string quadrat[2]; + UInt8 ostwert; + UInt8 nordwert; +}; + +struct gef_umgebungs_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; +}; + +struct gef_umgebungs_meldung2_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; + gef_gps_zeit_rt aktuelle_zeit; +}; + + +/*----------------------------------------------------------------*/ +/* Aufforderung BITE-Meldung */ +/* AUFFORDERUNG_BITE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_bite_meldungsart_et { + NUR_STATUSABFRAGE = 0, + ERST_SELBSTTEST = 1 +}; + +struct gef_aufforderung_bite_meldung_rt { + gef_header_rt header; + gef_bite_meldungsart_et bite_meldungsart; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration Wirkmodell */ +/* GEF_KONFIGURATION_WIRKMODELL */ +/*----------------------------------------------------------------*/ + +struct gef_wirkmodell_rt { + UInt8 minen_ied; + UInt8 steilfeuer; + UInt8 einsatzmittel; + UInt8 ac_waffen; +}; + +struct gef_konfiguration_wirkmodell_rt { + gef_header_rt header; + gef_wirkmodell_rt wirkmodelle; +}; + +/*----------------------------------------------------------------*/ +/* Konfigurationsmeldung */ +/* GEF_KONFIGURATION_TEILNEHMER */ +/*----------------------------------------------------------------*/ + +struct gef_login_parameter_rt { + UInt8 wartezeit_versuche; + UInt8 anzahl_versuche; + UInt8 mastering_flag; +}; + +enum8 gef_sprache_et { + keine_aenderung = 0, + deutsch = 1, + englisch = 2, + franzoesisch = 3 +}; + +struct gef_konfiguration_abe_rt { + UInt8 sprachausgabe; + gef_sprache_et sprache; +}; + +struct gef_konfiguration_wirkdarstellung_rt { + UInt8 pyrotechnik; +}; + +enum8 gef_betriebsart_mhgr_sensorik_et { + BetriebAmAusbAusstgPers = 0, + BetriebAnSonstigenFzg = 2, + BetriebAnSrFahrzeug = 3 +}; + +struct gef_konfiguration_mhgr_sensorik_rt { + gef_betriebsart_mhgr_sensorik_et betriebsart; + UInt8 energiesparmodus; +}; + +enum8 gef_konfiguration_ss_fir_et { + keineKonfigurationFir = 0, + fir = 1, + firSpzMarder = 2 +}; + +enum8 gef_konfiguration_ss_minenverlegung_et { + keineKonfigurationMinenverlegung = 0, + MvAnh = 1, + Wmv = 2 +}; + +enum8 gef_konfiguration_ss_standard_et { + keineKonfigurationSsStandard = 0, + ZABC = 3, + CSF = 4, + PzBr = 5, + MRF = 7 +}; + +struct gef_konfiguration_sondersenoriken_rt { + gef_konfiguration_ss_fir_et fir; + gef_konfiguration_ss_minenverlegung_et minenverlegung; + gef_konfiguration_ss_standard_et standard; +}; + +enum8 gef_agdus_hw_modus_et { + ohneHelmOhneWeste = 1, + mitHelmOhneWeste = 2, + mitHelmMitWeste = 3 +}; + +enum8 gef_konfigurations_positionsupdate_et { + Fahrzeug = 0, + Person = 1, + Luftfahrzeug = 2 +}; + +struct gef_konfiguration_anzeige_rt { + UInt8 hauptgruppe; + UInt8 untergruppe; +}; + +struct gef_konfigurationsdaten_rt { + gef_ausstattungs_id_t identitaet; + UInt16 can_startup_zeit; + unsigned char teilnehmertyp; + gef_login_parameter_rt login_parameter; + UInt32LE can_geraete_konfiguration; + gef_konfiguration_abe_rt abe; + gef_konfiguration_wirkdarstellung_rt wirkdarstellung; + gef_konfiguration_mhgr_sensorik_rt mhgr_sensorik; + gef_konfiguration_sondersenoriken_rt sondersenrik; + gef_agdus_hw_modus_et agdus_hw_modus; + gef_konfigurations_positionsupdate_et positionsupdate; + gef_konfiguration_anzeige_rt anzeige; + UInt8 wirkmodellAgdus; +}; +% +struct gef_konfiguration_teilnehmer_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_konfigurationsdaten_rt konfiguration; + gef_wirkmodell_rt wirkmodelle; +}; +/*----------------------------------------------------------------*/ +/* Lizensierung TNE-Meldung */ +/* LIZENSIERUNG_TNE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_lizenzierungsart_et { + ANMELDUNG_ERFOLGREICH = 0, + ANMELDUNG_ABGELEHNT = 1, + ABMELDUNG = 2 +}; + +struct gef_lizensierung_tne_meldung_rt { + gef_header_rt header; + gef_lizenzierungsart_et lizenzierungsart; + opaque fehlercode_lizenzierung[3]; +}; + +enum8 gef_qualifikation_et { + Undefiniert = 0, + Arzt = 1, + Sanitaeter = 2, + Ersthelfer = 3 +}; + +/*----------------------------------------------------------------*/ +/* Bestandsmeldung Saniätsmaterial */ +/* GEF_BESTANDSMELDUNG_SANITAETSMATERIAL */ +/*----------------------------------------------------------------*/ +struct gef_bestandmseldung_sanitatsmaterial_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt8 anzahl_sanmat; + UInt24 bestand_sanmaterialien; +}; + + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung PVSAN */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN */ +/*----------------------------------------------------------------*/ +struct gef_sanitetsdienst_instandsetzung_pvsan_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 massnahmen_getaetigt; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt16 massnahmen_benoetigt; +}; + +/*----------------------------------------------------------------*/ +/* Technik Funktionsraum-Meldung */ +/* TECHNIK_FUNKTIONSRAUM */ +/*----------------------------------------------------------------*/ +struct gef_technik_funktionsraum_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; + UInt8 typ; + string wirkfeldbezeichner[8]; + gef_gps_position_rt zentrum; + UInt16 breite; + UInt16 hoehe; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelgeschoss-Meldung */ +/* WIRKFELD_EINZELGESCHOSS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_munitionsart_steilfeuer_et { + STEILFEUER_AZ = 1, + STEILFEUER_HE_ANNZ = 2, + STEILFEUER_BOMBLET = 3, + STEILFEUER_SM_ART = 4, + STEILFEUER_NEBEL = 5, + MOERSER_AZ = 10, + MOERSER_ANNZ = 11, + BORDKANONE = 20, + UNGEL_RAKETE = 21, + BOMBLET = 22, + SPRENGBOMBE = 23 +}; +struct gef_beschreibung_wirkfeld_einzelgeschoss_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt einschlagort; + UInt8 wirkdurchmesser; + gef_munitionsart_steilfeuer_et munitionsart; +}; + +struct gef_wirkfeld_einzelgeschoss_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_einzelgeschoss_rt beschreibung_wirkfeld_einzelgeschoss; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt8 wirkfeldbreite; + UInt8 wirkfeldtiefe; + UInt16 drehwinkel; + UInt16 anzahl_einschlaege; + UInt8 wirkkantenlaenge; + gef_munitionsart_steilfeuer_et munitionsart; +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt beschreibung_wirkfeld_flaechendeckendes_feuer; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Stop-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_STOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Fortsetzen-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt { + UInt16 wirkfeldkennung; + UInt16 fortsetzungswert_zufallszahl; + UInt16 nummer_des_naechsten_einschags; + gef_gps_zeit_rt fortsetzungszeit; + UInt16 verbleibende_wirkdauer; +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Minensperre-Meldung */ +/* WIRKFELD_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_minentyp_et { + SchtzAbwMi_DUS = 211, + SchtzAbVMi_DUS = 212, + PzAbwVMi_DUS = 213, + SchtzAbwMi_virtuell = 214, + PzAbwVMi_virtuell = 215, + PzAbwWMi_virtuell = 216, + PzAbwRiMi_AGDUS = 60 +}; + +struct gef_segment_rt { + gef_gps_position_rt startpunkt; + UInt16 minenanzahl; + UInt16 drehwinkel; +}; + +struct gef_beschreibung_wirkfeld_minensperre_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt16 wirkfeldbreite; + UInt16 wirkfeldtiefe; + UInt8 verlegetiefe; + UInt8 verlegedichte; + gef_minentyp_et minentyp; + UInt16 minenanzahl; + UInt8Idx anzahl_segmente; + gef_segment_rt segment<5>; +}; + +struct gef_wirkfeld_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_minensperre_rt beschreibung_wirkfeld_minensperre; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Status Minensperre-Meldung */ +/* WIRKFELD_STATUS_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_minenstatus_rt { + UInt16 wirkfeldkennung; + UInt16IdxDiv8 anzahl_minen; + opaque minenstatus<150>; +}; + +struct gef_wirkfeld_status_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_minenstatus_rt beschreibung_minenstatus; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld A-Kampfmittel-Meldung */ +/* WIRKFELD_A_KAMPFMITTEL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_a_kampfmittel_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt16 kantenlaenge_bereich_1; + UInt16 kantenlaenge_bereich_2; + UInt16 oeffnungswinkel; + UInt16 drehwinkel; +}; + +struct gef_wirkfeld_a_kampfmittel_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_a_kampfmittel_rt beschreibung_wirkfeld_a_kampfmittel; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld C-Kampfstoff-Meldung */ +/* WIRKFELD_C_KAMPFSTOFF_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_kampfstofftyp_et { + fluechtig = 1, + sesshaft = 2 +}; + +struct gef_beschreibung_wirkfeld_c_kampfstoff_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt8 vergroesserungsfaktor; + UInt16 windrichtung; + UInt8 windgeschwindigkeit; + gef_gps_zeit_rt gueltigkeitszeitpunkt_wetterdaten; + gef_gps_position_rt position_gueltigkeitszeitpunkt_wetterdaten;; + UInt8 kampfstoffkennung; + gef_kampfstofftyp_et kampfstofftyp; +}; + +struct gef_wirkfeld_c_kampfstoff_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_c_kampfstoff_rt beschreibung_wirkfeld_c_kampfstoff; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung-Wirkfeld-Meldung */ +/* DEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_wirkfeldtyp_et { + Undefined = 0, + Minensperre = 1, + Steilfeuer_Flaeche = 2, + Steilfeuer_Einzel = 3, + A_Waffe = 4, + C_Waffe = 5, + Funktionsraum = 6, + TechnicalArea = 7, + DusSingleMineSimulator = 8, + GasPipeDetonation = 9, + SpecialArea = 10, + BeStillWarning = 11, + DangerZoneExplosion = 12, + AirSupport = 13 +}; + +struct gef_deaktivierung_wirkfeld_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Aenderung Bezeichner-Meldung */ +/* WIRKFELD_AENDERUNG_BEZEICHNER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_aenderung_bezeichner_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung Einzelmine-Meldung */ +/* DEAKTIVIERUNG_EINZELMINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivierung_einzelmine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_gps_zeit_rt GPS_Zeit; + UInt16 wirkfeldkennung; + UInt16 minenindex; +}; + + + +/*----------------------------------------------------------------*/ +/* Reaktivierung DUS Mine-Meldung */ +/* REAKTIVIERUNG_DUS_MINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_Minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_reaktivierung_dus_mine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_dus_minenkennungen_rt DUS_minenkennungen; +}; + +/*----------------------------------------------------------------*/ +/* Definition-IED */ +/* DEFINITION_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_typ_et { + S_IED = 1, + IED_innen = 2, + IED_aussen = 3 +}; + +enum8 gef_ied_kopplungsstatus_et { + IED_keine_Kopplung = 1, + IED_Kopplung_an_Tln = 2, + IED_Kopplung_an_IPS = 3 +}; + +enum8 gef_ied_takitscher_zustand_et { + IED_inaktiv = 0, /* verlegt und gesichert */ + IED_aktiv = 1, /* scharf */ + IED_geloescht = 2, /* entschaerft */ + IED_ausgeloest_Schalter = 3, + IED_ausgeloest_Fernbedienung = 4, + IED_ausgeloest_Lichtschranke = 5, + IED_ausgeloest_Zugdraht = 6, + IED_ausgeloest_Kontrollgeraet = 7, + IED_unbekannt = 255 /* Kontakt verloren */ +}; + +struct gef_definition_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_typ_et typ; + UInt8 ausloeser; + UInt8 sprengkraft; + gef_gps_position_rt gps_position; + UInt8 partei_id; + gef_ied_kopplungsstatus_et kopplungsstatus; + gef_ausstattungs_id_t gekoppelte_id; + gef_ied_takitscher_zustand_et taktischer_zustand; /* 0 inaktiv, 1 aktiv */ + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ +}; + +/*----------------------------------------------------------------*/ +/* Zustand-IED */ +/* ZUSTAND_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_fehler_et { + IED_kein_Fehler = 0, + IED_Kommunikations_Fehler = 1 +}; + +struct gef_zustand_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_takitscher_zustand_et taktischer_zustand; + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ + UInt8 batteriewarnung; /* Bitleiste */ + gef_ied_fehler_et fehler_status_elektronik; + gef_ied_fehler_et fehler_status_pyrotechnik1; + gef_ied_fehler_et fehler_status_pyrotechnik2; + gef_ied_fehler_et fehler_status_pyrotechnik3; +}; + + +/*----------------------------------------------------------------*/ +/* Treffer Ausloesung-Meldung */ +/* TREFFER_AUSLOESUNG_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_verwundung_beschaedigung_et { + Einsatzbereit = 0, + Leichter_Treffer = 1, + Mittlerer_Treffer = 2, + Schwerer_Treffer = 3, + Bewegungsunfaehig = 4, + Bewegungsunfaehig_sichtbar = 5, + Ausfall_Waffenanlage = 6, + Ausfall_Waffenanlage_sichtbar = 7, + Totalausfall_sichtbar = 8, + Zeitlicher_Ausfall = 9, + Annaehernder_Treffer = 10, + Treffer_ohne_Wirkung = 11 +}; + +struct gef_treffer_ausloesung_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_verwundung_beschaedigung_et verwundung_beschaedigung; +}; + +/*----------------------------------------------------------------*/ +/* Status Einzelminensimulator */ +/* STATUS_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_status_einzelminensimulator_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 minenkennung; + gef_gps_position_rt gps_position; + UInt8 minentyp; + UInt8 status; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelminensimulator */ +/* WIRKFELD_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_einzelminensimulator_rt { + UInt16 wirkfeldkennung; + UInt8 partei_id; + UInt16 minenkennung; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt minenposition; + UInt8 minentyp; +}; + +struct gef_wirkfeld_einzelminensimulator_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_einzelminensimulator_rt beschreibung_einzelminensimulator; +}; + +/*----------------------------------------------------------------*/ +/* Schiedsrichtereingriff */ +/* SCHIEDSRICHTEREINGRIFF */ +/*----------------------------------------------------------------*/ +/* +struct gef_schiedsrichtereingriff_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_gps_position_rt gps_position; + UInt16 schiedsrichter_aktion; + UInt8 schiedsrichter; +}; + + + +/*----------------------------------------------------------------*/ +/* Selektive Aufmunitionierung */ +/* GEF_SELEKTIVE_AUFMUNITIONIERUNG */ +/*----------------------------------------------------------------*/ +struct gef_aufmunitionierung_rt { + UInt16 munitionsart; + UInt8 ort; /* Turm / Wanne */ + UInt16 neuer_vorrat; /* 0xffff = default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt16 neuer_default_vorrat; /* 0xffff = factory default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt8 tracer_ratio; /* 0 = kein Trace, 1 = jedes Projektil, 2 = jedes 2. Projektil, ... */ +}; + +struct gef_selektive_aufmunitionierung_rt { + gef_header_rt header; + u_int waffen_id; + UInt8Idx anzahl_aufmunitionierungen; + gef_aufmunitionierung_rt aufmunitionierung<10>; +}; + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_behandlungs_ergebnis_et { + Keine = 0, + Erfolg = 1, + Stabilisiert = 2, + Fehler = 3 +}; + +struct gef_sanitetsdienst_instandsetzung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt8 verurschaer_typ; + UInt16 ausstattung_behandelnder; + gef_verwundung_beschaedigung_et status_start; + UInt8 typ_der_behandlung; + UInt8 triage; + UInt8 typ_der_behandlung; + gef_verwundung_beschaedigung_et status_ergebnis; + gef_behandlungs_ergebnis_et ergebhnis_behandlung; + UInt8 triage_priorität; + UInt8 komplett_status; + UInt24 behandlungszeit; + UInt24 erholungszeit; +}; + + + +*/ +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_betriebsmodus_et { + Nicht_vorhanden = 0, + Eingriff_durch_schiedsrichter = 1, + Wartezeit_nach_Erreichen_des_Funktionsraums = 2 +}; + +struct gef_funktionsraum_rt { + gef_betriebsmodus_et betriebsmodus; + UInt8 wartezeit; +}; + +struct gef_beschreibung_funktionsraum_rt { + UInt16 funktionsraumkennung; + string funktionsraumbezeichner[8]; + UInt8 partei_id; + gef_gps_position_rt funktionsraumeckpunkt; + UInt8 funktionsraumbreite; + UInt8 funktionsraumtiefe; + gef_funktionsraum_rt funktionsraum_fuer_entgiftungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_instandsetzungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_sandienstliche_versorgung; +}; + +struct gef_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_funktionsraum_rt beschreibung_funktionsraum; +}; + + + +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivieren_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 funktionsraumkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-SRT-Meldung */ +/* DATENVERKEHR_TDS_SRT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_fuer_tne_transparente_daten_rt { + opaque data<30>; /* 30 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_srt_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-DMF-Meldung */ +/* DATENVERKEHR_TDS_DMF_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_datenverkehr_tds_dmf_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Steuerung Verkehrsaufkommen-Meldung */ +/* STEUERUNG_VERKEHRSAUFKOMMEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_steuerung_verkehrsaufkommen_meldung_rt { + gef_header_rt header; + gef_lastzustand_datenfunk_et lastzustand_datenfunk; + UInt16 inhibit_zeit_fuer_positionsmeldungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Nachforderung Broadcast Telegramme-Meldung */ +/* NACHFORDERUNG_BROADCAST_TELEGRAMME_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachforderung_broadcast_telegramme_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + UInt8 ruecksetzzaehler; + UInt16 broadcast_index; +}; + + + +/*----------------------------------------------------------------*/ +/* Nop-Meldung */ +/* NOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_broadcasttelegramme_rt { + UInt16 feld_anfang; + UInt16 feld_ende; +}; + +struct gef_nop_meldung_rt { + gef_header_rt header; + gef_broadcasttelegramme_rt broadcasttelegramme; +}; + + + +/*----------------------------------------------------------------*/ +/* Sprachauswahl-Meldung */ +/* SPRACHAUSWAHL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_sprachauswahl_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sprache_et sprachauswahl; +}; + + + +/*----------------------------------------------------------------*/ +/* Allgemeine Nachricht-Meldung */ +/* ALLGEMEINE_NACHRICHT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachricht_rt { + UInt8Idx laenge; + string text<80>; +}; + +struct gef_allgemeine_nachricht_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_nachricht_rt nachricht; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Wirkfeld-Meldung */ +/* SAMMELDEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_wirkfeldkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 wirkfeldkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_wirkfeldkennungen_rt liste_der_wirkfeldkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung DUS-Minen-Meldung */ +/* SAMMELDEAKTIVIERUNG_DUS_MINEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_wf_sammeldeaktivierung_dus_minen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_dus_minenkennungen_rt liste_DUS_minenkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Funktionsraum-Meldung */ +/* SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_funktionsraumkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 funktionsraumkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_funktionsraumkennungen_rt liste_der_funktionsraumkennungen; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-GeoP-Meldung */ +/* DATENVERKEHR_TDS_GEOP_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_geop_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_geop_meldung_rt { + gef_header_rt header; + UInt8 laenge_GeoP_Daten; + gef_geop_daten_rt geop_daten; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-TgtS-Meldung */ +/* DATENVERKEHR_TDS_TGTS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_tgts_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_tgts_meldung_rt { + gef_header_rt header; + UInt8 laenge_tgts_Daten; + gef_tgts_daten_rt tgts_daten; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration IPS-Meldung */ +/* KONFIGURATION_IPS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zuordnung_rt { + UInt16 raumnummer_des_gebaeudemodell; + UInt16 IPS_Platz_des_gebaeudemodell; + UInt16 IPS_Kennung; +}; + +struct gef_ips_konfiguration_rt { + UInt8Idx anzahl; + gef_zuordnung_rt zuordnung<255>; +}; + +struct gef_konfiguration_ips_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_ips_konfiguration_rt ips_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG */ +/*----------------------------------------------------------------*/ +struct gef_treffer_ereignis_sekundaerwirkung_rt { + gef_header_rt header; + gef_gps_zeit_rt wirkbeginn; + UInt16 munCode; + UInt16 verursacher; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt8 effectCode; + UInt16 reserve1; + UInt16 reserve2; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration ZEG-Meldung */ +/* KONFIGURATION_ZEG_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zeg_zuordnung_rt { + UInt16 referenzmodul_des_gebaeudemodell; + UInt16 ZEG_Kennung; +}; + +struct gef_zeg_konfiguration_rt { + UInt8Idx anzahl; + gef_zeg_zuordnung_rt zeg_zuordnung<255>; +}; + +struct gef_konfiguration_zeg_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_zeg_konfiguration_rt zeg_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* Ausloseung DUS-Treffer */ +/* GEF_AUSLOESUNG_DUS_TREFFER */ +/*----------------------------------------------------------------*/ +struct gef_ausloesung_dus_treffer_rt { + gef_header_rt header; + gef_gps_zeit_rt zeit; + UInt8Idx munitionsart; + UInt16 richtung; + UInt16 entfernung; + UInt8Idx wirkung; + UInt16 verursacher; +}; +/*----------------------------------------------------------------*/ +/* GEF_ANFORDERUNG_SW_VERSION */ +/* GEF_SW_VERSIONSMELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_anforderung_sw_version_rt { + gef_header_rt header; + UInt16 geraetekennung; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_SETZEN (Zentrale -> SFM) */ +/*----------------------------------------------------------*/ +enum8 gef_tln_sprache_et { + TLN_SPRACHE_KEINE_AENDERUNG = 0, + TLN_SPRACHE_DE = 1, + TLN_SPRACHE_EN = 2, + TLN_SPRACHE_FR = 3, + TLN_SPRACHE_AR = 4, + TLN_SPRACHE_ES = 5, + TLN_SPRACHE_RU = 6 +}; + +enum8 gef_operation_mode_et { + OP_MODE_KEINE_AENDERUNG = 0, + OP_MODE_NORMAL = 1, + OP_MODE_BE_STILL = 2 +}; + +enum8 gef_wph_mode_weste_et { + WPH_MODE_WESTE_KEINE_AENDERUNG = 0, + WPH_MODE_WESTE_OHNE = 1, + WPH_MODE_WESTE_MIT = 2 +}; + +enum8 gef_wph_mode_helm_et { + WPH_MODE_HELM_KEINE_AENDERUNG = 0, + WPH_MODE_HELM_OHNE = 1, + WPH_MODE_HELM_MIT = 2 +}; + +enum8 gef_wph_mode_personenschutz_et { + WPH_MODE_PERSONENSCHUTZ_KEINE_AENDERUNG = 0, + WPH_MODE_PERSONENSCHUTZ_OHNE = 1, + WPH_MODE_PERSONENSCHUTZ_ANZUG = 2, + WPH_MODE_PERSONENSCHUTZ_ANZUG_HANDSCHUHE_SCHUHE = 3 +}; + +enum8 gef_schutzniveau_et { + SN_SCHUTZ_KEINE_AENDERUNG = 0, + SN_IDZ_ES = 1, + SN_IDZ_BS = 2, + SN_KSK = 3, + SN_SOLDAT_MIT_KOERPERSCHUTZ = 4, + SN_SOLDAT_DARSTELLER = 5 +}; + +enum8 gef_handgranaten_suche_et { + HS_KEINE_AENDERUNG = 0, + HS_SUCHE_AUS = 1, + HS_SUCHE_EIN = 2 +}; + +enum8 gef_international_mode_et { + IM_KEINE_AENDERUNG = 0, + IM_AUS = 1, + IM_EIN = 2 +}; + +/* Reaktivierung: in Minuten (0, 10 .. 2550) */ +struct gef_teilnehmermode_rt { + gef_tln_sprache_et sprache; + gef_operation_mode_et op_mode; + UInt8 reaktivierung_entgiftung; + UInt8 reaktivierung_inst; + UInt8 reaktivierung_sanitaet; + gef_wph_mode_personenschutz_et:1..3 mode_personenschutz; + gef_wph_mode_weste_et:4..5 mode_weste; + gef_wph_mode_helm_et:6..7! mode_helm; + gef_schutzniveau_et schutzniveau; + gef_handgranaten_suche_et:6..7! handgranaten_suche; + gef_international_mode_et:4..5 international_mode; +}; + +struct gef_teilnehmermode_setzen_rt { + gef_header_rt header; + UInt16 bcIndex; + gef_teilnehmermode_rt mode; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_MELDUNG (SFM -> Zentrale) */ +/*----------------------------------------------------------*/ +struct gef_teilnehmermode_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_teilnehmermode_rt mode; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_SETZEN */ +/*----------------------------------------------------------------*/ + +enum8 gef_positions_handling_et { + POS_HANDLING_DEFAULT = 0, + POS_HANDLING_UNGUELTIG_NICHT_SCHICKEN = 1, + POS_HANDLING_UNGUELTIG_KENNZEICHNEN = 2, + POS_HANDLING_UNGUELTIG_SCHICKEN = 3 +}; + +enum8 gef_optischer_code_et { + OPTISCHER_CODE_KEINE_AENDERUNG = 0, + OPTISCHER_CODE_OSAG_1_0 = 1, + OPTISCHER_CODE_OSAG_2_0_BASIC = 2 +}; + +struct gef_sfm_konfig_rt { + UInt16 pos_aenderung_fz; + UInt16 pos_aenderung_personal; + UInt16 pos_aenderung_lfz; + UInt16 pos_uebertragungs_interval; + UInt16 hoehengrenze; + gef_positions_handling_et:6..7 positions_handling; + UInt8Idx:0..1! pos_interval_umschaltung; + UInt16 wartezeit_nachforderung; + UInt8 faktor_wartezeit_hochlast; + UInt8 wartezeit_vbg_1_2; + UInt8 wartezeit_vbg_2_3; + UInt8 wartezeit_vbg_3_8; + gef_optischer_code_et optischer_code; + UInt8 verwundungsmodel; + UInt8 gueltigkeitsdauer_standortbestimmung; +}; + +struct gef_teilnehmer_konfig_setzen_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sfm_konfig_rt konfig; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_ANTWORT */ +/*----------------------------------------------------------------*/ + +struct gef_teilnehmer_konfig_antwort_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_sfm_konfig_rt konfig; +}; + +/*-------------------------------------------------------*/ +/* GEF_NOTRUF */ +/*-------------------------------------------------------*/ + +struct gef_notruf_rt { + gef_gps_position_rt gps_position; +}; + +/*==============================================================*/ +/* Zusammenfassung der Telegramm-Typen */ +/*==============================================================*/ +union gef_tg_nd_ switch (gef_telegramm_id_et telegramm_id) { + + case GEF_INIT: + gef_init_meldung_rt init_meldung; + + case GEF_MANIPULATIONSMELDUNG: + case GEF_BITE_MELDUNG: + case GEF_BITE_MELDUNG2: + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: + case GEF_FEHLERMELDUNG_GFD: + case GEF_POSITIONS_MELDUNG: + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + case GEF_POSITIONS_MELDUNG_LFZ: + case GEF_FEUER_EREIGNIS: + case GEF_TREFFER_EREIGNIS_DUS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: + case GEF_TAKTISCHER_STATUS: + case GEF_TREFFER_EREIGNIS_DUS_IPS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: + case GEF_EINTRETEN_FUNKTIONSRAUM: + case GEF_DATENVERKEHR_SRT_TDS: + case GEF_DATENVERKEHR_DMF_TDS: + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + case GEF_SONDERSENSORIK_FAHRSPUR: + case GEF_SONDERSENSORIK_DATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + case GEF_DATENVERKEHR_GEOP_TDS: + case GEF_DATENVERKEHR_TGTS_TDS: + case GEF_GERAETEEREIGNIS: + case GEF_WAFFENZUORDNUNG: + case GEF_IPS_POSITIONSDATEN: + case GEF_STANDORTBESTIMMUNG: + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + case GEF_ANFORDERUNG_KONFIG_ZEG: + case GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG: + case GEF_TREFFEREREIGNIS_GEBAEUDE: + case GEF_TEILNEHMERMODE_ANFORDERN: + case GEF_TEILNEHMER_KONFIG_ANFORDERN: + case GEF_SCHIEDSRICHTEREINGRIFF: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + gef_selektive_aufmunitionierung_rt selektive_aufmunitionierung; + + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + gef_sanitetsdienst_instandsetzung_rt sanitetsdienst_instandsetzung; + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + gef_bestandmseldung_sanitatsmaterial_rt bestandmseldung_sanitatsmaterial; + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + gef_sanitetsdienst_instandsetzung_pvsan_rt sanitetsdienst_instandsetzung_pvsan; + case GEF_TECHNIK_FUNKTIONSRAUM: + gef_technik_funktionsraum_rt technik_funktionsraum; + case GEF_UMGEBUNGS_MELDUNG: + gef_umgebungs_meldung_rt umgebungs_meldung; + + case GEF_UMGEBUNGS_MELDUNG2: + gef_umgebungs_meldung2_rt umgebungs_meldung2; + + case GEF_AUFFORDERUNG_BITE_MELDUNG: + gef_aufforderung_bite_meldung_rt aufforderung_bite_meldung; + + case GEF_LIZENSIERUNG_TNE: + gef_lizensierung_tne_meldung_rt linzensierung_tne_meldung; + + case GEF_KONFIGURATION_TEILNEHMER: + gef_konfiguration_teilnehmer_rt konfiguration_teilnehmer; + + case GEF_KONFIGURATION_WIRKMODELL: + gef_konfiguration_wirkmodell_rt konfiguration_wirkmodell; + + case GEF_TEILNEHMERMODE_SETZEN: + gef_teilnehmermode_setzen_rt teilnehmermode_setzen; + + case GEF_TEILNEHMERMODE_MELDUNG: + gef_teilnehmermode_meldung_rt teilnehmermode_meldung; + + case GEF_TEILNEHMER_KONFIG_SETZEN: + gef_teilnehmer_konfig_setzen_rt teilnehmer_konfig_setzen; + + case GEF_TEILNEHMER_KONFIG_ANTWORT: + gef_teilnehmer_konfig_antwort_rt teilnhemer_konfig_antwort; + +/* case GEF_POSITIONSKORREKTURDATEN: + */ + + case GEF_WIRKFELD_EINZELGESCHOSS: + gef_wirkfeld_einzelgeschoss_meldung_rt wirkfeld_einzelgeschoss_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + gef_wirkfeld_flaechendeckendes_feuer_meldung_rt wirkfeld_flaechendeckendes_feuer_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt wirkfeld_flaechendeckendes_feuer_stop_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung; + + case GEF_WIRKFELD_MINENSPERRE: + gef_wirkfeld_minensperre_meldung_rt wirkfeld_minensperre_meldung; + + case GEF_WIRKFELD_STATUS_MINENSPERRE: + gef_wirkfeld_status_minensperre_meldung_rt wirkfeld_status_minensperre_meldung; + + case GEF_WIRKFELD_A_KAMPFMITTEL: + gef_wirkfeld_a_kampfmittel_meldung_rt wirkfeld_a_kampfmittel_meldung; + + case GEF_WIRKFELD_C_KAMPFSTOFF: + gef_wirkfeld_c_kampfstoff_meldung_rt wirkfeld_c_kampfstoff_meldung; + + case GEF_DEAKTIVIERUNG_WIRKFELD: + gef_deaktivierung_wirkfeld_meldung_rt deaktivierung_wirkfeld_meldung; + + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + gef_wirkfeld_aenderung_bezeichner_meldung_rt wirkfeld_aenderung_bezeichner_meldung; + + case GEF_DEAKTIVIERUNG_EINZELMINE: + gef_deaktivierung_einzelmine_meldung_rt deaktivierung_einzelmine_meldung; + + case GEF_REAKTIVIERUNG_DUS_MINE: + gef_reaktivierung_dus_mine_meldung_rt reaktivierung_dus_mine_meldung; + + case GEF_DEFINITION_IED: + gef_definition_ied_rt definition_ied; + + case GEF_ZUSTAND_IED: + gef_zustand_ied_rt zustand_ied; + + case GEF_STATUS_EINZELMINENSIMULATOR: + gef_status_einzelminensimulator_rt status_einzelminensimulator_rt; + + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + gef_wirkfeld_einzelminensimulator_rt wirkfeld_einzelminensimulator_rt; + + case GEF_TREFFER_AUSLOESUNG: + gef_treffer_ausloesung_meldung_rt treffer_ausloesung_meldung; + + case GEF_FUNKTIONSRAUM: + gef_funktionsraum_meldung_rt funktionsraum_meldung; + + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + gef_deaktivieren_funktionsraum_meldung_rt deaktivieren_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_SRT: + gef_datenverkehr_tds_srt_meldung_rt datenverkehr_tds_srt_meldung; + + case GEF_DATENVERKEHR_TDS_DMF: + gef_datenverkehr_tds_dmf_meldung_rt datenverkehr_tds_dmf_meldung_meldung; + + case GEF_STEUERUNG_VERKEHRSAUFKOMMEN: + gef_steuerung_verkehrsaufkommen_meldung_rt steuerung_verkehrsaufkommen_meldung; + + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + gef_nachforderung_broadcast_telegramme_meldung_rt nachforderung_broadcast_telegramme_meldung; + + case GEF_NOP: + gef_nop_meldung_rt nop_meldung; + + case GEF_SPRACHAUSWAHL: + gef_sprachauswahl_meldung_rt sprachauswahl_meldung; + + case GEF_ALLGEMEINE_NACHRICHT: + gef_allgemeine_nachricht_meldung_rt allgemeine_nachricht_meldung; + +/* case GEF_ECHO_ON_OFF: + case GEF_ESW_MELDUNG: + case GEF_GEFECHTSFELDTELEGRAMM: */ + + case GEF_WF_SAMMELDEAKTIVIERUNG: + gef_wf_sammeldeaktivierung_meldung_rt wf_sammeldeaktivierung_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + gef_wf_sammeldeaktivierung_dus_minen_meldung_rt wf_sammeldeaktivierung_dus_minen_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt wf_sammeldeaktivierung_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_GEOP: + gef_datenverkehr_tds_geop_meldung_rt datenverkehr_tds_geop_meldung; + + case GEF_DATENVERKEHR_TDS_TGTS: + gef_datenverkehr_tds_tgts_meldung_rt datenverkehr_tds_tgts_meldung; + + case GEF_KONFIGURATION_IPS: + gef_konfiguration_ips_meldung_rt konfiguration_ips_meldung; + + case GEF_KONFIGURATION_ZEG: + gef_konfiguration_zeg_meldung_rt konfiguration_zeg_meldung; + + case GEF_AUSLOESUNG_DUS_TREFFER: + gef_ausloesung_dus_treffer_rt gef_ausloesung_dus_treffer; + + case GEF_ANFORDERUNG_SW_VERSION: + gef_anforderung_sw_version_rt anforderung_sw_version; + case GEF_SW_VERSIONSMELDUNG: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + gef_treffer_ereignis_sekundaerwirkung_rt treffer_ereignis_sekundaerwirkung; + + case GEF_NOTRUF: + gef_notruf_rt notruf; + + default: + void; +}; + +/* +struct dafu_tele { + u_long telegramm_zaehler; + unsigned short telegramm_prioritaet; + gef_tg_nd_ daten; +}; +*/ diff --git a/TetraIF/LogView/zsksxd_tetraForLogView_guez.cpp b/TetraIF/LogView/zsksxd_tetraForLogView_guez.cpp new file mode 120000 index 000000000..22f709a79 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView_guez.cpp @@ -0,0 +1 @@ +zsksxd_tetraForLogView_guez.x \ No newline at end of file diff --git a/TetraIF/LogView/zsksxd_tetraForLogView_guez.x b/TetraIF/LogView/zsksxd_tetraForLogView_guez.x new file mode 100644 index 000000000..68d6bcee7 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView_guez.x @@ -0,0 +1,1839 @@ +/* +const MAX_LAENGE_GEFECHTSFELDTELEGRAMM = 2000; +*/ + +/*-------------------------------*/ +/* Telegramm-ID's */ +/*-------------------------------*/ + +enum8 gef_telegramm_id_et { + + GEF_BESTAETIGUNG = 0, + + GEF_INIT = 1, + GEF_MANIPULATIONSMELDUNG = 2, + GEF_UMGEBUNGS_MELDUNG = 3, + GEF_UMGEBUNGS_MELDUNG2 = 203, + GEF_AUFFORDERUNG_BITE_MELDUNG = 4, + GEF_BITE_MELDUNG = 5, + GEF_BITE_MELDUNG2 = 205, + + GEF_LIZENSIERUNG_TNE = 6, + GEF_BETRIEBSZUSTAND_AUSSTATTUNG = 7, + GEF_KONFIGURATION_TEILNEHMER = 8, + GEF_KONFIGURATION_WIRKMODELL = 9, + GEF_ANFORDERUNG_KONFIGURATIONSDATEN = 10, + GEF_KONFIGURATIONSMELDUNG = 11, + GEF_FEHLERMELDUNG_GFD = 12, + + GEF_POSITIONS_MELDUNG = 21, + GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER = 22, + GEF_POSITIONS_MELDUNG_LFZ = 23, + GEF_POSITIONSKORREKTURDATEN = 24, + + GEF_WIRKFELD_EINZELGESCHOSS = 31, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER = 32, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP = 33, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN = 34, + GEF_WIRKFELD_MINENSPERRE = 35, + GEF_WIRKFELD_STATUS_MINENSPERRE = 36, + GEF_WIRKFELD_A_KAMPFMITTEL = 37, + GEF_WIRKFELD_C_KAMPFSTOFF = 38, + GEF_DEAKTIVIERUNG_WIRKFELD = 39, + GEF_WIRKFELD_AENDERUNG_BEZEICHNER = 40, + GEF_DEAKTIVIERUNG_EINZELMINE = 41, + GEF_REAKTIVIERUNG_DUS_MINE = 42, + GEF_DEFINITION_IED = 43, + GEF_ZUSTAND_IED = 44, + GEF_STATUS_EINZELMINENSIMULATOR = 45, + GEF_WIRKFELD_EINZELMINENSIMULATOR = 46, + + GEF_FEUER_EREIGNIS = 51, + GEF_TREFFER_EREIGNIS_DUS = 52, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION = 53, + GEF_TREFFER_AUSLOESUNG = 54, + GEF_SCHIEDSRICHTEREINGRIFF = 55, + GEF_SELEKTIVE_AUFMUNITIONIERUNG = 56, + + GEF_TREFFER_EREIGNIS_DUS_IPS = 228, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS = 229, + + GEF_TAKTISCHER_STATUS = 61, + GEF_FUNKTIONSRAUM = 62, + GEF_EINTRETEN_FUNKTIONSRAUM = 63, + GEF_DEAKTIVIEREN_FUNKTIONSRAUM = 64, + + GEF_DATENVERKEHR_SRT_TDS = 71, + GEF_DATENVERKEHR_TDS_SRT = 72, + GEF_DATENVERKEHR_DMF_TDS = 73, + GEF_DATENVERKEHR_TDS_DMF = 74, + + GEF_STEUERUNG_VERKEHRSAUFKOMMEN = 81, + GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME = 82, + GEF_NOP = 83, + + GEF_SONDERSENSORIK_BETRIEBSZUSTAND = 91, + GEF_SONDERSENSORIK_FAHRSPUR = 92, + GEF_SONDERSENSORIK_DATEN = 93, + GEF_SONDERSENSORIK_TREFFER_AUFGES_TLN = 94, + GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN = 95, + GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN = 96, + GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION = 97, + + GEF_SPRACHAUSWAHL = 101, + GEF_ALLGEMEINE_NACHRICHT = 102, + GEF_ECHO_ON_OFF = 103, + GEF_ESW_MELDUNG = 104, + + GEF_WF_SAMMELDEAKTIVIERUNG = 105, + GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN = 106, + GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM = 107, + + GEF_DATENVERKEHR_GEOP_TDS = 181, + GEF_DATENVERKEHR_TDS_GEOP = 182, + + GEF_DATENVERKEHR_TGTS_TDS = 183, + GEF_DATENVERKEHR_TDS_TGTS = 184, + GEF_GERAETEEREIGNIS = 185, + + GEF_WAFFENZUORDNUNG = 200, + GEF_IPS_POSITIONSDATEN = 201, + GEF_STANDORTBESTIMMUNG = 25, + GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE = 202, + GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG = 210, + GEF_AUSLOESUNG_DUS_TREFFER = 211, + GEF_ANFORDERUNG_SW_VERSION = 212, + GEF_SW_VERSIONSMELDUNG = 213, + + GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG = 218, + GEF_TECHNIK_FUNKTIONSRAUM = 219, + GEF_ANFORDERUNG_KONFIG_ZEG = 220, + GEF_KONFIGURATION_IPS = 221, + GEF_KONFIGURATION_ZEG = 222, + GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG = 223, + GEF_TREFFEREREIGNIS_GEBAEUDE = 224, + + GEF_TEILNEHMERMODE_SETZEN = 230, + GEF_TEILNEHMERMODE_MELDUNG = 231, + GEF_TEILNEHMERMODE_ANFORDERN = 232, + GEF_TEILNEHMER_KONFIG_ANTWORT = 233, + GEF_TEILNEHMER_KONFIG_SETZEN = 234, + GEF_TEILNEHMER_KONFIG_ANFORDERN = 235, + + GEF_SANITAETSDIENST_INSTANDSETZUNG = 240, + GEF_BESTANDSMELDUNG_SANITAETSMATERIAL = 241, + GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN = 242, + + GEF_GEFECHTSFELDTELEGRAMM = 300, + GEF_UEBERLAST_WARNUNG_ENTWARNUNG = 301, + GEF_DATENFUNK_INIT = 302, + GEF_DATENFUNK_EXIT = 303, + GEF_DATENFUNK_EXIT_ACKNOWLEDGE = 304, + GEF_ZUORDNUNG_GRUPPENRUFADRESSE = 305, + GEF_NOTRUF = 1120 +}; + + +/*==============================================================*/ +/* Strukturtypen, die mehrfach verwendet werden */ +/*==============================================================*/ + +/*---------------------------------------*/ +/* Identifikation */ +/*---------------------------------------*/ + +typedef UInt16 gef_ausstattungs_id_t; + + +/*---------------------------------------*/ +/* Header */ +/*---------------------------------------*/ + +struct gef_header_rt { + gef_ausstattungs_id_t identitaet; +}; + + +/*---------------------------------------*/ +/* GPS-Zeit */ +/*---------------------------------------*/ + +struct gef_gps_zeit_rt { + u_int GPS_zeit; +}; + + +/*---------------------------------------*/ +/* GPS-Position */ +/*---------------------------------------*/ + +struct gef_gps_position_rt { + SInt24 nordwert; + SInt24 ostwert; +}; + + +/*---------------------------------------*/ +/* Lastzustand Datenfunk */ +/*---------------------------------------*/ + +enum8 gef_lastzustand_datenfunk_et { + Normallast = 0, + Hochlast = 1, + Ueberlast = 2 +}; + + +/*==============================================================*/ +/* Beschreibung der speziellen TETRA-Telegramme */ +/*==============================================================*/ + +struct TETRA_register_indication_rt { + UInt32LE ISSI_ext_host; +}; + +enum8 TETRA_registration_status_et { + ISSI_successful_registered = 0, + Duplicate_ISSI = 1, + Invalid_ISSI = 2, + Invalid_IP_address = 3 +}; + +struct TETRA_register_response_rt { + TETRA_registration_status_et registration_status; +}; + +enum8 TETRA_login_status_et { + Login_Request = 1, + Login_Accept = 2, + Login_Reject = 3 +}; + +enum8 TETRA_login_mastering_et { + No_Mastering = 0, + Mastering = 1 +}; + +enum8 TETRA_reject_cause_et { + Reserved = 0, + EqIdAlreadyAssigned = 1, + IssiAlreadyAssigned = 2, + EqIdAssignedInOtherExercise = 3 +}; + +struct TETRA_login_telegram_rt { + gef_header_rt header; + TETRA_login_status_et:0..1 login_status; + TETRA_login_mastering_et:2..2 login_mastering; + TETRA_reject_cause_et:3..6! reject_cause; +}; + +enum8 TETRA_telegram_type_et { + NotFragmented = 0, + FirstFragment = 1, + MiddleFragment = 3, + LastFragment = 2 +}; + +enum8 TETRA_fragment_counter_et { + 0 = 0, + 1 = 1, + 2 = 2, + 3 = 3, + 4 = 4, + 5 = 5, + 6 = 6, + 7 = 7, + 8 = 8, + 9 = 9, + 10 = 10, + 11 = 11, + 12 = 12, + 13 = 13, + 14 = 14, + 15 = 15 +}; + +struct TETRA_first_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + gef_telegramm_id_et telegram_id; + opaque data<28>; /* 28 => dyn.-array-offset */ +}; + +struct TETRA_middle_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_last_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_air_interface_load_report_rt { + UInt8 network_index; + UInt16LE base_station_ID; + UInt8 channel_ID; + UInt8 queue_length; +}; + +struct TETRA_status_ind_req_rt { + UInt32LE ISSI_host; + UInt32LE ISSI_destination; + UInt32LE status; +}; + +enum8 TETRA_monitor_et { + No_Monitoring = 0, + Monitoring = 1 +}; + +struct TETRA_group_monitoring_ind_rt { + UInt32LE ISSI_host; + TETRA_monitor_et monitor; + UInt16LEIdx count_gssi; + UInt32LE gssi<5>; +}; + +struct TETRA_air_interface_load_req_rt { + UInt16LEIdx number_of_reports; + TETRA_air_interface_load_report_rt air_interface_load_report<4>; +}; + +struct TETRA_unknown_PDU_rt { + UInt8 magic_number; + UInt8 counter; + UInt16LE length; + UInt8 PDU_Type; + opaque data<5>; /* 5 => dyn.-array-offset */ +}; + + +/*==============================================================*/ +/* Beschreibung der Telegramme */ +/*==============================================================*/ + +/*----------------------------------------------------------------*/ +/* Automatische Conversion */ +/*----------------------------------------------------------------*/ +/* +Alle TETRA-Meldungen, die mit der Klasse CoPrtCnvTelegramConverter in +eine Zentral-Meldung konvertiert werden, müssen trotzdem in der TETRA- +union definiert werden, damit die Telegramme Namen bekommen. +*/ + +struct gef_automatic_conversion_rt { + gef_header_rt header; + UInt8 fehler_diese_meldung_sollte_automatisch_konvertiert_werden; +}; + + + +/*----------------------------------------------------------------*/ +/* Init-Meldung */ +/* INIT_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_tln_aufmunitionieren_et { + tln_am_nein = 0, + tln_am_ja = 1 +}; + +enum8 gef_tln_zuruecksetzen_et { + tln_zs_nein = 0, + tln_zs_ja = 1 +}; + +enum8 gef_tln_manipulation_et { + tln_mp_nein = 0, + tln_mp_reset = 1 +}; + +enum8 gef_tln_medizinische_vorraete_auffuellen_et { + tln_mv_nein = 0, + tln_mv_reset = 1 +}; + +/* MSB = 0 ... */ +struct gef_initialisierungsdaten_rt { + gef_tln_aufmunitionieren_et:2..2 tln_aufmunitionieren; + gef_tln_zuruecksetzen_et:1..1 tln_zuruecksetzen; + gef_tln_manipulation_et:7..7 tln_manipulation; + gef_tln_medizinische_vorraete_auffuellen_et:6..6 tln_mediziniesche_vorraete_auffuellen; +}; + +struct gef_init_meldung_rt { + gef_header_rt header; + gef_initialisierungsdaten_rt initialisierungsdaten; +}; + + +/*----------------------------------------------------------------*/ +/* Umgebungs-Meldung */ +/* UMGEBUNGS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_uebungspause_et { + KEINE_UEBUNGSPAUSE = 0, + B_MIT_TEST = 1 +}; + +enum8 gef_inhbit_time_et { + IH_UNDEFINED = 0, + IH_1_SEKUNDE = 1, + IH_2_SEKUNDEN = 2, + IH_3_SEKUNDEN = 3, + IH_4_SEKUNDEN = 4, + IH_5_SEKUNDEN = 5, + IH_6_SEKUNDEN = 6, + IH_7_SEKUNDEN = 7, + IH_8_SEKUNDEN = 8, + IH_9_SEKUNDEN = 9, + IH_10_SEKUNDEN = 10, + IH_11_SEKUNDEN = 11, + IH_12_SEKUNDEN = 12, + IH_13_SEKUNDEN = 13, + IH_14_SEKUNDEN = 14, + IH_15_SEKUNDEN = 15, + IH_16_SEKUNDEN = 16, + IH_17_SEKUNDEN = 17, + IH_18_SEKUNDEN = 18, + IH_19_SEKUNDEN = 19, + IH_20_SEKUNDEN = 20, + IH_21_SEKUNDEN = 21, + IH_22_SEKUNDEN = 22, + IH_23_SEKUNDEN = 23, + IH_24_SEKUNDEN = 24, + IH_25_SEKUNDEN = 25, + IH_26_SEKUNDEN = 26, + IH_27_SEKUNDEN = 27, + IH_28_SEKUNDEN = 28, + IH_29_SEKUNDEN = 29, + IH_30_SEKUNDEN = 30, + IH_31_SEKUNDEN = 31 +}; + +struct gef_betriebszustaende_gefechtsfeld_rt { + gef_uebungspause_et:0..0 uebungspause; + gef_inhbit_time_et:1..5 pos_inhibit_time; + gef_lastzustand_datenfunk_et:6..7! lastzustand_datenfunk; +}; + +struct gef_basiskoordinate_zur_positionsbestimmung_rt { + UInt8 zone; + string band; + string quadrat[2]; + UInt8 ostwert; + UInt8 nordwert; +}; + +struct gef_umgebungs_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; +}; + +struct gef_umgebungs_meldung2_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; + gef_gps_zeit_rt aktuelle_zeit; +}; + + +/*----------------------------------------------------------------*/ +/* Aufforderung BITE-Meldung */ +/* AUFFORDERUNG_BITE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_bite_meldungsart_et { + NUR_STATUSABFRAGE = 0, + ERST_SELBSTTEST = 1 +}; + +struct gef_aufforderung_bite_meldung_rt { + gef_header_rt header; + gef_bite_meldungsart_et bite_meldungsart; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration Wirkmodell */ +/* GEF_KONFIGURATION_WIRKMODELL */ +/*----------------------------------------------------------------*/ + +struct gef_wirkmodell_rt { + UInt8 minen_ied; + UInt8 steilfeuer; + UInt8 einsatzmittel; + UInt8 ac_waffen; +}; + +struct gef_konfiguration_wirkmodell_rt { + gef_header_rt header; + gef_wirkmodell_rt wirkmodelle; +}; + +/*----------------------------------------------------------------*/ +/* Konfigurationsmeldung */ +/* GEF_KONFIGURATION_TEILNEHMER */ +/*----------------------------------------------------------------*/ + +struct gef_login_parameter_rt { + UInt8 wartezeit_versuche; + UInt8 anzahl_versuche; + UInt8 mastering_flag; +}; + +enum8 gef_sprache_et { + keine_aenderung = 0, + deutsch = 1, + englisch = 2, + franzoesisch = 3 +}; + +struct gef_konfiguration_abe_rt { + UInt8 sprachausgabe; + gef_sprache_et sprache; +}; + +struct gef_konfiguration_wirkdarstellung_rt { + UInt8 pyrotechnik; +}; + +enum8 gef_betriebsart_mhgr_sensorik_et { + BetriebAmAusbAusstgPers = 0, + BetriebAnSonstigenFzg = 2, + BetriebAnSrFahrzeug = 3 +}; + +struct gef_konfiguration_mhgr_sensorik_rt { + gef_betriebsart_mhgr_sensorik_et betriebsart; + UInt8 energiesparmodus; +}; + +enum8 gef_konfiguration_ss_fir_et { + keineKonfigurationFir = 0, + fir = 1, + firSpzMarder = 2 +}; + +enum8 gef_konfiguration_ss_minenverlegung_et { + keineKonfigurationMinenverlegung = 0, + MvAnh = 1, + Wmv = 2 +}; + +enum8 gef_konfiguration_ss_standard_et { + keineKonfigurationSsStandard = 0, + ZABC = 3, + CSF = 4, + PzBr = 5, + MRF = 7 +}; + +struct gef_konfiguration_sondersenoriken_rt { + gef_konfiguration_ss_fir_et fir; + gef_konfiguration_ss_minenverlegung_et minenverlegung; + gef_konfiguration_ss_standard_et standard; +}; + +enum8 gef_agdus_hw_modus_et { + ohneHelmOhneWeste = 1, + mitHelmOhneWeste = 2, + mitHelmMitWeste = 3 +}; + +enum8 gef_konfigurations_positionsupdate_et { + Fahrzeug = 0, + Person = 1, + Luftfahrzeug = 2 +}; + +struct gef_konfiguration_anzeige_rt { + UInt8 hauptgruppe; + UInt8 untergruppe; +}; + +struct gef_konfigurationsdaten_rt { + gef_ausstattungs_id_t identitaet; + UInt16 can_startup_zeit; + unsigned char teilnehmertyp; + gef_login_parameter_rt login_parameter; + UInt32LE can_geraete_konfiguration; + gef_konfiguration_abe_rt abe; + gef_konfiguration_wirkdarstellung_rt wirkdarstellung; + gef_konfiguration_mhgr_sensorik_rt mhgr_sensorik; + gef_konfiguration_sondersenoriken_rt sondersenrik; + gef_agdus_hw_modus_et agdus_hw_modus; + gef_konfigurations_positionsupdate_et positionsupdate; + gef_konfiguration_anzeige_rt anzeige; + UInt8 wirkmodellAgdus; +}; +% +struct gef_konfiguration_teilnehmer_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_konfigurationsdaten_rt konfiguration; + gef_wirkmodell_rt wirkmodelle; +}; +/*----------------------------------------------------------------*/ +/* Lizensierung TNE-Meldung */ +/* LIZENSIERUNG_TNE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_lizenzierungsart_et { + ANMELDUNG_ERFOLGREICH = 0, + ANMELDUNG_ABGELEHNT = 1, + ABMELDUNG = 2 +}; + +struct gef_lizensierung_tne_meldung_rt { + gef_header_rt header; + gef_lizenzierungsart_et lizenzierungsart; + opaque fehlercode_lizenzierung[3]; +}; + +enum8 gef_qualifikation_et { + Undefiniert = 0, + Arzt = 1, + Sanitaeter = 2, + Ersthelfer = 3 +}; + +/*----------------------------------------------------------------*/ +/* Bestandsmeldung Saniätsmaterial */ +/* GEF_BESTANDSMELDUNG_SANITAETSMATERIAL */ +/*----------------------------------------------------------------*/ +struct gef_bestandmseldung_sanitatsmaterial_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt8 anzahl_sanmat; + UInt24 bestand_sanmaterialien; +}; + + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung PVSAN */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN */ +/*----------------------------------------------------------------*/ +struct gef_sanitetsdienst_instandsetzung_pvsan_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 massnahmen_getaetigt; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt16 massnahmen_benoetigt; +}; + +/*----------------------------------------------------------------*/ +/* Technik Funktionsraum-Meldung */ +/* TECHNIK_FUNKTIONSRAUM */ +/*----------------------------------------------------------------*/ +struct gef_technik_funktionsraum_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; + UInt8 typ; + string wirkfeldbezeichner[8]; + gef_gps_position_rt zentrum; + UInt16 breite; + UInt16 hoehe; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelgeschoss-Meldung */ +/* WIRKFELD_EINZELGESCHOSS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_munitionsart_steilfeuer_et { + STEILFEUER_AZ = 1, + STEILFEUER_HE_ANNZ = 2, + STEILFEUER_BOMBLET = 3, + STEILFEUER_SM_ART = 4, + STEILFEUER_NEBEL = 5, + MOERSER_AZ = 10, + MOERSER_ANNZ = 11, + BORDKANONE = 20, + UNGEL_RAKETE = 21, + BOMBLET = 22, + SPRENGBOMBE = 23 +}; +struct gef_beschreibung_wirkfeld_einzelgeschoss_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt einschlagort; + UInt8 wirkdurchmesser; + gef_munitionsart_steilfeuer_et munitionsart; +}; + +struct gef_wirkfeld_einzelgeschoss_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_einzelgeschoss_rt beschreibung_wirkfeld_einzelgeschoss; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt8 wirkfeldbreite; + UInt8 wirkfeldtiefe; + UInt16 drehwinkel_alt; + UInt8 mtpbreite; + UInt8 mtpdtiefe; + UInt16 drehwinkel; + UInt16 anzahl_einschlaege; + UInt16 wirkfeldradius; + gef_munitionsart_steilfeuer_et munitionsart; + UInt8 gefahrenabstand; + UInt8 gefahrenart; + gef_gps_position_rt mtp1; + gef_gps_position_rt mtp2; + gef_gps_position_rt mtp3; + gef_gps_position_rt mtp4; + +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt beschreibung_wirkfeld_flaechendeckendes_feuer; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Stop-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_STOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Fortsetzen-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt { + UInt16 wirkfeldkennung; + UInt16 fortsetzungswert_zufallszahl; + UInt16 nummer_des_naechsten_einschags; + gef_gps_zeit_rt fortsetzungszeit; + UInt16 verbleibende_wirkdauer; +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Minensperre-Meldung */ +/* WIRKFELD_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_minentyp_et { + SchtzAbwMi_DUS = 211, + SchtzAbVMi_DUS = 212, + PzAbwVMi_DUS = 213, + SchtzAbwMi_virtuell = 214, + PzAbwVMi_virtuell = 215, + PzAbwWMi_virtuell = 216, + PzAbwRiMi_AGDUS = 60 +}; + +struct gef_segment_rt { + gef_gps_position_rt startpunkt; + gef_gps_position_rt endpunkt; +}; + +struct gef_beschreibung_wirkfeld_minensperre_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt8 verlegetiefe; + UInt8 verlegedichte; + gef_minentyp_et minentyp; + UInt16 minenanzahl; + UInt8Idx anzahl_segmente; + gef_segment_rt segment<5>; +}; + +struct gef_wirkfeld_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_minensperre_rt beschreibung_wirkfeld_minensperre; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Status Minensperre-Meldung */ +/* WIRKFELD_STATUS_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_minenstatus_rt { + UInt16 wirkfeldkennung; + UInt16IdxDiv8 anzahl_minen; + opaque minenstatus<150>; +}; + +struct gef_wirkfeld_status_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_minenstatus_rt beschreibung_minenstatus; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld A-Kampfmittel-Meldung */ +/* WIRKFELD_A_KAMPFMITTEL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_a_kampfmittel_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt16 kantenlaenge_bereich_1; + UInt16 kantenlaenge_bereich_2; + UInt16 oeffnungswinkel; + UInt16 drehwinkel; +}; + +struct gef_wirkfeld_a_kampfmittel_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_a_kampfmittel_rt beschreibung_wirkfeld_a_kampfmittel; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld C-Kampfstoff-Meldung */ +/* WIRKFELD_C_KAMPFSTOFF_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_kampfstofftyp_et { + fluechtig = 1, + sesshaft = 2 +}; + +struct gef_beschreibung_wirkfeld_c_kampfstoff_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt8 vergroesserungsfaktor; + UInt16 windrichtung; + UInt8 windgeschwindigkeit; + gef_gps_zeit_rt gueltigkeitszeitpunkt_wetterdaten; + gef_gps_position_rt position_gueltigkeitszeitpunkt_wetterdaten;; + UInt8 kampfstoffkennung; + gef_kampfstofftyp_et kampfstofftyp; +}; + +struct gef_wirkfeld_c_kampfstoff_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_c_kampfstoff_rt beschreibung_wirkfeld_c_kampfstoff; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung-Wirkfeld-Meldung */ +/* DEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_wirkfeldtyp_et { + Undefined = 0, + Minensperre = 1, + Steilfeuer_Flaeche = 2, + Steilfeuer_Einzel = 3, + A_Waffe = 4, + C_Waffe = 5, + Funktionsraum = 6, + TechnicalArea = 7, + DusSingleMineSimulator = 8, + GasPipeDetonation = 9, + SpecialArea = 10, + BeStillWarning = 11, + DangerZoneExplosion = 12, + AirSupport = 13 +}; + +struct gef_deaktivierung_wirkfeld_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Aenderung Bezeichner-Meldung */ +/* WIRKFELD_AENDERUNG_BEZEICHNER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_aenderung_bezeichner_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung Einzelmine-Meldung */ +/* DEAKTIVIERUNG_EINZELMINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivierung_einzelmine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_gps_zeit_rt GPS_Zeit; + UInt16 wirkfeldkennung; + UInt16 minenindex; +}; + + + +/*----------------------------------------------------------------*/ +/* Reaktivierung DUS Mine-Meldung */ +/* REAKTIVIERUNG_DUS_MINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_Minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_reaktivierung_dus_mine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_dus_minenkennungen_rt DUS_minenkennungen; +}; + +/*----------------------------------------------------------------*/ +/* Definition-IED */ +/* DEFINITION_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_typ_et { + S_IED = 1, + IED_innen = 2, + IED_aussen = 3 +}; + +enum8 gef_ied_kopplungsstatus_et { + IED_keine_Kopplung = 1, + IED_Kopplung_an_Tln = 2, + IED_Kopplung_an_IPS = 3 +}; + +enum8 gef_ied_takitscher_zustand_et { + IED_inaktiv = 0, /* verlegt und gesichert */ + IED_aktiv = 1, /* scharf */ + IED_geloescht = 2, /* entschaerft */ + IED_ausgeloest_Schalter = 3, + IED_ausgeloest_Fernbedienung = 4, + IED_ausgeloest_Lichtschranke = 5, + IED_ausgeloest_Zugdraht = 6, + IED_ausgeloest_Kontrollgeraet = 7, + IED_unbekannt = 255 /* Kontakt verloren */ +}; + +struct gef_definition_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_typ_et typ; + UInt8 ausloeser; + UInt8 sprengkraft; + gef_gps_position_rt gps_position; + UInt8 partei_id; + gef_ied_kopplungsstatus_et kopplungsstatus; + gef_ausstattungs_id_t gekoppelte_id; + gef_ied_takitscher_zustand_et taktischer_zustand; /* 0 inaktiv, 1 aktiv */ + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ +}; + +/*----------------------------------------------------------------*/ +/* Zustand-IED */ +/* ZUSTAND_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_fehler_et { + IED_kein_Fehler = 0, + IED_Kommunikations_Fehler = 1 +}; + +struct gef_zustand_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_takitscher_zustand_et taktischer_zustand; + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ + UInt8 batteriewarnung; /* Bitleiste */ + gef_ied_fehler_et fehler_status_elektronik; + gef_ied_fehler_et fehler_status_pyrotechnik1; + gef_ied_fehler_et fehler_status_pyrotechnik2; + gef_ied_fehler_et fehler_status_pyrotechnik3; +}; + + +/*----------------------------------------------------------------*/ +/* Treffer Ausloesung-Meldung */ +/* TREFFER_AUSLOESUNG_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_verwundung_beschaedigung_et { + Einsatzbereit = 0, + Leichter_Treffer = 1, + Mittlerer_Treffer = 2, + Schwerer_Treffer = 3, + Bewegungsunfaehig = 4, + Bewegungsunfaehig_sichtbar = 5, + Ausfall_Waffenanlage = 6, + Ausfall_Waffenanlage_sichtbar = 7, + Totalausfall_sichtbar = 8, + Zeitlicher_Ausfall = 9, + Annaehernder_Treffer = 10, + Treffer_ohne_Wirkung = 11 +}; + +struct gef_treffer_ausloesung_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_verwundung_beschaedigung_et verwundung_beschaedigung; +}; + +/*----------------------------------------------------------------*/ +/* Status Einzelminensimulator */ +/* STATUS_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_status_einzelminensimulator_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 minenkennung; + gef_gps_position_rt gps_position; + UInt8 minentyp; + UInt8 status; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelminensimulator */ +/* WIRKFELD_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_einzelminensimulator_rt { + UInt16 wirkfeldkennung; + UInt8 partei_id; + UInt16 minenkennung; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt minenposition; + UInt8 minentyp; +}; + +struct gef_wirkfeld_einzelminensimulator_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_einzelminensimulator_rt beschreibung_einzelminensimulator; +}; + +/*----------------------------------------------------------------*/ +/* Schiedsrichtereingriff */ +/* SCHIEDSRICHTEREINGRIFF */ +/*----------------------------------------------------------------*/ +/* +struct gef_schiedsrichtereingriff_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_gps_position_rt gps_position; + UInt16 schiedsrichter_aktion; + UInt8 schiedsrichter; +}; + + + +/*----------------------------------------------------------------*/ +/* Selektive Aufmunitionierung */ +/* GEF_SELEKTIVE_AUFMUNITIONIERUNG */ +/*----------------------------------------------------------------*/ +struct gef_aufmunitionierung_rt { + UInt16 munitionsart; + UInt8 ort; /* Turm / Wanne */ + UInt16 neuer_vorrat; /* 0xffff = default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt16 neuer_default_vorrat; /* 0xffff = factory default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt8 tracer_ratio; /* 0 = kein Trace, 1 = jedes Projektil, 2 = jedes 2. Projektil, ... */ +}; + +struct gef_selektive_aufmunitionierung_rt { + gef_header_rt header; + u_int waffen_id; + UInt8Idx anzahl_aufmunitionierungen; + gef_aufmunitionierung_rt aufmunitionierung<10>; +}; + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_behandlungs_ergebnis_et { + Keine = 0, + Erfolg = 1, + Stabilisiert = 2, + Fehler = 3 +}; + +struct gef_sanitetsdienst_instandsetzung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt8 verurschaer_typ; + UInt16 ausstattung_behandelnder; + gef_verwundung_beschaedigung_et status_start; + UInt8 typ_der_behandlung; + UInt8 triage; + UInt8 typ_der_behandlung; + gef_verwundung_beschaedigung_et status_ergebnis; + gef_behandlungs_ergebnis_et ergebhnis_behandlung; + UInt8 triage_priorität; + UInt8 komplett_status; + UInt24 behandlungszeit; + UInt24 erholungszeit; +}; + + + +*/ +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_betriebsmodus_et { + Nicht_vorhanden = 0, + Eingriff_durch_schiedsrichter = 1, + Wartezeit_nach_Erreichen_des_Funktionsraums = 2 +}; + +struct gef_funktionsraum_rt { + gef_betriebsmodus_et betriebsmodus; + UInt8 wartezeit; +}; + +struct gef_beschreibung_funktionsraum_rt { + UInt16 funktionsraumkennung; + string funktionsraumbezeichner[8]; + UInt8 partei_id; + gef_gps_position_rt funktionsraumeckpunkt; + UInt8 funktionsraumbreite; + UInt8 funktionsraumtiefe; + gef_funktionsraum_rt funktionsraum_fuer_entgiftungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_instandsetzungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_sandienstliche_versorgung; +}; + +struct gef_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_funktionsraum_rt beschreibung_funktionsraum; +}; + + + +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivieren_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 funktionsraumkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-SRT-Meldung */ +/* DATENVERKEHR_TDS_SRT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_fuer_tne_transparente_daten_rt { + opaque data<30>; /* 30 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_srt_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-DMF-Meldung */ +/* DATENVERKEHR_TDS_DMF_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_datenverkehr_tds_dmf_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Steuerung Verkehrsaufkommen-Meldung */ +/* STEUERUNG_VERKEHRSAUFKOMMEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_steuerung_verkehrsaufkommen_meldung_rt { + gef_header_rt header; + gef_lastzustand_datenfunk_et lastzustand_datenfunk; + UInt16 inhibit_zeit_fuer_positionsmeldungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Nachforderung Broadcast Telegramme-Meldung */ +/* NACHFORDERUNG_BROADCAST_TELEGRAMME_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachforderung_broadcast_telegramme_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + UInt8 ruecksetzzaehler; + UInt16 broadcast_index; +}; + + + +/*----------------------------------------------------------------*/ +/* Nop-Meldung */ +/* NOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_broadcasttelegramme_rt { + UInt16 feld_anfang; + UInt16 feld_ende; +}; + +struct gef_nop_meldung_rt { + gef_header_rt header; + gef_broadcasttelegramme_rt broadcasttelegramme; +}; + + + +/*----------------------------------------------------------------*/ +/* Sprachauswahl-Meldung */ +/* SPRACHAUSWAHL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_sprachauswahl_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sprache_et sprachauswahl; +}; + + + +/*----------------------------------------------------------------*/ +/* Allgemeine Nachricht-Meldung */ +/* ALLGEMEINE_NACHRICHT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachricht_rt { + UInt8Idx laenge; + string text<80>; +}; + +struct gef_allgemeine_nachricht_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_nachricht_rt nachricht; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Wirkfeld-Meldung */ +/* SAMMELDEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_wirkfeldkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 wirkfeldkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_wirkfeldkennungen_rt liste_der_wirkfeldkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung DUS-Minen-Meldung */ +/* SAMMELDEAKTIVIERUNG_DUS_MINEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_wf_sammeldeaktivierung_dus_minen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_dus_minenkennungen_rt liste_DUS_minenkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Funktionsraum-Meldung */ +/* SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_funktionsraumkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 funktionsraumkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_funktionsraumkennungen_rt liste_der_funktionsraumkennungen; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-GeoP-Meldung */ +/* DATENVERKEHR_TDS_GEOP_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_geop_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_geop_meldung_rt { + gef_header_rt header; + UInt8 laenge_GeoP_Daten; + gef_geop_daten_rt geop_daten; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-TgtS-Meldung */ +/* DATENVERKEHR_TDS_TGTS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_tgts_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_tgts_meldung_rt { + gef_header_rt header; + UInt8 laenge_tgts_Daten; + gef_tgts_daten_rt tgts_daten; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration IPS-Meldung */ +/* KONFIGURATION_IPS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zuordnung_rt { + UInt16 raumnummer_des_gebaeudemodell; + UInt16 IPS_Platz_des_gebaeudemodell; + UInt16 IPS_Kennung; +}; + +struct gef_ips_konfiguration_rt { + UInt8Idx anzahl; + gef_zuordnung_rt zuordnung<255>; +}; + +struct gef_konfiguration_ips_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_ips_konfiguration_rt ips_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG */ +/*----------------------------------------------------------------*/ +struct gef_treffer_ereignis_sekundaerwirkung_rt { + gef_header_rt header; + gef_gps_zeit_rt wirkbeginn; + UInt16 munCode; + UInt16 verursacher; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt8 effectCode; + UInt16 minenIndex; + UInt16 unused; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration ZEG-Meldung */ +/* KONFIGURATION_ZEG_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zeg_zuordnung_rt { + UInt16 referenzmodul_des_gebaeudemodell; + UInt16 ZEG_Kennung; +}; + +struct gef_zeg_konfiguration_rt { + UInt8Idx anzahl; + gef_zeg_zuordnung_rt zeg_zuordnung<255>; +}; + +struct gef_konfiguration_zeg_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_zeg_konfiguration_rt zeg_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* Ausloseung DUS-Treffer */ +/* GEF_AUSLOESUNG_DUS_TREFFER */ +/*----------------------------------------------------------------*/ +struct gef_ausloesung_dus_treffer_rt { + gef_header_rt header; + gef_gps_zeit_rt zeit; + UInt8Idx munitionsart; + UInt16 richtung; + UInt16 entfernung; + UInt8Idx wirkung; + UInt16 verursacher; +}; +/*----------------------------------------------------------------*/ +/* GEF_ANFORDERUNG_SW_VERSION */ +/* GEF_SW_VERSIONSMELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_anforderung_sw_version_rt { + gef_header_rt header; + UInt16 geraetekennung; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_SETZEN (Zentrale -> SFM) */ +/*----------------------------------------------------------*/ +enum8 gef_tln_sprache_et { + TLN_SPRACHE_KEINE_AENDERUNG = 0, + TLN_SPRACHE_DE = 1, + TLN_SPRACHE_EN = 2, + TLN_SPRACHE_FR = 3, + TLN_SPRACHE_AR = 4, + TLN_SPRACHE_ES = 5, + TLN_SPRACHE_RU = 6 +}; + +enum8 gef_operation_mode_et { + OP_MODE_KEINE_AENDERUNG = 0, + OP_MODE_NORMAL = 1, + OP_MODE_BE_STILL = 2 +}; + +enum8 gef_wph_mode_weste_et { + WPH_MODE_WESTE_KEINE_AENDERUNG = 0, + WPH_MODE_WESTE_OHNE = 1, + WPH_MODE_WESTE_MIT = 2 +}; + +enum8 gef_wph_mode_helm_et { + WPH_MODE_HELM_KEINE_AENDERUNG = 0, + WPH_MODE_HELM_OHNE = 1, + WPH_MODE_HELM_MIT = 2 +}; + +enum8 gef_wph_mode_personenschutz_et { + WPH_MODE_PERSONENSCHUTZ_KEINE_AENDERUNG = 0, + WPH_MODE_PERSONENSCHUTZ_OHNE = 1, + WPH_MODE_PERSONENSCHUTZ_ANZUG = 2, + WPH_MODE_PERSONENSCHUTZ_ANZUG_HANDSCHUHE_SCHUHE = 3 +}; + +enum8 gef_schutzniveau_et { + SN_SCHUTZ_KEINE_AENDERUNG = 0, + SN_IDZ_ES = 1, + SN_IDZ_BS = 2, + SN_KSK = 3, + SN_SOLDAT_MIT_KOERPERSCHUTZ = 4, + SN_SOLDAT_DARSTELLER = 5 +}; + +enum8 gef_handgranaten_suche_et { + HS_KEINE_AENDERUNG = 0, + HS_SUCHE_AUS = 1, + HS_SUCHE_EIN = 2 +}; + +enum8 gef_international_mode_et { + IM_KEINE_AENDERUNG = 0, + IM_AUS = 1, + IM_EIN = 2 +}; + +/* Reaktivierung: in Minuten (0, 10 .. 2550) */ +struct gef_teilnehmermode_rt { + gef_tln_sprache_et sprache; + gef_operation_mode_et op_mode; + UInt8 reaktivierung_entgiftung; + UInt8 reaktivierung_inst; + UInt8 reaktivierung_sanitaet; + gef_wph_mode_personenschutz_et:1..3 mode_personenschutz; + gef_wph_mode_weste_et:4..5 mode_weste; + gef_wph_mode_helm_et:6..7! mode_helm; + gef_schutzniveau_et schutzniveau; + gef_handgranaten_suche_et:6..7! handgranaten_suche; + gef_international_mode_et:4..5 international_mode; +}; + +struct gef_teilnehmermode_setzen_rt { + gef_header_rt header; + UInt16 bcIndex; + gef_teilnehmermode_rt mode; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_MELDUNG (SFM -> Zentrale) */ +/*----------------------------------------------------------*/ +struct gef_teilnehmermode_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_teilnehmermode_rt mode; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_SETZEN */ +/*----------------------------------------------------------------*/ + +enum8 gef_positions_handling_et { + POS_HANDLING_DEFAULT = 0, + POS_HANDLING_UNGUELTIG_NICHT_SCHICKEN = 1, + POS_HANDLING_UNGUELTIG_KENNZEICHNEN = 2, + POS_HANDLING_UNGUELTIG_SCHICKEN = 3 +}; + +enum8 gef_optischer_code_et { + OPTISCHER_CODE_KEINE_AENDERUNG = 0, + OPTISCHER_CODE_OSAG_1_0 = 1, + OPTISCHER_CODE_OSAG_2_0_BASIC = 2 +}; + +struct gef_sfm_konfig_rt { + UInt16 pos_aenderung_fz; + UInt16 pos_aenderung_personal; + UInt16 pos_aenderung_lfz; + UInt16 pos_uebertragungs_interval; + UInt16 hoehengrenze; + gef_positions_handling_et:6..7 positions_handling; + UInt8Idx:0..1! pos_interval_umschaltung; + UInt16 wartezeit_nachforderung; + UInt8 faktor_wartezeit_hochlast; + UInt8 wartezeit_vbg_1_2; + UInt8 wartezeit_vbg_2_3; + UInt8 wartezeit_vbg_3_8; + gef_optischer_code_et optischer_code; + UInt8 verwundungsmodel; + UInt8 gueltigkeitsdauer_standortbestimmung; +}; + +struct gef_teilnehmer_konfig_setzen_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sfm_konfig_rt konfig; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_ANTWORT */ +/*----------------------------------------------------------------*/ + +struct gef_teilnehmer_konfig_antwort_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_sfm_konfig_rt konfig; +}; + +/*-------------------------------------------------------*/ +/* GEF_NOTRUF */ +/*-------------------------------------------------------*/ + +struct gef_notruf_rt { + gef_gps_position_rt gps_position; +}; + +/*==============================================================*/ +/* Zusammenfassung der Telegramm-Typen */ +/*==============================================================*/ +union gef_tg_nd_ switch (gef_telegramm_id_et telegramm_id) { + + case GEF_INIT: + gef_init_meldung_rt init_meldung; + + case GEF_MANIPULATIONSMELDUNG: + case GEF_BITE_MELDUNG: + case GEF_BITE_MELDUNG2: + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: + case GEF_FEHLERMELDUNG_GFD: + case GEF_POSITIONS_MELDUNG: + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + case GEF_POSITIONS_MELDUNG_LFZ: + case GEF_FEUER_EREIGNIS: + case GEF_TREFFER_EREIGNIS_DUS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: + case GEF_TAKTISCHER_STATUS: + case GEF_TREFFER_EREIGNIS_DUS_IPS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: + case GEF_EINTRETEN_FUNKTIONSRAUM: + case GEF_DATENVERKEHR_SRT_TDS: + case GEF_DATENVERKEHR_DMF_TDS: + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + case GEF_SONDERSENSORIK_FAHRSPUR: + case GEF_SONDERSENSORIK_DATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + case GEF_DATENVERKEHR_GEOP_TDS: + case GEF_DATENVERKEHR_TGTS_TDS: + case GEF_GERAETEEREIGNIS: + case GEF_WAFFENZUORDNUNG: + case GEF_IPS_POSITIONSDATEN: + case GEF_STANDORTBESTIMMUNG: + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + case GEF_ANFORDERUNG_KONFIG_ZEG: + case GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG: + case GEF_TREFFEREREIGNIS_GEBAEUDE: + case GEF_TEILNEHMERMODE_ANFORDERN: + case GEF_TEILNEHMER_KONFIG_ANFORDERN: + case GEF_SCHIEDSRICHTEREINGRIFF: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + gef_selektive_aufmunitionierung_rt selektive_aufmunitionierung; + + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + gef_sanitetsdienst_instandsetzung_rt sanitetsdienst_instandsetzung; + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + gef_bestandmseldung_sanitatsmaterial_rt bestandmseldung_sanitatsmaterial; + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + gef_sanitetsdienst_instandsetzung_pvsan_rt sanitetsdienst_instandsetzung_pvsan; + case GEF_TECHNIK_FUNKTIONSRAUM: + gef_technik_funktionsraum_rt technik_funktionsraum; + case GEF_UMGEBUNGS_MELDUNG: + gef_umgebungs_meldung_rt umgebungs_meldung; + + case GEF_UMGEBUNGS_MELDUNG2: + gef_umgebungs_meldung2_rt umgebungs_meldung2; + + case GEF_AUFFORDERUNG_BITE_MELDUNG: + gef_aufforderung_bite_meldung_rt aufforderung_bite_meldung; + + case GEF_LIZENSIERUNG_TNE: + gef_lizensierung_tne_meldung_rt linzensierung_tne_meldung; + + case GEF_KONFIGURATION_TEILNEHMER: + gef_konfiguration_teilnehmer_rt konfiguration_teilnehmer; + + case GEF_KONFIGURATION_WIRKMODELL: + gef_konfiguration_wirkmodell_rt konfiguration_wirkmodell; + + case GEF_TEILNEHMERMODE_SETZEN: + gef_teilnehmermode_setzen_rt teilnehmermode_setzen; + + case GEF_TEILNEHMERMODE_MELDUNG: + gef_teilnehmermode_meldung_rt teilnehmermode_meldung; + + case GEF_TEILNEHMER_KONFIG_SETZEN: + gef_teilnehmer_konfig_setzen_rt teilnehmer_konfig_setzen; + + case GEF_TEILNEHMER_KONFIG_ANTWORT: + gef_teilnehmer_konfig_antwort_rt teilnhemer_konfig_antwort; + +/* case GEF_POSITIONSKORREKTURDATEN: + */ + + case GEF_WIRKFELD_EINZELGESCHOSS: + gef_wirkfeld_einzelgeschoss_meldung_rt wirkfeld_einzelgeschoss_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + gef_wirkfeld_flaechendeckendes_feuer_meldung_rt wirkfeld_flaechendeckendes_feuer_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt wirkfeld_flaechendeckendes_feuer_stop_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung; + + case GEF_WIRKFELD_MINENSPERRE: + gef_wirkfeld_minensperre_meldung_rt wirkfeld_minensperre_meldung; + + case GEF_WIRKFELD_STATUS_MINENSPERRE: + gef_wirkfeld_status_minensperre_meldung_rt wirkfeld_status_minensperre_meldung; + + case GEF_WIRKFELD_A_KAMPFMITTEL: + gef_wirkfeld_a_kampfmittel_meldung_rt wirkfeld_a_kampfmittel_meldung; + + case GEF_WIRKFELD_C_KAMPFSTOFF: + gef_wirkfeld_c_kampfstoff_meldung_rt wirkfeld_c_kampfstoff_meldung; + + case GEF_DEAKTIVIERUNG_WIRKFELD: + gef_deaktivierung_wirkfeld_meldung_rt deaktivierung_wirkfeld_meldung; + + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + gef_wirkfeld_aenderung_bezeichner_meldung_rt wirkfeld_aenderung_bezeichner_meldung; + + case GEF_DEAKTIVIERUNG_EINZELMINE: + gef_deaktivierung_einzelmine_meldung_rt deaktivierung_einzelmine_meldung; + + case GEF_REAKTIVIERUNG_DUS_MINE: + gef_reaktivierung_dus_mine_meldung_rt reaktivierung_dus_mine_meldung; + + case GEF_DEFINITION_IED: + gef_definition_ied_rt definition_ied; + + case GEF_ZUSTAND_IED: + gef_zustand_ied_rt zustand_ied; + + case GEF_STATUS_EINZELMINENSIMULATOR: + gef_status_einzelminensimulator_rt status_einzelminensimulator_rt; + + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + gef_wirkfeld_einzelminensimulator_rt wirkfeld_einzelminensimulator_rt; + + case GEF_TREFFER_AUSLOESUNG: + gef_treffer_ausloesung_meldung_rt treffer_ausloesung_meldung; + + case GEF_FUNKTIONSRAUM: + gef_funktionsraum_meldung_rt funktionsraum_meldung; + + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + gef_deaktivieren_funktionsraum_meldung_rt deaktivieren_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_SRT: + gef_datenverkehr_tds_srt_meldung_rt datenverkehr_tds_srt_meldung; + + case GEF_DATENVERKEHR_TDS_DMF: + gef_datenverkehr_tds_dmf_meldung_rt datenverkehr_tds_dmf_meldung_meldung; + + case GEF_STEUERUNG_VERKEHRSAUFKOMMEN: + gef_steuerung_verkehrsaufkommen_meldung_rt steuerung_verkehrsaufkommen_meldung; + + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + gef_nachforderung_broadcast_telegramme_meldung_rt nachforderung_broadcast_telegramme_meldung; + + case GEF_NOP: + gef_nop_meldung_rt nop_meldung; + + case GEF_SPRACHAUSWAHL: + gef_sprachauswahl_meldung_rt sprachauswahl_meldung; + + case GEF_ALLGEMEINE_NACHRICHT: + gef_allgemeine_nachricht_meldung_rt allgemeine_nachricht_meldung; + +/* case GEF_ECHO_ON_OFF: + case GEF_ESW_MELDUNG: + case GEF_GEFECHTSFELDTELEGRAMM: */ + + case GEF_WF_SAMMELDEAKTIVIERUNG: + gef_wf_sammeldeaktivierung_meldung_rt wf_sammeldeaktivierung_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + gef_wf_sammeldeaktivierung_dus_minen_meldung_rt wf_sammeldeaktivierung_dus_minen_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt wf_sammeldeaktivierung_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_GEOP: + gef_datenverkehr_tds_geop_meldung_rt datenverkehr_tds_geop_meldung; + + case GEF_DATENVERKEHR_TDS_TGTS: + gef_datenverkehr_tds_tgts_meldung_rt datenverkehr_tds_tgts_meldung; + + case GEF_KONFIGURATION_IPS: + gef_konfiguration_ips_meldung_rt konfiguration_ips_meldung; + + case GEF_KONFIGURATION_ZEG: + gef_konfiguration_zeg_meldung_rt konfiguration_zeg_meldung; + + case GEF_AUSLOESUNG_DUS_TREFFER: + gef_ausloesung_dus_treffer_rt gef_ausloesung_dus_treffer; + + case GEF_ANFORDERUNG_SW_VERSION: + gef_anforderung_sw_version_rt anforderung_sw_version; + case GEF_SW_VERSIONSMELDUNG: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + gef_treffer_ereignis_sekundaerwirkung_rt treffer_ereignis_sekundaerwirkung; + + case GEF_NOTRUF: + gef_notruf_rt notruf; + + default: + void; +}; + +/* +struct dafu_tele { + u_long telegramm_zaehler; + unsigned short telegramm_prioritaet; + gef_tg_nd_ daten; +}; +*/ diff --git a/TetraIF/PrtCnv/AppComponent.cpp b/TetraIF/PrtCnv/AppComponent.cpp new file mode 100644 index 000000000..c81081775 --- /dev/null +++ b/TetraIF/PrtCnv/AppComponent.cpp @@ -0,0 +1,88 @@ + + + + + + + + + + + + + +#include "AppComponent.hpp" + +namespace N_AppComponent +{ + +int32_t AppComponent::create(NGL::Settings *settings) +{ + for (IAppComponent *c : m_Childs) + c->create(settings); + return 0; +} + + +int32_t AppComponent::destroy() +{ + for (IAppComponent *c : m_Childs) + c->destroy(); + return 0; +} + + +int32_t AppComponent::init() +{ + for (IAppComponent *c : m_Childs) + c->init(); + return 0; +} + + +int32_t AppComponent::deinit() +{ + for (IAppComponent *c : m_Childs) + c->deinit(); + return 0; +} + + +int32_t AppComponent::start() +{ + for (IAppComponent *c : m_Childs) + c->start(); + return 0; +} + + +int32_t AppComponent::stop() +{ + for (IAppComponent *c : m_Childs) + c->stop(); + return 0; +} + + +void AppComponent::addChild(IAppComponent *a_child, const QString &a_name) +{ + if (a_child) + { + a_child->setName(a_name); + m_Childs.push_back(a_child); + } +} + + +IAppComponent *AppComponent::getChild(const QString &a_name) +{ + for (IAppComponent *c : m_Childs) + { + if (a_name == c->getName()) + return c; + } + return nullptr; +} + +} + diff --git a/TetraIF/PrtCnv/AppComponent.hpp b/TetraIF/PrtCnv/AppComponent.hpp new file mode 100644 index 000000000..e129a0403 --- /dev/null +++ b/TetraIF/PrtCnv/AppComponent.hpp @@ -0,0 +1,45 @@ + + + + + + + + + + + + +#pragma once + +#include +#include "IAppComponent.hpp" +#include + +namespace NGL { +class Settings; +} + +namespace N_AppComponent +{ +class PRTCNVLIB_EXPORT AppComponent : public N_AppComponent::IAppComponent +{ +public: + AppComponent() = default; + ~AppComponent() = default; + + + int32_t create(NGL::Settings *settings) override; + int32_t deinit() override; + int32_t destroy() override; + int32_t init() override; + int32_t start() override; + int32_t stop() override; + +protected: + void addChild(IAppComponent* a_child, const QString& a_name = QString()); + IAppComponent* getChild(const QString& a_name); +private: + std::vector m_Childs; +}; +} diff --git a/TetraIF/PrtCnv/CMakeLists.txt b/TetraIF/PrtCnv/CMakeLists.txt new file mode 100644 index 000000000..9d01e7289 --- /dev/null +++ b/TetraIF/PrtCnv/CMakeLists.txt @@ -0,0 +1,78 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + + +#ADD_SUBDIRECTORY(TetraTestServer) +ADD_SUBDIRECTORY(LastTest) +ADD_SUBDIRECTORY(LastTestAuswertung) + +SET(PrtCnv_SRCS + logger.h + logger.cpp + + AppComponent.cpp + AppComponent.hpp + IAppComponent.hpp + PrtCnvApplication.cpp + PrtCnvApplication.hpp + PrtCnvBroadcastMgr.cpp + PrtCnvBroadcastMgr.hpp + PrtCnvCentralThread.cpp + PrtCnvCentralThread.hpp + PrtCnvDbThread.cpp + PrtCnvDbThread.hpp + PrtCnvInjectionSocket.cpp + PrtCnvInjectionSocket.hpp + PrtCnvInjectionThread.cpp + PrtCnvInjectionThread.hpp + PrtCnvMember.cpp + PrtCnvMember.hpp + PrtCnvRadioThread.cpp + PrtCnvRadioThread.hpp + PrtCnvRadioTrafficThread.cpp + PrtCnvRadioTrafficThread.hpp + PrtCnvSocketThread.cpp + PrtCnvSocketThread.hpp + PrtCnvStoredCentralTelegram.hpp + PrtCnvStoredRadioTelegram.hpp + PrtCnvStoredTelegram.hpp + PrtCnvTelegramLogThread.cpp + PrtCnvTelegramLogThread.hpp + PrtCnvThread.cpp + PrtCnvThread.hpp + PrtCnvThreadStarter.cpp + PrtCnvThreadStarter.hpp +) + +NGL_ADD_LIBRARY2(AAR SV PrtCnvLib SHARED ${PrtCnv_SRCS}) +NGL_TARGET_LINK_LIBRARIES(PrtCnvLib + PRIVATE + ngldb + nglsettings + LtsUtilsCoreHeaderOnly + Qt5::Sql + Qt5::WebSockets + PUBLIC + CoPrtCnv + Qt5::Core + Qt5::Network + NGLLogger +) +NGL_TARGET_INCLUDE_DIRECTORIES(PrtCnvLib + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +NGL_ADD_EXECUTABLE(AAR SV PrtCnv PrtCnvMain.cpp) +NGL_TARGET_LINK_LIBRARIES(PrtCnv + PrtCnvLib + Qt5::Core + LtsCommandLineParser + nglcoreapplication +) +NGL_INSTALL_TARGET(PrtCnv) +NGL_INSTALL(AAR SV FILES log4cxx_prtcnv.props DESTINATION bin) +NGL_INSTALL(AAR SV FILES PrtCnv.dat.tts DESTINATION bin) diff --git a/TetraIF/PrtCnv/IAppComponent.hpp b/TetraIF/PrtCnv/IAppComponent.hpp new file mode 100644 index 000000000..44b7138c3 --- /dev/null +++ b/TetraIF/PrtCnv/IAppComponent.hpp @@ -0,0 +1,59 @@ + + + + + + + + + + + + +#pragma once + +#include + +namespace NGL { + class Settings; +} + +namespace N_AppComponent +{ + class IAppComponent + { + public: + IAppComponent() = default; + virtual ~IAppComponent() = default; + + virtual int32_t create(NGL::Settings *settings) = 0; + + + virtual int32_t deinit() = 0; + + + virtual int32_t destroy() = 0; + + + virtual int32_t init() = 0; + + + virtual int32_t start() = 0; + + + virtual int32_t stop() = 0; + + + inline const QString& getName() const + { + return m_Name; + } + inline void setName(const QString& newVal) + { + m_Name = newVal; + } + protected: + QString m_Name; + }; + +} diff --git a/TetraIF/PrtCnv/LastTest/CMakeLists.txt b/TetraIF/PrtCnv/LastTest/CMakeLists.txt new file mode 100644 index 000000000..5bd0aca8a --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(my_SRCS + main.cpp + tetra_if.cpp + tetra_if.h +) + +NGL_ADD_EXECUTABLE(AAR SV PrtCnvLastTest ${my_SRCS}) +NGL_TARGET_LINK_LIBRARIES(PrtCnvLastTest + Qt5::Core + Qt5::Network + CoPrtCnv + NGLLogger + ngltools +) +NGL_INSTALL_TARGET(PrtCnvLastTest) diff --git a/TetraIF/PrtCnv/LastTest/main.cpp b/TetraIF/PrtCnv/LastTest/main.cpp new file mode 100644 index 000000000..c13be4fad --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/main.cpp @@ -0,0 +1,62 @@ + + +#include +#include +#include +#include +#include +#include "tetra_if.h" + +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + + NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx_tetra.props", false); + + NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()); + + const QStringList args = app.arguments().mid(1); + if (args.count() < 4) + TetraIF::usage(); + QHostAddress tetra(args[0]); + if (tetra.isNull()) + { + ERROR_LOG(logger) << "Invalid IP address " << args[0]; + TetraIF::usage(); + } + bool bOk; + unsigned short port = args[1].toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Invalid IP port " << args[1]; + TetraIF::usage(); + } + unsigned short issi = args[2].toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Invalid ISSI id " << args[2]; + TetraIF::usage(); + } + const QString mode = args[3].toLower(); + if (mode != QLatin1String("listen") && + mode != QLatin1String("send_random") && + mode != QLatin1String("send_file")) + { + ERROR_LOG(logger) << "Invalid mode " << args[3]; + TetraIF::usage(); + } + TetraIF t(tetra, port, issi); + if (mode == QLatin1String("listen")) + t.listenMode(args.mid(4)); + else if (mode == QLatin1String("send_random")) + t.randomMode(args.mid(4)); + else if (mode == QLatin1String("send_file")) + t.fileMode(args.mid(4)); + + t.start(); + + return app.exec(); +} diff --git a/TetraIF/PrtCnv/LastTest/tetra_if.cpp b/TetraIF/PrtCnv/LastTest/tetra_if.cpp new file mode 100644 index 000000000..78aa2d235 --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/tetra_if.cpp @@ -0,0 +1,503 @@ + + +#include "tetra_if.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +TetraIF::TetraIF(const QHostAddress &addr, unsigned short port, unsigned short issi) + : QObject() + , m_addr(addr) + , m_port(port) + , m_issi(issi) + , m_socket(new QTcpSocket(this)) + , m_count(0) + , m_telegramsPerSecond(0) + , m_telegramsInCurSecond(0) + , m_secondFragment(0) + , m_timer(nullptr) + , m_SendCounter(0) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()) + +{ + connect(m_socket, &QTcpSocket::connected, this, &TetraIF::onConnected); + connect(m_socket, &QTcpSocket::disconnected, this, &TetraIF::onDisconnected); + connect(m_socket, &QTcpSocket::readyRead, this, &TetraIF::onReadyRead); + connect(m_socket, QOverload::of(&QTcpSocket::error), this, &TetraIF::onError); + + m_outputDir = QCoreApplication::applicationDirPath(); + m_outputDir += QLatin1Char('/') + QString::number(m_issi) + QLatin1Char('-'); +} + +void TetraIF::start() +{ + m_socket->connectToHost(m_addr, m_port); +} + +void TetraIF::listenMode(const QStringList &args) +{ + + if (args.count() > 1) + usage(); + m_outputDir = QCoreApplication::applicationDirPath(); + if (args.count() == 1) + m_outputDir = args[0]; + if (!QDir().mkpath(m_outputDir)) + { + ERROR_LOG(m_logger) << "Error creating directory " + << m_outputDir; + usage(); + } + + m_outputDir += QLatin1Char('/') + QString::number(m_issi) + QLatin1Char('-'); +} + +void TetraIF::randomMode(const QStringList &args) +{ + if (args.count() < 3) + { + ERROR_LOG(m_logger) << "Invalid argument count"; + usage(); + } + bool bOk; + int dataSize = args[0].toInt(&bOk); + if (!bOk || dataSize > 256 || dataSize < 0) + { + ERROR_LOG(m_logger) << "Invalid data size " << args[0]; + usage(); + } + m_count = args[1].toInt(&bOk); + if (!bOk || m_count == 0 || m_count < -1) + { + ERROR_LOG(m_logger) << "Invalid count " << args[1]; + usage(); + } + m_telegramsPerSecond = args[2].toInt(&bOk); + if (!bOk || m_telegramsPerSecond < 1) + { + ERROR_LOG(m_logger) << "Invalid telegrams/second " << args[2]; + usage(); + } + m_data.reserve(dataSize); + for (int i = 0; i < dataSize; ++i) + m_data += (i % 256); + + parseISSIs(args.mid(3)); + + INFO_LOG(m_logger) << "Sending " << m_data.size() + << " bytes, " << m_telegramsPerSecond + << " telegrams/second for " << m_count + << " time(s) to issi(s) " << getIssisAsString(); + + setupTimer(); +} + +void TetraIF::fileMode(const QStringList &args) +{ + if (args.count() < 3) + { + ERROR_LOG(m_logger) << "Invalid argument count"; + usage(); + } + QFile f(args[0]); + if (!f.exists() || f.size() > 256) + { + ERROR_LOG(m_logger) << "Invalid file: " << args[0]; + usage(); + } + bool bOk; + m_count = args[1].toInt(&bOk); + if (!bOk || m_count == 0 || m_count < -1) + { + ERROR_LOG(m_logger) << "Invalid count " << args[1]; + usage(); + } + m_telegramsPerSecond = args[2].toInt(&bOk); + if (!bOk || m_telegramsPerSecond < 1) + { + ERROR_LOG(m_logger) << "Invalid telegrams/second " << args[2]; + usage(); + } + if (!f.open(QIODevice::ReadOnly)) + { + ERROR_LOG(m_logger) << "Error opening file " + << f.fileName() + << " for reading - error: " + << f.errorString(); + } + m_data = f.readAll(); + + parseISSIs(args.mid(3)); + + INFO_LOG(m_logger) << "Sending " << m_data.size() + << " bytes, " << m_telegramsPerSecond + << " telegrams/second for " << m_count + << " time(s) to issi(s) " << getIssisAsString(); + + setupTimer(); +} + +void TetraIF::usage() +{ + NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()); + ERROR_LOG(logger) << "Usage : " << QCoreApplication::applicationFilePath() << " "; + ERROR_LOG(logger) << " : listen|send_random|send_file"; + ERROR_LOG(logger) << " : []"; + ERROR_LOG(logger) << " : [ .. ]"; + ERROR_LOG(logger) << " : [ .. ]"; + exit(1); +} + +void TetraIF::onConnected() +{ + INFO_LOG(m_logger) << "Connected to " << m_socket->peerName() << ":" << m_socket->peerPort(); + doInitialLogin(); +} + +void TetraIF::onDisconnected() +{ + INFO_LOG(m_logger) << "Disconnected - exiting application"; + QCoreApplication::quit(); +} + +void TetraIF::onReadyRead() +{ + do + { + DEBUG_LOG(m_logger) << "Got " << m_socket->bytesAvailable() << " bytes from socket"; + + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; + if (m_socket->bytesAvailable() < int(sizeof(header))) + return; + + m_socket->peek(reinterpret_cast(&header), sizeof(header)); + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) + { + ERROR_LOG(m_logger) << "Incorrect magic number (0x" + << QString::number(header.m_MagicNumber, 16) + << " - aborting"; + exit(2); + } + if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) + { + ERROR_LOG(m_logger) << "Radio-Telegram length to big: " + << header.m_Length + << ", but I proceed with this telegram."; + } + + const quint16 dataSize = header.m_Length + sizeof(header); + if (m_socket->bytesAvailable() < dataSize) + { + INFO_LOG(m_logger) << "not enough bytes available - waiting for more data"; + return; + } + QByteArray buf(dataSize, Qt::Uninitialized); + m_socket->read(buf.data(), dataSize); + handleReceivedTelegram(buf); + + } + while (m_socket->bytesAvailable()); +} + +void TetraIF::onError(QAbstractSocket::SocketError err) +{ + ERROR_LOG(m_logger) << "Socket error " + << err + << " (" + << m_socket->errorString() + << ") - aborting"; + exit(2); +} + +void TetraIF::doInitialLogin() +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram tele(m_issi); + m_socket->write(tele.data()); + m_socket->flush(); +} + +void TetraIF::handleReceivedTelegram(const QByteArray &data) +{ + const auto type = N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type(data.at(4)); + + switch (type) + { + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: + handleRegisterRsp(data.at(5)); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: + handleDataIndReq(data); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: + + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: + + break; + + default: + return; + } + INFO_LOG(m_logger) << "PDU Type: " << type; + dumpData(data); +} + +void TetraIF::handleRegisterRsp(const uint8_t a_registrationStatus) +{ + QByteArray logText; + switch (a_registrationStatus) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered: + INFO_LOG(m_logger) << "Valid register response from Tetra "; + if (m_timer) + m_timer->start(); + return; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DuplicateISSI: + logText = "TETRA: Register-Response: Status=Duplicate ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidISSI: + logText = "TETRA: Register-Response: Status=Invalid ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidIpAddress: + logText = "TETRA: Register-Response: Status=Invalid IP address => Configure TETRA for accepting our IP-address ("; + { + const QList ipList = QNetworkInterface::allAddresses(); + for (const QHostAddress &addr : ipList) + logText += addr.toString().toUtf8() + ", "; + logText += ")..."; + } + break; + default: + logText = "Unknown registration status: " + QByteArray::number(a_registrationStatus); + break; + } + + ERROR_LOG(m_logger) << logText; + exit(2); +} + +void TetraIF::dumpData(const QByteArray &data) +{ + + if (m_outputDir.isEmpty()) + return; + const qint64 msecs = QDateTime::currentMSecsSinceEpoch(); + const QString timeStr = QStringLiteral("%1.%2").arg(msecs / 1000).arg(msecs % 1000); + { + QFile f(m_outputDir + timeStr + QLatin1String(".dat")); + if (!f.open(QIODevice::WriteOnly)) + { + ERROR_LOG(m_logger) << "Error opening file " + << f.fileName() + << " for writing - error: " + << f.errorString(); + } + f.write(data); + f.close(); + } + if (data.size() > 27) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram tele(data); + INFO_LOG(m_logger) << "Got telegram from " + << tele.getSrcISSI() + << " with size " + << data.size() + << " and payload size " + << tele.getPayloadSize(); + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, tele.data()); + QFile f(m_outputDir + QStringLiteral("payload-%1-%2.dat").arg(QString::number(tele.getSrcISSI()), timeStr)); + if (!f.open(QIODevice::WriteOnly)) + { + ERROR_LOG(m_logger) << "Error opening file " + << f.fileName() + << " for writing - error: " + << f.errorString(); + } + + f.write(&data.data()[27], data.size() - 27); + f.close(); + } +} + +void TetraIF::onSendData() +{ + ++m_secondFragment; + + if (m_secondFragment == 100) + { + m_secondFragment = 0; + m_telegramsInCurSecond = 0; + } + + int telegramsToSendNow = (m_telegramsPerSecond - m_telegramsInCurSecond) / (100 - m_secondFragment); + NOTICE_LOG(m_logger) << "telegramsToSendNow: " << telegramsToSendNow << ", " << m_telegramsPerSecond << ", " << m_telegramsInCurSecond << ", " << m_secondFragment; + + m_telegramsInCurSecond += telegramsToSendNow; + static uint8_t s_counter = 1; + static char s_randomChar = 0; + for (int i = 0; i < telegramsToSendNow; ++i) + { + for (unsigned short dest_issi : qAsConst(m_issiList)) + { + + m_data[0] = s_randomChar++; + N_CoPrtCnv::CoPrtCnvRadioTelegram tele(GEF_BESTAETIGUNG, m_data.size(), dest_issi); + tele.setPayloadDataComplete(m_data); + tele.setSrcISSI(m_issi); + tele.setDestISSI(dest_issi); + tele.setZaehler(s_counter++); + DEBUG_LOG(m_logger) << "Sending " << tele.getSize() << " bytes to Tetra (ISSI: " << dest_issi << ")"; + m_socket->write(tele.data()); + } + if (m_count > 0) + { + if (--m_count <= 0) + { + INFO_LOG(m_logger) << "Finsihed"; + m_socket->disconnectFromHost(); + } + } + m_socket->flush(); + } +} + +void TetraIF::parseISSIs(const QStringList &issiList) +{ + m_issiList.clear(); + + if (issiList.count() == 0) + { + m_issiList += 0; + return; + } + for (const QString &issiStr : issiList) + { + bool bOk; + unsigned short issi = issiStr.toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(m_logger) << "Not a valid issi number: " << issiStr; + usage(); + } + m_issiList += issi; + } +} + +QString TetraIF::getIssisAsString() const +{ + QString ret; + for (unsigned short issi : qAsConst(m_issiList)) + ret += QString::number(issi) + QLatin1String(", "); + return ret.left(ret.size() - 2); +} + +void TetraIF::handleDataIndReq(const QByteArray &data) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(data); + uint32_t m_HostISSI = 2; + if (m_HostISSI == radioTelegram->getDestISSI()) + { + + switch (radioTelegram->getFragmentStatus()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_NotFragmented: + handleLoginTelegram(radioTelegram); + break; + default: + ERROR_LOG(m_logger) << "Unknown payload-status!: " << radioTelegram->getFragmentStatus(); + break; + } + + delete radioTelegram; + } +} + +void TetraIF::handleLoginTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *a_loginTelegram) +{ + uint16_t identity = a_loginTelegram->getIdentity(); + uint32_t issi = a_loginTelegram->getSrcISSI(); + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginRequest == (a_loginTelegram->getPayloadDataUInt8(2) & N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginStatusMask)) + { + bool sent = sendLoginResponse(issi); + if (sent) + INFO_LOG(m_logger) << "Login: New TPU with Id=" << identity << " and ISSI=" << issi << " logged in"; + else + + INFO_LOG(m_logger) << "Login: New TPU with Id=" << identity << " and ISSI=" << issi << " is NOT logged in"; + } + +} + +bool TetraIF::sendLoginResponse(const uint32_t a_ISSI) +{ + ++m_SendCounter; + N_CoPrtCnv::CoPrtCnvRadioTelegram *a_telegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_BESTAETIGUNG, 20, a_ISSI); + a_telegram->setZaehler(m_SendCounter); + + a_telegram->setDestISSI(a_ISSI); + a_telegram->setSrcISSI(2); + gef_telegramm_id_et telId = a_telegram->isNormalTelegram() ? a_telegram->getTelID() : GEF_BESTAETIGUNG; + + + INFO_LOG(m_logger) << "Send telegram to radio: telId=" << telId << " wcounter=" << a_telegram->zaehler() << " size= 28"; + + + + a_telegram->setProtocolIdentifier(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_TDSMessageWithoutSDS_TL); + a_telegram->setPayloadData(0x01); + a_telegram->setPayloadData(0x04); + + a_telegram->getData()[22] = 0x0d; + + char *data = a_telegram->getData(); + + + data[02] = 0x18; + + data[22] = 0x0d; + data[23] = 0x00; + + data[24] = 0x02; + data[25] = 0x00; + + data[13] = 0x00; + data[26] = 0x01; + data[27] = 0x40; + + m_socket->write(data, 28); + delete a_telegram; + return m_socket->flush(); + +} + +void TetraIF::setupTimer() +{ + delete m_timer; + m_timer = new QTimer(this); + connect(m_timer, &QTimer::timeout, this, &TetraIF::onSendData); + m_timer->setInterval(10); +} diff --git a/TetraIF/PrtCnv/LastTest/tetra_if.h b/TetraIF/PrtCnv/LastTest/tetra_if.h new file mode 100644 index 000000000..c239a2315 --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/tetra_if.h @@ -0,0 +1,61 @@ + + +#pragma once +#include +#include +#include + +#include +#include + +class QTcpSocket; +class QTimer; +class TetraIF : public QObject +{ + Q_OBJECT +public: + TetraIF(const QHostAddress &addr, unsigned short port, unsigned short issi); + + void start(); + void listenMode(const QStringList &args); + void randomMode(const QStringList &args); + void fileMode(const QStringList &args); + + static void usage(); +protected Q_SLOTS: + void onConnected(); + void onDisconnected(); + void onReadyRead(); + void onError(QAbstractSocket::SocketError); + void onSendData(); +protected: + void doInitialLogin(); + void handleReceivedTelegram(const QByteArray &data); + void handleRegisterRsp(const uint8_t a_registrationStatus); + void dumpData(const QByteArray &data); + + void parseISSIs(const QStringList &issiList); + void handleDataIndReq(const QByteArray &data); + void handleLoginTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *a_loginTelegram); + bool sendLoginResponse(const uint32_t a_ISSI); + QString getIssisAsString() const; + + void setupTimer(); + +protected: + QHostAddress m_addr; + unsigned short m_port; + unsigned short m_issi; + QTcpSocket *m_socket; + int m_count; + int m_telegramsPerSecond; + int m_telegramsInCurSecond; + int m_secondFragment; + QByteArray m_data; + QList m_issiList; + QTimer *m_timer; + uint8_t m_SendCounter; + + QString m_outputDir; + NGL::INGLLogger &m_logger; +}; diff --git a/TetraIF/PrtCnv/LastTestAuswertung/CMakeLists.txt b/TetraIF/PrtCnv/LastTestAuswertung/CMakeLists.txt new file mode 100644 index 000000000..4d4301fd1 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(lta_SRCS + main.cpp + mainwindow.cpp +) + +SET(lta_HDRS + mainwindow.h +) + +SET(lta_UICS + mainwindow.ui +) + +NGL_WRAP_UI(lta_SRCS ${lta_UICS}) +NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION LastTestAuswertung ${lta_SRCS} ${lta_HDRS} ${lta_UICS}) +NGL_TARGET_LINK_LIBRARIES(LastTestAuswertung + Qt5::Core + Qt5::Widgets +) diff --git a/TetraIF/PrtCnv/LastTestAuswertung/LastTestAuswertung.pro b/TetraIF/PrtCnv/LastTestAuswertung/LastTestAuswertung.pro new file mode 100644 index 000000000..0ccbcd0c8 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/LastTestAuswertung.pro @@ -0,0 +1,16 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2011-05-13T08:20:33 +# +#------------------------------------------------- + +TARGET = LastTestAuswertung +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp + +HEADERS += mainwindow.h + +FORMS += mainwindow.ui diff --git a/TetraIF/PrtCnv/LastTestAuswertung/main.cpp b/TetraIF/PrtCnv/LastTestAuswertung/main.cpp new file mode 100644 index 000000000..84bb2601d --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/main.cpp @@ -0,0 +1,10 @@ +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.cpp b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.cpp new file mode 100644 index 000000000..0cad665e9 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.cpp @@ -0,0 +1,428 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include +#include +#include +#include +#include + + + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + init(); +} + +MainWindow::~MainWindow() +{ + m_files.clear(); + + + + +} + +void MainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) + { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void MainWindow::init() +{ + + connect(ui->pushButtonOrdnerFinden, &QPushButton::clicked, this, &MainWindow::slot_findFolder); + connect(ui->pushButtonAnalysieren, &QPushButton::clicked, this, &MainWindow::slot_analysieren); + + ui->progressBar->setValue(0); + ui->labelResult->setText(QString()); + QIntValidator intVal; + intVal.setBottom(0); + intVal.setTop(100000); + ui->lineEditISSI->setValidator(&intVal); +} + +void MainWindow::slot_findFolder() +{ + + + + QString name = QFileDialog::getExistingDirectory(this, tr("Choose folder"), QDir::homePath(), QFileDialog::DontResolveSymlinks); + ui->lineEditOrdner->setText(name); + ui->labelResult->setText(QString()); + +} + +void MainWindow::slot_analysieren() +{ + ui->labelResult->setText(QString()); + QString ISSI = ui->lineEditISSI->text(); + if (ISSI.isEmpty()) + ISSI = QLatin1String("1"); + m_logfileList.clear(); + + + QDir folder(ui->lineEditOrdner->text()); + m_files = folder.entryList(); + folder.~QDir(); + ui->progressBar->setValue(1); + const QString paytext = ISSI + QLatin1String("-payload"); + const QString issitext = ISSI + QLatin1String("-1"); + for (int i = 0; i < m_files.count(); i++) + { + + QString name = m_files[i]; + if (name.contains(paytext)) + { + m_files.removeAt(i); + i--; + } + else + { + if (!name.contains(QLatin1String(".dat"))) + { + m_files.removeAt(i); + i--; + } + else + { + if (!name.contains(issitext)) + { + m_files.removeAt(i); + i--; + } + } + } + } + + ui->progressBar->setValue(10); + if (m_files.count() == 0) + ui->labelResult->setText(tr("no logfiles found")); + else + { + openLogfile(ui->lineEditOrdner->text(), m_files.count()); + ui->progressBar->setValue(12); + ui->progressBar->repaint(); + readFiles(); + ui->progressBar->setValue(90); + ui->progressBar->repaint(); + QString ausgabetext = QLatin1String("\tANALYSIS COMPLETED - ") + QString::number(auswerten()) + QLatin1String(" missing messages"); + ui->labelResult->setText(ausgabetext); + } + ui->progressBar->setValue(100); + ui->progressBar->repaint(); +} + +void MainWindow::readFiles() +{ + for (int j = 0; j < m_files.count(); j++) + { + QString filename = ui->lineEditOrdner->text(); + filename += QLatin1Char('/'); + filename += m_files[j]; + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) + { + + QByteArray ar = file.read(150); + file.close(); + if (ar.count() > 36) + { + QString issi = getISSI(ar); + QByteArray bytes = ar; + + + bytes.remove(0, 34); + bytes.remove(2, 150); + uint nr = bytes[0] & 255; + nr *= 256; + nr += bytes[1] & 255; + + + bytes = ar; + bytes.remove(0, 30); + bytes.remove(4, 150); + + const QByteArray test = bytes.toHex(); + qint64 zeit = test.toLongLong(nullptr, 16); + + const QDateTime timeStart(QDateTime::fromMSecsSinceEpoch(zeit * 1000)); + + writeToLogfile(issi, timeStart, getTimestamp(m_files[j]), m_files[j], nr); + writeLogZeiten(timeStart, getTimestamp(m_files[j]), issi); + + } + } + file.close(); + double val = 70; + val /= m_files.count(); + val *= (j + 1); + val += 20; + ui->progressBar->setValue(int(val)); + + } + +} + +void MainWindow::openLogfile(const QString &folder, int count) +{ + m_logfile = folder; + m_logZeiten = folder; + m_logfile += QLatin1String("/logfile_analysis.txt"); + QFile file(m_logfile); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + const QString msg = QStringLiteral("There are %1 logfiles evaluated.\nISSI SENDING TIME RECIEVING TIME FILENAME NO \n").arg(count); + file.write(msg.toUtf8()); + file.close(); + } + m_logZeiten += QLatin1String("/transmission_times.csv"); + file.setFileName(m_logZeiten); + if (file.open(QIODevice::WriteOnly)) + { + file.write("ISSI;Sending Time ; Receiving Time\n"); + file.close(); + } + +} + +void MainWindow::writeToLogfile(const QString &issi, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr, + const QString &bytes) +{ + QString text = issi; + text += QLatin1String(": "); + text += timestamp.toString(QLatin1String("dd.MM.yyyy hh:mm:ss")); + text += QLatin1String(" - "); + text += filename; + text += QLatin1String(" -> "); + text += bytes; + text += QLatin1String(" --> "); + text += QString::number(lfdNr, 10); + text += QLatin1Char('\n'); + QFile file(m_logfile); + if (file.open(QIODevice::Append | QIODevice::Text)) + { + file.write(text.toLatin1()); + file.close(); + } + LogfileInfo info; + info.timestamp = timestamp; + info.issi = issi; + info.lfdNr = lfdNr; + m_logfileList.append(info); +} + +void MainWindow::writeToLogfile(const QString &issi, + const QDateTime &sendeZeit, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr) +{ + QString text = issi; + text += QLatin1String(": "); + text += sendeZeit.toString(QLatin1String("hh:mm:ss")); + text += QLatin1String(" --> "); + text += timestamp.toString(QLatin1String("dd.MM.yyyy hh:mm:ss")); + text += QLatin1String(" - "); + text += filename; + text += QLatin1String(" --> "); + text += QString::number(lfdNr, 10); + text += QLatin1Char('\n'); + QFile file(m_logfile); + if (file.open(QIODevice::Append | QIODevice::Text)) + { + file.write(text.toLatin1()); + file.close(); + } + LogfileInfo info; + info.timestamp = timestamp; + info.issi = issi; + info.lfdNr = lfdNr; + m_logfileList.append(info); +} + +QDateTime MainWindow::getTimestamp(const QString &filename) const +{ + const auto list1 = filename.splitRef(QLatin1Char('-')); + if (list1.size() < 2) + return {}; + + const QStringRef &fn = list1.at(1); + const auto list2 = fn.split(QLatin1Char('.')); + auto str = list2.at(0).toString(); + str.remove(10, 10); + + return QDateTime::fromMSecsSinceEpoch(str.toLongLong() * 1000); +} + +QString MainWindow::getISSI(QByteArray ar) +{ + + ar.remove(0, 5); + ar.remove(4, 200); + QByteArray issi = ar.toHex(); + + if (ar.count() == 4) + { + if (ar[2] == '\0' && ar[3] == '\0') + { + ar.remove(2, 2); + issi = ar.toHex(); + int hex[4]; + for (int i = 3; i >= 0; i--) + { + char c = issi.at(i); + if (c >= '0' && c <= '9') + hex[i] = c - '0'; + else if (c >= 'a' && c <= 'f') + hex[i] = c - 'a' + 10; + + } + int sum = 0; + sum += hex[1]; + sum += hex[0] * 16; + sum += hex[3] * 256; + sum += hex[2] * 4096; + issi = QByteArray::number(sum); + } + } + + + return QString::fromLatin1(issi); +} + +int MainWindow::auswerten() +{ + + + QFile f(m_logfile); + if (!f.open(QIODevice::Append | QIODevice::Text)) + return -1; + f.write("***************************RESULT************************************\n"); + QSet issis; + issis.reserve(100); + for (int i = 0; i < m_logfileList.count(); i++) + { + + issis += m_logfileList.at(i).issi; + } + ui->progressBar->setValue(94); + ui->progressBar->repaint(); + int fehlcount = 0; + QVector numList; + int i = 0; + for (const QString &issi : qAsConst(issis)) + { + + numList.clear(); + for (int j = 0; j < m_logfileList.count(); j++) + { + if (issi == m_logfileList.at(j).issi) + numList.append(m_logfileList.at(j).lfdNr); + } + QByteArray text = issi.toLatin1(); + text += ":\t"; + text += QByteArray::number(numList.count()); + text += " messages transmitted\n"; + text += "\t"; + f.write(text); + + fehlcount += fehlendeNumsEintragen(numList, f); + + + double val = 5; + val /= issis.count(); + val *= (i + 1); + val += 94; + ui->progressBar->setValue(qRound(val)); + ui->progressBar->repaint(); + + ++i; + } + return fehlcount; +} + +int MainWindow::fehlendeNumsEintragen(const QVector &numList, QFile &f) +{ + + QVector fehlendeNums = getFehlendeNums(numList); + QByteArray text = QByteArray::number(fehlendeNums.count()); + text += " lost messages\n"; + text += "\t\t following messages are missing ("; + for (int j = 0; j < fehlendeNums.count(); j++) + { + text += QByteArray::number(fehlendeNums.at(j)); + text += ", "; + } + + text += ")\n"; + + f.write(text); + + return fehlendeNums.count(); +} + +QVector MainWindow::getFehlendeNums(const QVector &numsDurchgang) +{ + + uint count = numsDurchgang.count(); + uint maxnum = 0; + uint minnum = 999999; + for (uint k = 0; k < count; k++) + { + + if (numsDurchgang.at(k) > maxnum) + maxnum = numsDurchgang.at(k); + if (numsDurchgang.at(k) < minnum) + minnum = numsDurchgang.at(k); + } + + QVector fehlendeNum; + for (uint z = minnum; z <= maxnum; z++) + { + + bool vorhanden = false; + for (uint j = 0; j < count; j++) + { + if (numsDurchgang.at(j) == z) + { + vorhanden = true; + break; + } + } + if (!vorhanden) + fehlendeNum.append(z); + } + return fehlendeNum; +} + +void MainWindow::writeLogZeiten(const QDateTime &beginn, const QDateTime &end, const QString &issi) +{ + QString msg = issi; + msg += QLatin1Char(';'); + msg += beginn.toString(QLatin1String("hh:mm:ss")); + msg += QLatin1Char(';'); + msg += end.toString(QLatin1String("hh:mm:ss")); + msg += QLatin1Char('\n'); + QFile file(m_logZeiten); + file.open(QIODevice::Append | QIODevice::Text); + file.write(msg.toUtf8()); + file.close(); + + +} diff --git a/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.h b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.h new file mode 100644 index 000000000..e8b60ec56 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.h @@ -0,0 +1,69 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +namespace Ui +{ +class MainWindow; +} + +struct LogfileInfo +{ + QString issi; + QDateTime timestamp; + uint lfdNr; +}; +struct ZeitNum +{ + uint zeit; + int num; +}; + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::MainWindow *ui; + void init(); + void readFiles(); + QStringList m_files; + QDateTime getTimestamp(const QString &filename) const; + QString m_logfile; + QString m_logZeiten; + void openLogfile(const QString &folder, int count); + void writeToLogfile(const QString &issi, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr, + const QString &bytes); + void writeToLogfile(const QString &issi, + const QDateTime &sendeZeit, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr); + QString getISSI(QByteArray ar); + int auswerten(); + QVector getFehlendeNums(const QVector &numsDurchgang); + int fehlendeNumsEintragen(const QVector &numList, QFile &file); + void writeLogZeiten(const QDateTime &beginn, const QDateTime &end, const QString &issi); + + QVector m_logfileList; + +private slots: + void slot_findFolder(); + void slot_analysieren(); +}; + + + +#endif diff --git a/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.ui b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.ui new file mode 100644 index 000000000..b34067217 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.ui @@ -0,0 +1,123 @@ + + + MainWindow + + + + 0 + 0 + 521 + 234 + + + + Logfiles analysieren + + + + + + 10 + 80 + 501 + 101 + + + + + + + analyse logfiles + + + + + + + 24 + + + + + + + + 12 + + + + TextLabel + + + + + + + + + 9 + 0 + 501 + 65 + + + + + + + + + + + + choose folder + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ISSI by the central<br />(if no ISSI is entered, ISSI 1 will be used)</p></body></html> + + + + + + + + + + + + 0 + 0 + 521 + 21 + + + + + + TopToolBarArea + + + false + + + + + + + + diff --git a/TetraIF/PrtCnv/PrtCnv.dat.tts b/TetraIF/PrtCnv/PrtCnv.dat.tts new file mode 100644 index 000000000..c8d1f0fc9 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnv.dat.tts @@ -0,0 +1,90 @@ +[Common] +LogCentralTelegrams=1 +LogRadioTelegrams=1 +LogTelegramPath=logdata +LogTelegramPrefix=PrtCnv_ +; virtual TeilnehmerId of protocol-converter +VirtualIdPrtCnv=90 + +[Db] +DatabaseFileName=db/telegrams.db + +[Central] +UseSocketsInsteadFiles=1 +HostName=ECCORSV01 +Port=9600 +; Milliseconds +AckTimeout=900 +ConnectTimeout=2000 +DisconnectTimeout=10000 +AliveTimeout=3000 +; nbr of unsuccessful send-attempts, before telegram will be deleted without sending it +NbrOfAttempts=5 + +[Radio] +HostName=127.0.0.1 +Port=52010 +HostISSI=9999 +; Seconds +CyclicEnvironmentTime=30 +; Milliseconds +BroadcastISSI=5000 +ConnectTimeout=2000 +DisconnectTimeout=10000 +AliveTimeout=3000 +; 1 - UseSDS_TL +UseSDS_TL=0 +DumpReceivedTelegrams=1 +DumpSentTelegrams=1 +; GSSIs which we would like to subscribe to - make sure to not subscribe to our own BroadcastISSI ! +ListenGroups=5001 + +[Login] +LoginFilePathWithPrefix=login/pk_ +DoLicenseDespiteSelftestOrConfigFailure=0 +DoCheckPlayerId=1 +LowestPlayerId=500 +HighestPlayerId=9999 +PlayerIdFilePath=playerIds.dat + +[Broadcast] +; In seconds, delay between sending 1st and 2nd broadcast +BroadcastDelay2=10 +; In seconds, delay between sending 2nd and 3rd broadcast +BroadcastDelay3=20 +; the time to wait for NachforderungBroadcast from TNEs, before begin sending the broadcasts +ClaimWindow=30 +; factor for extend the claimwindow when we have full load in downlink +FullLoadFactor=3 +; if less TNEs ask for broadcasts, they will be send directed +BroadcastLimit=10 +; the time to wait before sending next broadcast in milliseconds +SendGap=500 + +[TrafficControl] +; from PrtCnv to Tetra (Telegram-Counting) +; Number of telegrams (0..255) reported by air-interface-report telegram when we have high load +SendQueueHighLoad=150 +; Number of telegrams that will be sent per second, when we have high-load +SendTelegramsHighLoad=50 +; Number of telegrams (0..255) reported by air-interface-report telegram when we have full load +SendQueueFullLoad=200 +; Number of telegrams that will be sent per second, when we have full-load +SendTelegramsFullLoad=10 +; from Tetra to PrtCnv (Byte-Counting) +; high load in percent (0 .. 100) +ReceiveQueueHighLoad=50 +; full load in percent (ReceiveQueueHighLoad .. 100) +ReceiveQueueFullLoad=75 +; hysteresis in percent (0 .. 10) +ReceiveQueueHysteresis=5 +; Averaging time in seconds +ReceiveAveragingTime=5 +; Throughput in KB/s per Transceiver +ReceiveThroughput=3.6 +; Transceiver count +TransceiverCount=6 + +[Injection] +Enable=true +Port=46666 diff --git a/TetraIF/PrtCnv/PrtCnvApplication.cpp b/TetraIF/PrtCnv/PrtCnvApplication.cpp new file mode 100644 index 000000000..ada274ae4 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvApplication.cpp @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + +#include "PrtCnvApplication.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvThread.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace PrtCnv +{ + +static std::string threadIdToString(PrtCnvApplication::E_ThreadId id) +{ + switch (id) + { + case PrtCnvApplication::e_Central: + return "Central"; + case PrtCnvApplication::e_Radio: + return "Radio"; + case PrtCnvApplication::e_Db: + return "Db"; + case PrtCnvApplication::e_Log: + return "Log"; + case PrtCnvApplication::e_Injection: + return "Injection"; + case PrtCnvApplication::e_RadioTraffic: + return "RadioTraffic"; + case PrtCnvApplication::e_ThreadIdMax: + break; + } + return std::to_string(id); +} + +PrtCnvApplication::PrtCnvApplication() + : m_Config(nullptr) + , m_exerciseId(0) + , m_accessMutex(QMutex::Recursive) + , m_logger(getLogger("PrtCnvApplication")) +{} + + +PrtCnvApplication::~PrtCnvApplication() +{ + delete m_Config; + for (const auto &ti : m_threadInfo) + delete ti.thread; +} + + + + + +void PrtCnvApplication::waitForCreate(const E_ThreadId a_threadId) +{ + INFO_LOG(m_logger) << "Wait for others until we can create " << threadIdToString(a_threadId); + setConstructed(a_threadId); + switch (a_threadId) + { + case e_Central: + while (!(isConstructed(e_Db) && + isConstructed(e_Radio) && + isConstructed(e_Log) && + isConstructed(e_Injection))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Radio: + while (!(isConstructed(e_Db) && + isConstructed(e_Central) && + isConstructed(e_Log) && + isConstructed(e_Injection))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Db: + while (!(isConstructed(e_Radio) && + isConstructed(e_Central))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + default: + break; + } + INFO_LOG(m_logger) << "Now we can create " << threadIdToString(a_threadId); +} + + + + + +void PrtCnvApplication::waitForInit(E_ThreadId a_threadId) +{ + INFO_LOG(m_logger) << "Wait for others until we can initialize " << threadIdToString(a_threadId); + setCreated(a_threadId); + switch (a_threadId) + { + case e_Central: + while (!(isCreated(e_Db) && + isCreated(e_Radio))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Radio: + while (!(isCreated(e_Db) && + isCreated(e_Central))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Db: + while (!(isCreated(e_Radio) && + isCreated(e_Central))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + default: + break; + } + INFO_LOG(m_logger) << "Now we can initialize " << threadIdToString(a_threadId); +} + + + + +void PrtCnvApplication::waitForStart(E_ThreadId a_threadId) +{ + INFO_LOG(m_logger) << "Wait for others until we can start " << threadIdToString(a_threadId); + setInitialized(a_threadId); + switch (a_threadId) + { + case e_Central: + while (!(isStarted(e_Db) && + isInitialized(e_Radio) && + isStarted(e_Log) && + isStarted(e_Injection))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Radio: + while (!(isStarted(e_Db) && + isInitialized(e_Central) && + isStarted(e_Log) && + isStarted(e_Injection) && + isInitialized(e_RadioTraffic))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Db: + while (!(isInitialized(e_Radio) && + isInitialized(e_Central) && + isStarted(e_Log))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_RadioTraffic: + while (!(isInitialized(e_Radio) && + isStarted(e_Log))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + default: + break; + } + INFO_LOG(m_logger) << "Now we can start " << threadIdToString(a_threadId); +} + + + + + +void PrtCnvApplication::waitForExec(E_ThreadId a_threadId) +{ + setStarted(a_threadId); +} + + + + +void PrtCnvApplication::startApp() +{ + createApplication(); + init(); + start(); +} + +void PrtCnvApplication::shutdownApp() +{ + stop(); + deinit(); + destroy(); + for (const auto &ti : m_threadInfo) + ti.thread->quit(); + for (const auto &ti : m_threadInfo) + ti.thread->wait(); + for (auto &ti : m_threadInfo) + { + delete ti.thread; + ti.thread = nullptr; + } +} + +void PrtCnvApplication::setCleanDb(bool bCleanDb) +{ + PrtCnvThread::m_DoCleanDb = bCleanDb; +} + +void PrtCnvApplication::setExerciseId(int exerciseId) +{ + m_exerciseId = exerciseId; +} + +void PrtCnvApplication::setConfigFile(const QString &configFile) +{ + m_ConfigFileName = configFile; +} + + + + +int32_t PrtCnvApplication::createApplication() +{ + setName(QStringLiteral("Common")); + if (m_ConfigFileName.isEmpty()) + { + m_ConfigFileName = QCoreApplication::applicationDirPath(); + if (m_exerciseId > 0) + m_ConfigFileName += QStringLiteral("/PrtCnv_ex_") + QString::number(m_exerciseId) + QStringLiteral(".dat"); + else + m_ConfigFileName += QStringLiteral("/PrtCnv.dat"); + } + m_Config = new NGL::Settings(m_ConfigFileName); + std::cout << "Use config-file: " << qPrintable(m_ConfigFileName) << std::endl; + + for (int i = 0; i < e_ThreadIdMax; i++) + m_threadInfo[i].thread = new PrtCnvThreadStarter((E_ThreadId)i, m_ConfigFileName, this); + + N_AppComponent::AppComponent::create(m_Config); + + return 0; +} + + + + +int32_t PrtCnvApplication::start() +{ + + for (const auto &ti : m_threadInfo) + ti.thread->start(); + + N_AppComponent::AppComponent::start(); + + return 0; +} + + + + + +PrtCnv::PrtCnvThreadStarter *PrtCnvApplication::getThreadStarter(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return nullptr; + + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].thread; +} + +void PrtCnvApplication::setDatabaseConnectionParams(const QString &driver, + const QString &hostName, + const QString &database, + const QString &schemaName, + const QString &userName, + const QString &password) +{ + m_dbDriver = driver; + m_dbHostName = hostName; + m_dbDatabaseName = database; + m_dbSchemaName = schemaName; + m_dbUserName = userName; + m_dbPassword = password; +} + +void PrtCnvApplication::logWlsTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, + bool bIsSend) +{ + const auto threadHandler = m_threadInfo[e_Log].thread; + PrtCnvTelegramLogThread *t = static_cast(threadHandler ? threadHandler->getThread() : nullptr); + if (t) + t->writeWlsTelegramLog(tele, bIsSend, 0); +} + + +bool PrtCnvApplication::isConstructed(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isConstructed; +} + + +void PrtCnvApplication::setConstructed(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isConstructed = true; +} + + +bool PrtCnvApplication::isInitialized(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isInitialized; +} + + +void PrtCnvApplication::setInitialized(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isInitialized = true; +} + + +bool PrtCnvApplication::isCreated(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isCreated; +} + + +void PrtCnvApplication::setCreated(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isCreated = true; +} + + +bool PrtCnvApplication::isStarted(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isStarted; +} + + +void PrtCnvApplication::setStarted(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isStarted = true; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvApplication.hpp b/TetraIF/PrtCnv/PrtCnvApplication.hpp new file mode 100644 index 000000000..a496730ba --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvApplication.hpp @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + +#pragma once + +#include +#include "AppComponent.hpp" +#include "logger.h" +#include +#include +#include +#include + + + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + + + class PRTCNVLIB_EXPORT PrtCnvApplication : public QObject, public N_AppComponent::AppComponent + { + Q_OBJECT + public: + + + + enum E_ThreadId + { + e_Central, + e_Radio, + e_Db, + e_Log, + e_Injection, + e_RadioTraffic, + e_ThreadIdMax + }; + PrtCnvApplication(); + ~PrtCnvApplication(); + + + + void startApp(); + void shutdownApp(); + static void setCleanDb(bool bCleanDb); + void setExerciseId(int exerciseId); + int exerciseId() const { return m_exerciseId; } + void setConfigFile(const QString &configFile); + + + + int32_t start() override; + + + + + void waitForInit(E_ThreadId a_threadId); + + + + void waitForStart(E_ThreadId a_threadId); + + + + void waitForCreate(const E_ThreadId a_threadId); + + + + void waitForExec(E_ThreadId a_threadId); + + + + PrtCnvThreadStarter* getThreadStarter(const E_ThreadId a_threadId); + + + + void setDatabaseConnectionParams(const QString &driver, + const QString &hostName, + const QString &database, + const QString &schemaName, + const QString &userName, + const QString &password); + QString databaseDriver() const { return m_dbDriver; } + QString databaseHostName() const { return m_dbHostName; } + QString databaseName() const { return m_dbDatabaseName; } + QString databaseSchemaName() const { return m_dbSchemaName; } + QString databaseUserName() const { return m_dbUserName; } + QString databasePassword() const { return m_dbPassword; } + +public slots: + void logWlsTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool bIsSend); + +signals: + void textMessageFromPrtCnvToCentral(const QByteArray &ba); + void textMessageFromCentralToPrtCnv(const QByteArray &ba); + void outgoingBroadcastTelegramsRequest(int equipmentNumber, int broadcastIndex, int resetCounter); + void warehouseMessageFromPtrCnv(const QByteArray &jsonData); +protected: + + + int32_t createApplication(); + + + + bool isConstructed(const E_ThreadId a_threadId) const; + + + + void setConstructed(const E_ThreadId a_threadId); + + + + bool isInitialized(const E_ThreadId a_threadId) const; + + + + void setInitialized(const E_ThreadId a_threadId); + + + + bool isCreated(const E_ThreadId a_threadId) const; + + + + void setCreated(const E_ThreadId a_threadId); + + + + bool isStarted(const E_ThreadId a_threadId) const; + + + + void setStarted(const E_ThreadId a_threadId); + +protected: + + + NGL::Settings *m_Config; + + struct ThreadInfo + { + PrtCnvThreadStarter *thread = nullptr; + bool isConstructed = false; + bool isCreated = false; + bool isInitialized = false; + bool isStarted = false; + } m_threadInfo[e_ThreadIdMax]; + + + QString m_ConfigFileName; + + + int m_exerciseId; + + + + mutable QMutex m_accessMutex; + + QString m_dbDriver; + QString m_dbHostName; + QString m_dbDatabaseName; + QString m_dbSchemaName; + QString m_dbUserName; + QString m_dbPassword; + + NGL::INGLLogger &m_logger; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp new file mode 100644 index 000000000..b36512d8f --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp @@ -0,0 +1,1709 @@ + + + + + + + + + + + + + +#include "PrtCnvBroadcastMgr.hpp" +#include "PrtCnvDbThread.hpp" +#include +#include +#include +#include + +namespace PrtCnv +{ + +PrtCnvBroadcastMgr::PrtCnvBroadcastMgr() + : m_ClaimWindow(0) + , m_HighLoadFactor(0) + , m_BroadcastLimit(0) + , m_Config(nullptr) + , m_ActClaimWindow(0) + , m_State(e_ST_UNDEFINED) + , m_TickCounter(0) + , m_DbThread(nullptr) + , m_BroadcastIndex(0) + , m_IsFullLoad(false) + , m_FinishedBroadcastIndex(0) + , m_FirstBroadcastIndexOfBc1(0) + , m_logger(getLogger("PrtCnvBroadcastMgr")) + , m_loggerBcRequest(getLogger("PrtCnvBroadcastMgr.BcRequest")) +{ +} + + + + +int32_t PrtCnvBroadcastMgr::create(NGL::Settings *settings) +{ + m_Config = settings; + return 0; +} + + + + +int32_t PrtCnvBroadcastMgr::init() +{ + const QString broadcastGroup(QStringLiteral("Broadcast")); + N_CoPrtCnv::CoPrtCnvRadioTelegram::setBroadcastDelayTimes( + m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastDelay2"), 60), + m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastDelay3"), 60)); + N_CoPrtCnv::CoPrtCnvRadioTelegram::setMaxBroadcastSendCnt(m_Config->getInteger(broadcastGroup, QStringLiteral("MaxBroadcastSendCount"), 1)); + + const int sendGap = m_Config->getInteger(broadcastGroup, QStringLiteral("SendGap"), 500); + m_ClaimWindow = (m_Config->getInteger(broadcastGroup, QStringLiteral("ClaimWindow"), 30) * 1000) / sendGap; + m_HighLoadFactor = m_Config->getInteger(broadcastGroup, QStringLiteral("HighLoadFactor"), 3); + m_BroadcastLimit = m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastLimit"), 10); + + cleanAndInit(true); + + INFO_LOG(m_loggerBcRequest) << "m_ActClaimWindow=" << m_ActClaimWindow << " m_State=" << m_State; + + return 0; +} + + + + + + +void PrtCnvBroadcastMgr::setDbThread(PrtCnvDbThread *a_dbThread) +{ + m_DbThread = a_dbThread; +} + + + + + + +void PrtCnvBroadcastMgr::cleanAndInit(const bool a_deleteTelegrams) +{ + if (a_deleteTelegrams) + { + m_deactivatedAesArea2bcIndex.clear(); + m_deactivatedBcIndex2AesArea.clear(); + + m_deactivatedDusMine2bcIndex.clear(); + m_deactivatedBcIndex2DusMine.clear(); + + m_deactivatedFuncArea2bcIndex.clear(); + m_deactivatedBcIndex2FuncArea.clear(); + + m_BroadcastMap.clear(); + + m_LastTelegramMap.clear(); + m_FunktionsraumTelegramMap.clear(); + m_WirkfeldTelegramMapByKennung.clear(); + m_WirkfeldTelegramMapByTime.clear(); + + m_BroadcastIndex = 0; + } + + m_claimerArray.clear(); + + m_ActClaimWindow = m_ClaimWindow; + m_IsFullLoad = false; + m_TickCounter = 0; + m_State = e_ST_COLLECT; + + m_FinishedBroadcastIndex = 0; + m_FirstBroadcastIndexOfBc1 = 0; +} + + + + +bool PrtCnvBroadcastMgr::handleRadioTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + switch (a_radioTelegram.getTelID()) + { + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + handleNachforderungBroadcastTelegram(a_radioTelegram.getIdentity(), + a_radioTelegram.getPayloadDataUInt32(8, 2) + 1, + a_radioTelegram.getPayloadDataUInt8(7)); + return false; + default: + + break; + } + return true; +} + + + + +void PrtCnvBroadcastMgr::handleNachforderungBroadcastTelegram(int identity, int broadcastIndex, int resetCounter) +{ + INFO_LOG(m_loggerBcRequest) << "Got NachforderungBroadcast from TNE with id=" << identity + << " resetCounter=" << resetCounter + << " broadcastIndex=" << broadcastIndex - 1 + << " m_TickCounter=" << m_TickCounter << " m_State=" << m_State; + if (resetCounter == m_DbThread->getResetCounter()) + { + m_DbThread->incClaimCount(identity); + + for (auto &ebi : m_claimerArray) + { + if (ebi.equipNo == identity) + { + ebi.bcIndex = broadcastIndex; + return; + } + } + m_claimerArray.emplace_back(identity, broadcastIndex); + return; + } + WARNING_LOG(m_logger) << "NachforderungBroadcast from TNE with id=" << identity + << ": resetCounter different we have: " << int(m_DbThread->getResetCounter()) + << "; TNE has: " << resetCounter << " => discarded"; +} + + + + + + +std::shared_ptr PrtCnvBroadcastMgr::getNextBroadcastTelegramToSend(const uint16_t a_beginSearchWithBroadcastIndex, + const time_t a_currentTime) +{ + + + + + DEBUG_LOG(m_logger) << "getNextBroadcastTelegramToSend, startIdx: " << a_beginSearchWithBroadcastIndex; + auto iter = m_BroadcastMap.upper_bound(0 == a_beginSearchWithBroadcastIndex ? m_FinishedBroadcastIndex : a_beginSearchWithBroadcastIndex); + while (iter != m_BroadcastMap.end()) + { + auto broadcastTelegram = iter->second; + gef_telegramm_id_et telId = broadcastTelegram->getTelID(); + + if (GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM == telId + || GEF_WF_SAMMELDEAKTIVIERUNG == telId + || GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN == telId) + { + + if (!broadcastTelegram->getBroadcastonlyTelegram()) + { + ++iter; + continue; + } + } + + bool isBcOnly = false; + if (broadcastTelegram->getBroadcastonlyTelegram()) + { + broadcastTelegram = broadcastTelegram->getBroadcastonlyTelegram(); + isBcOnly = true; + } + + bool wasLast = false; + if (broadcastTelegram->mustBeSentAsBroadcast(a_currentTime, wasLast)) + { + + if (wasLast) + { + if (isBcOnly || broadcastTelegram->isBroadcastOnly()) + { + removeFromAllMaps(broadcastTelegram); + } + else + { + + m_FinishedBroadcastIndex = broadcastTelegram->getBroadcastIndex(); + } + } + + broadcastTelegram->setIdentity(0); + return broadcastTelegram; + } + else + { + + + + + + + + + + + + + + + + + + + + + uint16_t bcCounter = broadcastTelegram->getBroadcastCounter(); + if (2 == bcCounter) + { + + + if (m_FirstBroadcastIndexOfBc1 > iter->first) + { + iter = m_BroadcastMap.lower_bound(m_FirstBroadcastIndexOfBc1); + continue; + } + } + else if (1 == bcCounter) + { + m_FirstBroadcastIndexOfBc1 = broadcastTelegram->getBroadcastIndex(); + return nullptr; + } + } + ++iter; + } + return nullptr; +} + + + + + +std::shared_ptr PrtCnvBroadcastMgr::getNextNachforderungTelegramToSend() +{ + removeExpiredTelegrams(); + switch (m_State) + { + case e_ST_COLLECT: + + if (m_TickCounter >= m_ActClaimWindow && !m_IsFullLoad) + { + + prepareForSendNachforderungen(); + } + else + { + + getAllFinishedBroadcastsFromDb(); + } + break; + + + case e_ST_SEND_NACHFORDERUNG: + return evaluateNextNachforderungToSend(); + default: + break; + } + return {}; +} + + + + + +void PrtCnvBroadcastMgr::removeExpiredTelegrams() +{ + const time_t now = time(nullptr); + auto iter = m_WirkfeldTelegramMapByTime.begin(); + while (iter != m_WirkfeldTelegramMapByTime.end()) + { + + + if (iter->first + 5 > now) + return; + + auto radioTelegram = iter->second; + INFO_LOG(m_logger) << "Remove expired telegram with telId=" << radioTelegram->getTelID() + << " and BC=" << radioTelegram->getBroadcastIndex() << " from BC-list"; + uint16_t wirkfeldKennung = radioTelegram->getPayloadDataUInt32(5, 2); + removeWirkfeldTelegrams(wirkfeldKennung); + iter = m_WirkfeldTelegramMapByTime.begin(); + } +} + + + + + +void PrtCnvBroadcastMgr::prepareForSendNachforderungen() +{ + + m_TickCounter = 0; + if (!m_claimerArray.empty()) + { + dump(); + + + + m_State = e_ST_SEND_NACHFORDERUNG; + + + std::swap(m_claimerArray, m_claimerArray); + std::sort(m_claimerArray.begin(), m_claimerArray.end(), + [] (const EquipNoBcIndex &a, const EquipNoBcIndex &b) + { + if (a.bcIndex != b.bcIndex) + return a.bcIndex < b.bcIndex; + return a.equipNo < b.equipNo; + }); + + + INFO_LOG(m_loggerBcRequest) << "BroadcastLimit: " << m_BroadcastLimit; + if (m_claimerArray.size() > m_BroadcastLimit) + { + m_claimerArray.clear(); + m_claimerArray.emplace_back(0, m_claimerArray.begin()->bcIndex); + } + + + for (const EquipNoBcIndex &enbi : m_claimerArray) + { + int curBcIndex = enbi.bcIndex; + int nextBcIndex = -1; + + while (true) + { + auto tel = getNachforderungsTelegram(curBcIndex, enbi.bcIndex, nextBcIndex); + curBcIndex = nextBcIndex; + if (tel) + { + auto copy(std::make_shared(*tel)); + copy->setIdentity(enbi.equipNo); + m_broadcastTelegamsToSend.push_back(copy); + } + else + break; + }; + + std::sort(m_broadcastTelegamsToSend.begin(), m_broadcastTelegamsToSend.end(), + [] (const std::shared_ptr &a, const std::shared_ptr &b) + { + const int bcIndexA = a->getTelID() == GEF_NOP ? a->getPayloadDataUInt32(3, 2) : a->getBroadcastIndex(); + const int bcIndexB = b->getTelID() == GEF_NOP ? b->getPayloadDataUInt32(3, 2) : b->getBroadcastIndex(); + if (bcIndexA != bcIndexB) + return bcIndexA > bcIndexB; + return a->getIdentity() < b->getIdentity(); + }); + + if (m_loggerBcRequest.isDebugEnabled()) + { + DEBUG_LOG(m_loggerBcRequest) << "Created broadcast list:"; + for (const auto &tele : m_broadcastTelegamsToSend) + DEBUG_LOG(m_loggerBcRequest) << "Identity: " << tele->getIdentity() + << ", bc: " << tele->getBroadcastIndex() + << ", type: " << tele->getTelID(); + } + } + m_claimerArray.clear(); + } +} + + + + + +std::shared_ptr PrtCnvBroadcastMgr::evaluateNextNachforderungToSend() +{ + if (m_broadcastTelegamsToSend.empty()) + { + m_State = e_ST_COLLECT; + return nullptr; + } + auto tel = m_broadcastTelegamsToSend.back(); + m_broadcastTelegamsToSend.pop_back(); + return tel; +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccumulationTelegram(int curBcIndex, + int startBcIndex, + gef_telegramm_id_et telId, + const QMap &bcIndex2Type, + int maxIdsPerTelegram, + int sizeOfSumField) const +{ + if (bcIndex2Type.isEmpty()) + return nullptr; + + auto itLastBcTele = m_BroadcastMap.end(); + --itLastBcTele; + const int endBcIndex = itLastBcTele->second->getBroadcastIndex(); + + DEBUG_LOG(m_loggerBcRequest) << "createAccumulationTelegram for telId " << telId + << ", begin: " << startBcIndex + << ", cur: " << curBcIndex << ", end: " << endBcIndex + << ", #elements in container: " << bcIndex2Type.size(); + DEBUG_LOG(m_loggerBcRequest) << "Given broadcast list for " << telegramId2String(telId); + for (auto it = bcIndex2Type.begin(); it != bcIndex2Type.end(); ++it) + DEBUG_LOG(m_loggerBcRequest) << " bcIndex: " << it.key() + << ", id: " << it.value(); + + + auto itStart = bcIndex2Type.lowerBound(startBcIndex); + if (itStart == bcIndex2Type.end()) + { + Q_ASSERT(false); + return nullptr; + } + auto itEnd = bcIndex2Type.lowerBound(endBcIndex); + if (itEnd == bcIndex2Type.end()) + --itEnd; + + const int completeTelegrams = std::distance(itStart, itEnd) + 1; + if (completeTelegrams <= 0) + { + Q_ASSERT(false); + return nullptr; + } + const auto itCur = bcIndex2Type.find(curBcIndex); + if (itCur == bcIndex2Type.end()) + { + Q_ASSERT(false); + return nullptr; + } + const int telegramsStillSendable = std::distance(itCur, itEnd) + 1; + if (telegramsStillSendable <= 0) + { + Q_ASSERT(false); + return nullptr; + } + + const int telegramsToSend = (completeTelegrams / maxIdsPerTelegram) + 1; + if (telegramsStillSendable > telegramsToSend) + { + INFO_LOG(m_loggerBcRequest) << telId << ": sending nop since accuTelegram is sent later (" << telegramsStillSendable + << ", need only " << telegramsToSend << ")"; + return nullptr; + } + + const int curIdStart = (telegramsToSend - telegramsStillSendable) * maxIdsPerTelegram; + const int idsToSendNow = (curIdStart + maxIdsPerTelegram <= completeTelegrams ? maxIdsPerTelegram : completeTelegrams % maxIdsPerTelegram); + INFO_LOG(m_loggerBcRequest) << telId << ": creating accuTelegram from index " << curIdStart << ", count: " << idsToSendNow; + + itStart += curIdStart; + + + auto tele(std::make_shared(telId, 3 + 2 + sizeOfSumField + sizeof(uint16_t) * idsToSendNow, 0)); + tele->setPayload2Byte(curBcIndex); + if (sizeOfSumField == 1) + tele->setPayload1Byte(idsToSendNow); + else if (sizeOfSumField == 2) + tele->setPayload2Byte(idsToSendNow); + else + { + Q_ASSERT(false); + return nullptr; + } + for (int i = 0; i < idsToSendNow; ++i) + { + tele->setPayload2Byte(itStart.value()); + ++itStart; + } + return tele; +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleDeactivatedAesAreas(int curBcIndex, + int startBcIndex) const +{ + return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG, + m_deactivatedBcIndex2AesArea, 100, 1); +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleDeactivatedFuncAreas(int curBcIndex, + int startBcIndex) const +{ + return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM, + m_deactivatedBcIndex2FuncArea, 100, 1); +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleDeactivatedDusMines(int curBcIndex, + int startBcIndex) const +{ + return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN, + m_deactivatedBcIndex2DusMine, 500, 2); +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleActivatedDusMines(int curBcIndex) +{ + if (m_activatedDusMines.isEmpty()) + return {}; + + const int idsToSendNow = m_activatedDusMines.size(); + if (idsToSendNow > 500) + { + WARNING_LOG(m_logger) << "More than 500 activated DUS mines in system - this is not allowed!"; + Q_ASSERT(false); + return {}; + } + auto tele(std::make_shared(GEF_REAKTIVIERUNG_DUS_MINE, 5 + 2 + sizeof(uint16_t) * idsToSendNow, 0)); + tele->setPayload2Byte(curBcIndex); + tele->setPayload2Byte(idsToSendNow); + for (int dusMineId : qAsConst(m_activatedDusMines)) + tele->setPayload2Byte(dusMineId); + + return tele; +} + + + + + + + + + + + + + + + +std::shared_ptrPrtCnvBroadcastMgr::getNachforderungsTelegram(int curBcIndex, + int startBcIndex, + int &nextBcIndex) +{ + DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - curBcIndex: " << curBcIndex + << ", startBcIndex: " << startBcIndex; + if (curBcIndex == 0) curBcIndex++; + DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - curBcIndex after Ssnity: " << curBcIndex + << ", startBcIndex: " << startBcIndex; + + nextBcIndex = curBcIndex; + bool doSendNop = false; + + while (true) + { + auto iter = m_BroadcastMap.lower_bound(nextBcIndex); + if (iter == m_BroadcastMap.end()) + break; + + auto radioTelegram = iter->second; + DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - cur tel id is " << radioTelegram->getTelID() + << ", bcIndex: " << radioTelegram->getBroadcastIndex() + << ", send nop: " << doSendNop; + + if (nextBcIndex < iter->first) + { + + + doSendNop = true; + nextBcIndex = iter->first; + } + else if (radioTelegram->isBroadcastOnly()) + { + doSendNop = true; + nextBcIndex = iter->first + 1; + } + else + { + std::shared_ptr retTele; + switch (radioTelegram->getTelID()) + { + case GEF_DEAKTIVIERUNG_WIRKFELD: + retTele = createAccuTeleDeactivatedAesAreas(radioTelegram->getBroadcastIndex(), startBcIndex); + break; + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + retTele = createAccuTeleDeactivatedFuncAreas(radioTelegram->getBroadcastIndex(), startBcIndex); + break; + case GEF_DEAKTIVIERUNG_EINZELMINE: + retTele = createAccuTeleDeactivatedDusMines(radioTelegram->getBroadcastIndex(), startBcIndex); + break; + case GEF_REAKTIVIERUNG_DUS_MINE: + retTele = createAccuTeleActivatedDusMines(radioTelegram->getBroadcastIndex()); + break; + default: + retTele = radioTelegram; + break; + } + + + if (retTele && doSendNop) + break; + ++nextBcIndex; + if (retTele) + return retTele; + doSendNop = true; + } + } + + + + if (!doSendNop && nextBcIndex <= m_BroadcastIndex) + { + nextBcIndex = m_BroadcastIndex + 1; + doSendNop = true; + } + + if (doSendNop) + { + + INFO_LOG(m_loggerBcRequest) << "Returning NOP: " << curBcIndex << " to " << nextBcIndex - 1; + return getNopTelegram(curBcIndex, nextBcIndex - 1); + } + + return nullptr; +} + + + + + + + +void PrtCnvBroadcastMgr::getAllFinishedBroadcastsFromDb(const bool a_doRestore) +{ + + + + + + + uint16_t broadcastIndex = 0; + while (true) + { + auto radioTelegram = m_DbThread->getNextBroadcastTelegram(); + if (!radioTelegram) + break; + broadcastIndex = radioTelegram->getBroadcastIndex(); + INFO_LOG(m_logger) << "Move Broadcast-telegram from DbThread>BroadcastMgr with telId=" + << radioTelegram->getTelID() << " BC=" << broadcastIndex; + dumpTelegram(m_logger, broadcastIndex, radioTelegram.get()); + + + + + + + + + + + + { + addToBroadcastMap(radioTelegram); + } + + if (a_doRestore && MAX_BROADCAST_INDEX == broadcastIndex) + handleOverrunOfBroadcastCounter(a_doRestore); + } + + if (m_logger.isDebugEnabled()) + { + static int iBroadcastDumpCounter = 0; + if ((iBroadcastDumpCounter++ % 30) == 0) + { + DEBUG_LOG(m_logger) << "Dumping broadcast map:"; + for (const auto &it : m_BroadcastMap) + dumpTelegram(m_logger, it.first, it.second.get()); + } + } + + + if (a_doRestore) + { + m_BroadcastIndex = broadcastIndex; + m_FinishedBroadcastIndex = m_BroadcastIndex; + } +} + + + + + + +void PrtCnvBroadcastMgr::addToBroadcastMap(const std::shared_ptr &a_radioTelegram) +{ + INFO_LOG(m_logger) << "Move from radioList to bcList: BC=" << a_radioTelegram->getBroadcastIndex() + << " telID=" << a_radioTelegram->getTelID(); + switch (a_radioTelegram->getTelID()) + { + + case GEF_INIT: + case GEF_UMGEBUNGS_MELDUNG2: + ERROR_LOG(m_logger) << "Internal error: telegram with telId=" << a_radioTelegram->getTelID() << " should never be a normal broadcast"; + break; + + case GEF_DATENVERKEHR_TDS_SRT: + case GEF_DATENVERKEHR_TDS_DMF: + case GEF_TREFFER_AUSLOESUNG: + case GEF_ALLGEMEINE_NACHRICHT: + addBroadcastOnlyTelegramToMap(a_radioTelegram); + break; + + + case GEF_SPRACHAUSWAHL: + case GEF_KONFIGURATION_WIRKMODELL: + case GEF_TEILNEHMERMODE_SETZEN: + case GEF_TEILNEHMER_KONFIG_SETZEN: + replaceLastTelegramAndAddAtEnd(a_radioTelegram); + break; + + case GEF_WIRKFELD_EINZELGESCHOSS: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_C_KAMPFMITTEL: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + { + + const uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + INFO_LOG(m_logger) << "Adding to braodcast map, Telegram Id: " << a_radioTelegram->getTelID() + << ", kennung: " << wirkfeldKennung; + if (isEffectSimulationIdDeactivated(wirkfeldKennung)) + { + INFO_LOG(m_logger) << "Got tele with tel id " << telegramId2String(a_radioTelegram->getTelID()) + << ", wirkfeldkennung: " << wirkfeldKennung << ", bcIndex: " << a_radioTelegram->getBroadcastIndex() + << " but this effect simulation is already deactivated... ignoring"; + dumpTelegram(m_logger, a_radioTelegram->getBroadcastIndex(), a_radioTelegram.get()); + emit areaEffectSimulationActivated(wirkfeldKennung); + } + else if (0 != wirkfeldKennung && wirkfeldKennung <= std::numeric_limits::max()) + { + switch (a_radioTelegram->getTelID()) + { + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN); + break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP); + break; + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + break; + case GEF_WIRKFELD_STATUS_MINENSPERRE: + + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_DEAKTIVIERUNG_EINZELMINE); + break; + default: + removeWirkfeldTelegrams(wirkfeldKennung); + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + removeFromDeactivatedAesArea(wirkfeldKennung); + emit areaEffectSimulationActivated(wirkfeldKennung); + break; + } + + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + } + else + { + + ERROR_LOG(m_logger) << "Internal error: Got invalid kennung: " << wirkfeldKennung; + } + break; + } + + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + { + auto wirkfeldTyp = static_cast(a_radioTelegram->getPayloadDataUInt32(5, 1)); + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2); + INFO_LOG(m_logger) << "addToBroadcastMap - Wirkfeld Aenderung Bezeichner for type " + << wirkfeldTyp2Str(wirkfeldTyp) << " - kennung: " + << wirkfeldKennung; + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + break; + } + case GEF_DEAKTIVIERUNG_WIRKFELD: + { + auto wirkfeldTyp = static_cast(a_radioTelegram->getPayloadDataUInt32(5, 1)); + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2); + INFO_LOG(m_logger) << "Deaktivierung Wirkfeld for type " + << wirkfeldTyp2Str(wirkfeldTyp) << " - kennung: " + << wirkfeldKennung << ", bc: " << a_radioTelegram->getBroadcastIndex(); + switch (wirkfeldTyp) + { + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::MineArea: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionArea: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionSingle: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::NContamination: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::CContamination: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DusSingleMineSimulator: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DangerZoneExplosion: + if (0 != wirkfeldKennung && wirkfeldKennung <= 32767) + { + emit areaEffectSimulationDeactivated(wirkfeldKennung); + + removeWirkfeldTelegrams(wirkfeldKennung); + if (addToDeactivatedAesArea(wirkfeldKennung, a_radioTelegram->getBroadcastIndex())) + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + } + else + { + + ERROR_LOG(m_logger) << "Internal error: Got invalid kennung: " << wirkfeldKennung; + } + break; + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::FunctionalArea: + default: + + ERROR_LOG(m_logger) << "Internal error: WirkfeldTyp " << wirkfeldTyp2Str(wirkfeldTyp) << " in GEF_DEAKTIVIERUNG_WIRKFELD not implemented"; + } + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + case GEF_DEAKTIVIERUNG_EINZELMINE: + { + deactivateSingleMine(a_radioTelegram); + break; + } + + case GEF_REAKTIVIERUNG_DUS_MINE: + { + reactivateDusMine(a_radioTelegram); + break; + } + + case GEF_TECHNIK_FUNKTIONSRAUM: + { + + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + + removeFromTechnikFunktionsAndBroadcastMaps(funktionsraumkennung); + + + m_TechnikFunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram)); + + + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + case GEF_FUNKTIONSRAUM: + { + + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + + removeFromFunktionsAndBroadcastMaps(funktionsraumkennung); + removeFromDeactivatedFuncArea(funktionsraumkennung); + + + m_FunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram)); + + + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + { + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + emit areaEffectSimulationDeactivated(funktionsraumkennung); + + removeFromFunktionsAndBroadcastMaps(funktionsraumkennung); + if (addToDeactivatedFuncArea(funktionsraumkennung, a_radioTelegram->getBroadcastIndex())) + m_FunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram)); + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + default: + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + } + +} + + +template +bool removeFromContainers(T &id2bcIndex, S &BcIndex2id, int aesAreaId) +{ + auto it = id2bcIndex.find(aesAreaId); + if (it == id2bcIndex.end()) + return false; + BcIndex2id.remove(it.value()); + id2bcIndex.erase(it); + return true; +} + +template +bool addToContainers(T &id2bcIndex, S &BcIndex2id, int aesAreaId, int bcIndex) +{ + auto it = id2bcIndex.find(aesAreaId); + if (it != id2bcIndex.end()) + { + if (it.value() == bcIndex) + return false; + BcIndex2id.remove(it.value()); + } + id2bcIndex[aesAreaId] = bcIndex; + BcIndex2id[bcIndex] = aesAreaId; + return true; +} + +bool PrtCnvBroadcastMgr::removeFromDeactivatedAesArea(int aesAreaId) +{ + return removeFromContainers(m_deactivatedAesArea2bcIndex, m_deactivatedBcIndex2AesArea, aesAreaId); +} + + +bool PrtCnvBroadcastMgr::addToDeactivatedAesArea(int aesAreaId, int bcIndex) +{ + return addToContainers(m_deactivatedAesArea2bcIndex, m_deactivatedBcIndex2AesArea, aesAreaId, bcIndex); +} + +bool PrtCnvBroadcastMgr::removeFromDeactivatedFuncArea(int aesAreaId) +{ + return removeFromContainers(m_deactivatedFuncArea2bcIndex, m_deactivatedBcIndex2FuncArea, aesAreaId); +} + +bool PrtCnvBroadcastMgr::addToDeactivatedFuncArea(int aesAreaId, int bcIndex) +{ + return addToContainers(m_deactivatedFuncArea2bcIndex, m_deactivatedBcIndex2FuncArea, aesAreaId, bcIndex); +} + +bool PrtCnvBroadcastMgr::removeFromDeactivatedDusMine(int dusMineId) +{ + return removeFromContainers(m_deactivatedDusMine2bcIndex, m_deactivatedBcIndex2DusMine, dusMineId); +} + +bool PrtCnvBroadcastMgr::addToDeactivatedDusMine(int dusMineId, int bcIndex) +{ + return addToContainers(m_deactivatedDusMine2bcIndex, m_deactivatedBcIndex2DusMine, dusMineId, bcIndex); +} + +bool PrtCnvBroadcastMgr::removeFromActivatedDusMine(int dusMineId) +{ + return (m_activatedDusMines.remove(dusMineId)); +} + +void PrtCnvBroadcastMgr::addToActivatedDusMine(int dusMineId) +{ + m_activatedDusMines.insert(dusMineId); +} + + + + + +int PrtCnvBroadcastMgr::getSammeltelegramIndex(const std::shared_ptr &a_sammelTelegram, + const uint16_t a_kennung) const +{ + + uint16_t nbrLength = 0; + switch (a_sammelTelegram->getTelID()) + { + case GEF_WF_SAMMELDEAKTIVIERUNG: + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + nbrLength = 1; + break; + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + case GEF_REAKTIVIERUNG_DUS_MINE: + nbrLength = 2; + break; + default: + ERROR_LOG(m_logger) << "Unknown Sammeltelegram with telId=" << a_sammelTelegram->getTelID(); + return -1; + } + + const int cntAesIds = a_sammelTelegram->getPayloadDataUInt32(5, nbrLength); + for (int i = 0; i < cntAesIds; i++) + { + if (a_kennung == a_sammelTelegram->getPayloadDataUInt32(5 + nbrLength + i * 2, 2)) + return i; + } + return -1; +} + + + + + + + +void PrtCnvBroadcastMgr::deactivateSingleMine(const std::shared_ptr &a_radioTelegram) +{ + uint32_t wirkfeldkennung = a_radioTelegram->getPayloadDataUInt32(9, 2); + uint32_t minenkennung = a_radioTelegram->getPayloadDataUInt32(11, 2); + + if (0 == wirkfeldkennung) + { + removeFromActivatedDusMine(minenkennung); + addToDeactivatedDusMine(minenkennung, a_radioTelegram->getBroadcastIndex()); + DEBUG_LOG(m_logger) << "Deactivating DUS-Mine: " << minenkennung << ", #deactivated mines: " << m_deactivatedBcIndex2DusMine.size(); + removeDusMineDeactivationFromBroadcastMap(minenkennung); + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + } + else + { + + bool sentAsNormalBroadcastFinished = deactivateEinzelmineFromMinensperre(wirkfeldkennung, minenkennung, a_radioTelegram->getBroadcastIndex()); + if (sentAsNormalBroadcastFinished) + { + + addWirkfeldTelegram(a_radioTelegram, wirkfeldkennung, GEF_BESTAETIGUNG, minenkennung); + addBroadcastOnlyTelegramToMap(a_radioTelegram); + } + else + { + + + + + + } + } +} + + + + + + + + + +bool PrtCnvBroadcastMgr::deactivateEinzelmineFromMinensperre(const uint16_t a_wirkfeldKennung, + const uint16_t a_minenKennung, + const uint16_t a_broadcastIndex) +{ + + auto iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung); + while (iter != m_WirkfeldTelegramMapByKennung.end()) + { + if (iter->first != a_wirkfeldKennung) break; + + auto radioTelegram = iter->second; + if (radioTelegram->getTelID() == GEF_WIRKFELD_STATUS_MINENSPERRE && a_wirkfeldKennung == radioTelegram->getPayloadDataUInt32(5, 2)) + { + + uint16_t nbrOfMines = radioTelegram->getPayloadDataUInt32(7, 2); + if (nbrOfMines >= a_minenKennung && a_minenKennung != 0) + { + + + uint16_t bytePos = 9 + (a_minenKennung - 1) / 8; + if (bytePos < radioTelegram->getPayloadSize()) + { + uint8_t mask = 0x80 >> ((a_minenKennung - 1) % 8); + + + radioTelegram->setPayloadDataWithIndex(bytePos, (uint8_t)(radioTelegram->getPayloadDataUInt8(bytePos) & (~mask)), 1); + moveTelegramInBroadcastMap(radioTelegram, a_broadcastIndex); + + + + + + bool dummy; + if (radioTelegram->mustBeSentAsBroadcast(std::numeric_limits::max(), dummy, false)) + { + INFO_LOG(m_logger) << "A normal broadcast-telegram WirkfeldStatusMinensperre still exists"; + return false; + } + return true; + } + else + ERROR_LOG(m_logger) << "Got corrupt telegram WirkfeldstatusMinensperre with nbrOfMines=" << nbrOfMines << " and payloadSize=" << radioTelegram->getPayloadSize(); + } + else + { + + ERROR_LOG(m_logger) << "Mine with kennung=" << a_minenKennung << " does not fit into status (nbrOfMines=" << nbrOfMines << ")"; + } + return true; + } + ++iter; + } + ERROR_LOG(m_logger) << "Did not find the WirkfeldStatusMinensperre with kennung=" << a_wirkfeldKennung + << ", therefore deactivated mine with kennung=" << a_minenKennung << " could not be updated."; + return true; +} + + + + + + +void PrtCnvBroadcastMgr::reactivateDusMine(const std::shared_ptr &a_radioTelegram) +{ + + const uint32_t nbrOfMines = a_radioTelegram->getPayloadDataUInt32(5, 2); + + DEBUG_LOG(m_logger) << "Reactivating DUS-Mines, #mines: " << nbrOfMines; + if (0 == nbrOfMines) + { + + for (int dusMineId : qAsConst(m_deactivatedBcIndex2DusMine)) + { + removeDusMineDeactivationFromBroadcastMap(dusMineId); + addToActivatedDusMine(dusMineId); + } + m_deactivatedDusMine2bcIndex.clear(); + m_deactivatedBcIndex2DusMine.clear(); + } + else + { + + for (uint32_t i = 0; i < nbrOfMines; i++) + { + const int dusMineId = a_radioTelegram->getPayloadDataUInt32(7 + 2 * i, 2); + DEBUG_LOG(m_logger) << "Reactivating DUS-Mines, mindId: " << dusMineId; + removeDusMineDeactivationFromBroadcastMap(dusMineId); + removeFromDeactivatedDusMine(dusMineId); + addToActivatedDusMine(dusMineId); + } + } + + auto pred = [](const std::shared_ptr &tele) -> bool + { + return (tele->getTelID() == GEF_REAKTIVIERUNG_DUS_MINE); + }; + removeFromBroadcastMapFunc(pred); + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); +} + + + + + + +void PrtCnvBroadcastMgr::addWirkfeldTelegram(const std::shared_ptr &a_radioTelegram, + const uint16_t a_wirkfeldKennung, + const gef_telegramm_id_et a_telId, + const uint16_t a_minenKennung) +{ + + auto iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung); + while (iter != m_WirkfeldTelegramMapByKennung.end()) + { + if (iter->first != a_wirkfeldKennung) + break; + auto radioTelegram = iter->second; + + bool isSameMine = true; + if (0 != a_minenKennung) + { + if (GEF_DEAKTIVIERUNG_EINZELMINE == a_radioTelegram->getTelID()) + { + if (GEF_DEAKTIVIERUNG_EINZELMINE == radioTelegram->getTelID()) + { + uint16_t mineIndex = radioTelegram->getPayloadDataUInt32(11, 2); + isSameMine = mineIndex == a_minenKennung; + INFO_LOG(m_logger) << "Mine with kennung=" << a_minenKennung << " found: " << isSameMine; + } + } + else + ERROR_LOG(m_logger) << "Internal error: Only telegrams 'Deaktivierung_Einzelmine' must be called with a_mineKennung. I proceed without respecting mine-kennung..."; + } + + if ((radioTelegram->getTelID() == a_radioTelegram->getTelID() || radioTelegram->getTelID() == a_telId) && isSameMine) + { + + removeFromWirkfeldAndBroadcastMaps(iter); + iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung); + } + else + ++iter; + } + + + INFO_LOG(m_logger) << "Add kennung: " << a_wirkfeldKennung + << " telId=" << a_radioTelegram->getTelID() + << " BC=" << a_radioTelegram->getBroadcastIndex(); + m_WirkfeldTelegramMapByKennung.insert(std::make_pair(a_wirkfeldKennung, a_radioTelegram)); + time_t expireTime = a_radioTelegram->getExpireTime(); + if (expireTime > 0) + m_WirkfeldTelegramMapByTime.insert(std::make_pair(expireTime, a_radioTelegram)); +} + + + + + + + + +void PrtCnvBroadcastMgr::removeWirkfeldTelegrams(const uint16_t a_kennung) +{ + INFO_LOG(m_logger) << "Removing all Wirkfeld-Telegrams with kennung=" << a_kennung; + + auto iter = m_WirkfeldTelegramMapByKennung.find(a_kennung); + while (iter != m_WirkfeldTelegramMapByKennung.end()) + { + if (iter->first != a_kennung) + break; + + removeFromWirkfeldAndBroadcastMaps(iter); + + iter = m_WirkfeldTelegramMapByKennung.find(a_kennung); + } +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung) +{ + auto iter = m_FunktionsraumTelegramMap.find(a_funktionsraumKennung); + if (iter != m_FunktionsraumTelegramMap.end()) + { + auto radioTelegram = iter->second; + + + INFO_LOG(m_logger) << "Removing Funktionsraum-telegram with kennung=" << a_funktionsraumKennung + << " and BC=" << radioTelegram->getBroadcastIndex(); + m_FunktionsraumTelegramMap.erase(iter); + + removeFromBroadcastMap(radioTelegram); + } +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromTechnikFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung) +{ + auto iter = m_TechnikFunktionsraumTelegramMap.find(a_funktionsraumKennung); + if (iter != m_TechnikFunktionsraumTelegramMap.end()) + { + auto radioTelegram = iter->second; + + + INFO_LOG(m_logger) << "Removing Funktionsraum-telegram with kennung=" << a_funktionsraumKennung + << " and BC=" << radioTelegram->getBroadcastIndex(); + m_TechnikFunktionsraumTelegramMap.erase(iter); + + removeFromBroadcastMap(radioTelegram); + } +} + + + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromWirkfeldAndBroadcastMaps(const std::multimap>::iterator &a_wirkfeldTelegramMapByKennungIterator) +{ + auto radioTelegram = a_wirkfeldTelegramMapByKennungIterator->second; + + INFO_LOG(m_logger) << "Removing wirkfeld-telegram with telId=" << radioTelegram->getTelID() + << ", kennung=" << a_wirkfeldTelegramMapByKennungIterator->first + << " and BC=" << radioTelegram->getBroadcastIndex() + << " from byWirkfeldKennung-map"; + + + m_WirkfeldTelegramMapByKennung.erase(a_wirkfeldTelegramMapByKennungIterator); + + + time_t expireTime = radioTelegram->getExpireTime(); + if (0 != expireTime) + { + auto iter = m_WirkfeldTelegramMapByTime.find(expireTime); + while (iter != m_WirkfeldTelegramMapByTime.end()) + { + if (iter->second == radioTelegram) + { + INFO_LOG(m_logger) << "Removing wirkfeld-telegram with telId=" << radioTelegram->getTelID() + << " also from byTime-map"; + m_WirkfeldTelegramMapByTime.erase(iter); + break; + } + ++iter; + } + } + + removeFromBroadcastMap(radioTelegram); +} + + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromBroadcastMap(const std::shared_ptr &a_radioTelegram) +{ + + if (!a_radioTelegram) + return; + + auto iter = m_BroadcastMap.find(a_radioTelegram->getBroadcastIndex()); + if (iter != m_BroadcastMap.end()) + { + if (iter->second == a_radioTelegram) + { + m_BroadcastMap.erase(iter); + detachTelegram(a_radioTelegram); + } + else if (iter->second->getBroadcastonlyTelegram() == a_radioTelegram) + iter->second->setBroadcastonlyTelegram(nullptr); + } +} + +void PrtCnvBroadcastMgr::removeFromBroadcastMapFunc(const std::function &)> &pred) +{ + auto it = m_BroadcastMap.begin(); + while (it != m_BroadcastMap.end()) + { + const auto &p = *it; + if (pred(p.second)) + it = m_BroadcastMap.erase(it); + else + ++it; + } +} + +void PrtCnvBroadcastMgr::removeDusMineDeactivationFromBroadcastMap(int dusMineId) +{ + auto pred = [dusMineId](const std::shared_ptr &tele) -> bool + { + return (tele->getTelID() == GEF_DEAKTIVIERUNG_EINZELMINE && + 0 == tele->getPayloadDataUInt32(9, 2) && + uint32_t(dusMineId) == tele->getPayloadDataUInt32(11, 2)); + }; + removeFromBroadcastMapFunc(pred); +} + +template +void removeFromMap(T &cont, const std::shared_ptr &a_radioTelegram) +{ + auto iter = cont.begin(); + while (iter != cont.end()) + { + if (iter->second == a_radioTelegram) + iter = cont.erase(iter); + else + ++iter; + } +} + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromAllMaps(const std::shared_ptr &a_radioTelegram) +{ + INFO_LOG(m_logger) << "Remove telegram with telId=" << a_radioTelegram->getTelID() << " BC=" << a_radioTelegram->getBroadcastIndex(); + + removeFromBroadcastMap(a_radioTelegram); + + + removeFromMap(m_WirkfeldTelegramMapByKennung, a_radioTelegram); + + + removeFromMap(m_WirkfeldTelegramMapByTime, a_radioTelegram); + + + removeFromMap(m_FunktionsraumTelegramMap, a_radioTelegram); + + + removeFromMap(m_LastTelegramMap, a_radioTelegram); +} + + + + + +void PrtCnvBroadcastMgr::replaceLastTelegramAndAddAtEnd(const std::shared_ptr &a_newRadioTelegram) +{ + + auto iter = m_LastTelegramMap.find(a_newRadioTelegram->getTelID()); + if (iter != m_LastTelegramMap.end()) + { + auto lastRadioTelegram = iter->second; + + INFO_LOG(m_logger) << "remove last telegram with telId=" << lastRadioTelegram->getTelID() + << " and BC=" << lastRadioTelegram->getBroadcastIndex(); + removeFromBroadcastMap(lastRadioTelegram); + m_LastTelegramMap.erase(iter); + } + + m_BroadcastMap.insert(std::make_pair(a_newRadioTelegram->getBroadcastIndex(), a_newRadioTelegram)); + + m_LastTelegramMap.insert(std::make_pair(a_newRadioTelegram->getTelID(), a_newRadioTelegram)); + INFO_LOG(m_logger) << "New last telegram with with telId=" << a_newRadioTelegram->getTelID() + << " and BC=" << a_newRadioTelegram->getBroadcastIndex(); +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::moveTelegramInBroadcastMap(const std::shared_ptr &a_radioTelegram, + const uint16_t a_newBroadcastIndex, + const std::shared_ptr &a_attachTelegram) +{ + + INFO_LOG(m_logger) << "Move telId=" << a_radioTelegram->getTelID() + << " from BC=" << a_radioTelegram->getBroadcastIndex() + << " to BC=" << a_newBroadcastIndex; + removeFromBroadcastMap(a_radioTelegram); + + a_radioTelegram->setBroadcastIndex(a_newBroadcastIndex); + m_BroadcastMap.insert(std::make_pair(a_newBroadcastIndex, a_radioTelegram)); + + if (a_attachTelegram && (a_attachTelegram->getTelID() != GEF_REAKTIVIERUNG_DUS_MINE)) + { + INFO_LOG(m_logger) << "Attach telID=" << a_attachTelegram->getTelID() + << " to telID=" << a_radioTelegram->getTelID() + << " BC=" << a_newBroadcastIndex; + a_radioTelegram->setBroadcastonlyTelegram(a_attachTelegram); + a_attachTelegram->setBroadcastIndex(a_newBroadcastIndex); + } +} + + + + + +uint16_t PrtCnvBroadcastMgr::getBroadcastIndex() const +{ + return m_BroadcastIndex; +} + + + + + +uint16_t PrtCnvBroadcastMgr::getNextBroadcastIndex() +{ + return ++m_BroadcastIndex; +} + + + + + +std::shared_ptr PrtCnvBroadcastMgr::getNopTelegram(const uint16_t a_from, const uint16_t a_to) +{ + auto nopTelegram(std::make_shared(GEF_NOP, 7, 0)); + nopTelegram->setPayloadDataWithIndex(3, a_from, 2); + nopTelegram->setPayloadDataWithIndex(5, a_to, 2); + return nopTelegram; +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::addBroadcastOnlyTelegramToMap(const std::shared_ptr &a_broadcastOnlyTelegram) +{ + uint16_t broadcastIndex = a_broadcastOnlyTelegram->getBroadcastIndex(); + auto iter = m_BroadcastMap.find(broadcastIndex); + if (m_BroadcastMap.end() == iter) + { + + INFO_LOG(m_logger) << "Insert telId=" << a_broadcastOnlyTelegram->getTelID() + << " as broadcastonly telegram with BC=" << broadcastIndex; + a_broadcastOnlyTelegram->setBroadcastOnly(); + m_BroadcastMap.insert(std::make_pair(broadcastIndex, a_broadcastOnlyTelegram)); + } + else + { + + INFO_LOG(m_logger) << "Add telId=" << a_broadcastOnlyTelegram->getTelID() + << " as broadcastonly telegram to telegramm with BC=" << iter->second->getBroadcastIndex(); + iter->second->setBroadcastonlyTelegram(a_broadcastOnlyTelegram); + } +} + + + + + + +void PrtCnvBroadcastMgr::detachTelegram(const std::shared_ptr &a_radioTelegram) +{ + auto broadcastOnlyTelegram = a_radioTelegram->getBroadcastonlyTelegram(); + if (broadcastOnlyTelegram) + { + uint16_t broadcastIndex = a_radioTelegram->getBroadcastIndex(); + + INFO_LOG(m_logger) << "detach bconly-telegram : telId=" << a_radioTelegram->getTelID() << " BC=" << broadcastIndex; + if (broadcastOnlyTelegram->getBroadcastIndex() != broadcastIndex) + ERROR_LOG(m_logger) << "Internal error: BC=" << broadcastOnlyTelegram->getBroadcastIndex() << " of attached telegram is not equal BC=" << broadcastIndex; + auto iter = m_BroadcastMap.find(broadcastIndex); + if (iter != m_BroadcastMap.end()) + ERROR_LOG(m_logger) << "Internal error: m_BroadcastMap-entry with BC=" << broadcastIndex << " must not exists"; + else + { + INFO_LOG(m_logger) << "Insert broadcast-only BC=" << broadcastOnlyTelegram->getBroadcastIndex(); + broadcastOnlyTelegram->setBroadcastOnly(); + m_BroadcastMap.insert(std::make_pair(broadcastIndex, broadcastOnlyTelegram)); + } + a_radioTelegram->setBroadcastonlyTelegram(nullptr); + } +} + + + + + + +void PrtCnvBroadcastMgr::handleOverrunOfBroadcastCounter(const bool a_doRestore) +{ + WARNING_LOG(m_logger) << "Broadcast-counter reaches maximum => reduce broadcast-list and increment reset-counter"; + + + + if (!a_doRestore) + { + m_DbThread->waitUntilDbWritten(); + getAllFinishedBroadcastsFromDb(); + } + + + uint16_t newBroadcastCounter = 0; + std::map> newBroadcastMap; + auto iter = m_BroadcastMap.begin(); + while (iter != m_BroadcastMap.end()) + { + auto radioTelegram = iter->second; + if (radioTelegram->isBroadcastOnly()) + { + + ++iter; + removeFromAllMaps(radioTelegram); + } + else + { + radioTelegram->setBroadcastIndex(++newBroadcastCounter); + auto broadcastOnlyTelegram = radioTelegram->getBroadcastonlyTelegram(); + if (broadcastOnlyTelegram) + { + radioTelegram->setBroadcastonlyTelegram(nullptr); + ++iter; + removeFromAllMaps(broadcastOnlyTelegram); + } + else + { + + + bool wasLast; + if (radioTelegram->mustBeSentAsBroadcast(std::numeric_limits::max(), wasLast, false)) + { + do + { + radioTelegram->mustBeSentAsBroadcast(std::numeric_limits::max(), wasLast, true); + } + while (!wasLast); + } + ++iter; + } + INFO_LOG(m_logger) << "New BC-index for broadcast-telegram with telId=" << radioTelegram->getTelID() << " BC=" << newBroadcastCounter; + newBroadcastMap.insert(std::make_pair(newBroadcastCounter, radioTelegram)); + } + } + m_BroadcastMap.clear(); + m_BroadcastMap = newBroadcastMap; + + + cleanAndInit(false); + if (!a_doRestore) m_DbThread->setResetCounter(m_DbThread->getResetCounter() + 1); + + WARNING_LOG(m_logger) << "New broadcast-counter=" << newBroadcastCounter << " new reset-counter=" << (int)m_DbThread->getResetCounter(); + m_BroadcastIndex = newBroadcastCounter; +} + + + + + +void PrtCnvBroadcastMgr::restoreAfterCrash() +{ + getAllFinishedBroadcastsFromDb(true); +} + + + + + +void PrtCnvBroadcastMgr::dump() +{ + + for (const auto &it : m_BroadcastMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_BroadcastMap, "); + + for (const auto &it : m_WirkfeldTelegramMapByKennung) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_WirkfeldTelegramMapByKennung, "); + + for (const auto &it : m_WirkfeldTelegramMapByTime) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_WirkfeldTelegramMapByTime, "); + + for (const auto &it : m_FunktionsraumTelegramMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_FunktionsraumTelegramMap, "); + + for (const auto &it : m_TechnikFunktionsraumTelegramMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_TechnikFunktionsraumTelegramMap, "); + + for (const auto &it : m_LastTelegramMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_LastTelegramMap, "); +} + + + + + + +void PrtCnvBroadcastMgr::incTickAndSetTrafficLoad(const bool a_isHighLoad, const bool a_isFullLoad) +{ + if (e_ST_COLLECT == m_State) + ++m_TickCounter; + m_IsFullLoad = a_isFullLoad; + if (a_isHighLoad) + m_ActClaimWindow = m_HighLoadFactor * m_ClaimWindow; + else + m_ActClaimWindow = m_ClaimWindow; +} + + + + +bool PrtCnvBroadcastMgr::isEffectSimulationIdDeactivated(const uint16_t effectsimulationId) const +{ + INFO_LOG(m_logger) << "Checking deactivation for Id " << effectsimulationId; + return m_deactivatedAesArea2bcIndex.contains(effectsimulationId); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp new file mode 100644 index 000000000..7b424aa6f --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp @@ -0,0 +1,359 @@ + + + + + + + + + + + + + +#pragma once + +#include "logger.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace N_CoPrtCnv +{ +class CoPrtCnvRadioTelegram; +} + +#define MAX_BROADCAST_INDEX 65535 + + +namespace PrtCnv +{ +class PrtCnvDbThread; + + + +class PrtCnvBroadcastMgr final : public QObject +{ + Q_OBJECT +public: + + + + enum E_State + { + e_ST_UNDEFINED, + e_ST_COLLECT, + e_ST_SEND_NACHFORDERUNG + }; + + PrtCnvBroadcastMgr(); + + + + bool handleRadioTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + + + int32_t create(NGL::Settings *settings); + + + + int32_t init(); + + + + std::shared_ptr getNextBroadcastTelegramToSend(const uint16_t a_beginSearchWithBroadcastIndex, + const time_t a_currentTime); + + + + void setDbThread(PrtCnvDbThread *a_dbThread); + + + + + void cleanAndInit(const bool a_deleteTelegrams); + + + + + void handleOverrunOfBroadcastCounter(const bool a_doRestore = false); + + + + std::shared_ptr getNextNachforderungTelegramToSend(); + + + + void dump(); + + + + + void restoreAfterCrash(); + + + + + uint16_t getBroadcastIndex() const; + + + + uint16_t getNextBroadcastIndex(); + + + + void addBroadcastOnlyTelegramToMap(const std::shared_ptr &a_broadcastOnlyTelegram); + + + + void incTickAndSetTrafficLoad(const bool a_isHighLoad, const bool a_isFullLoad); + + + + bool isEffectSimulationIdDeactivated(const uint16_t effectsimulationId) const; + + + + void handleNachforderungBroadcastTelegram(int identity, int broadcastIndex, int resetCounter); + +protected: + struct EquipNoBcIndex + { + int equipNo = 0; + int bcIndex = 0; + + EquipNoBcIndex() = default; + EquipNoBcIndex(int e, int b) : equipNo(e), bcIndex(b) {} + }; + + + std::vector m_claimerArray; + + + uint16_t m_ClaimWindow; + + + uint16_t m_HighLoadFactor; + + + uint16_t m_BroadcastLimit; + + + NGL::Settings *m_Config; + + + uint16_t m_ActClaimWindow; + + + PrtCnvBroadcastMgr::E_State m_State; + uint16_t m_TickCounter; + + + PrtCnvDbThread *m_DbThread; + + + + + std::map> m_BroadcastMap; + + std::vector> m_broadcastTelegamsToSend; + + + + std::map> m_LastTelegramMap; + + + + + std::multimap> m_WirkfeldTelegramMapByKennung; + + + + + std::multimap> m_WirkfeldTelegramMapByTime; + + + + + std::map> m_FunktionsraumTelegramMap; + + + + + std::map> m_TechnikFunktionsraumTelegramMap; + + + + + uint16_t m_BroadcastIndex; + + + + bool m_IsFullLoad; + + + uint16_t m_FinishedBroadcastIndex; + + + uint16_t m_FirstBroadcastIndexOfBc1; + + + + void addToBroadcastMap(const std::shared_ptr &a_radioTelegram); + + + + std::shared_ptr getNachforderungsTelegram(int curBcIndex, int startBcIndex, int &nextBcIndex); + + + + int getSammeltelegramIndex(const std::shared_ptr &a_sammelTelegram, + const uint16_t a_kennung) const; + + + + void moveTelegramInBroadcastMap(const std::shared_ptr &a_radioTelegram, + const uint16_t a_newBroadcastIndex, + const std::shared_ptr &a_attachTelegram = {}); + + + + void removeFromBroadcastMap(const std::shared_ptr &a_radioTelegram); + void removeFromBroadcastMapFunc(const std::function &)> &pred); + void removeDusMineDeactivationFromBroadcastMap(int dusMineId); + + std::shared_ptr createAccumulationTelegram(int curBcIndex, + int startBcIndex, + gef_telegramm_id_et telId, + const QMap &bcIndex2Type, + int maxIdsPerTelegram, + int sizeOfSumField) const; + + bool removeFromDeactivatedAesArea(int aesAreaId); + bool addToDeactivatedAesArea(int aesAreaId, int bcIndex); + + QHash m_deactivatedAesArea2bcIndex; + + QMap m_deactivatedBcIndex2AesArea; + std::shared_ptrcreateAccuTeleDeactivatedAesAreas(int curBcIndex, int startBcIndex) const; + + bool removeFromDeactivatedFuncArea(int aesAreaId); + bool addToDeactivatedFuncArea(int aesAreaId, int bcIndex); + + QHash m_deactivatedFuncArea2bcIndex; + + QMap m_deactivatedBcIndex2FuncArea; + std::shared_ptrcreateAccuTeleDeactivatedFuncAreas(int curBcIndex, int startBcIndex) const; + + bool removeFromDeactivatedDusMine(int dusMineId); + bool addToDeactivatedDusMine(int dusMineId, int bcIndex); + + QHash m_deactivatedDusMine2bcIndex; + + QMap m_deactivatedBcIndex2DusMine; + std::shared_ptr createAccuTeleDeactivatedDusMines(int curBcIndex, int startBcIndex) const; + + bool removeFromActivatedDusMine(int dusMineId); + void addToActivatedDusMine(int dusMineId); + QSet m_activatedDusMines; + std::shared_ptr createAccuTeleActivatedDusMines(int curBcIndex); + + + + bool removeFromSammeltelegram(const std::shared_ptr &a_sammelTelegram, + const uint16_t a_kennung, + const uint16_t a_anzahlPos, + const uint8_t a_anzahlSize, + bool &a_sammelTelRemoved); + + + + void replaceLastTelegramAndAddAtEnd(const std::shared_ptr &a_newRadioTelegram); + + + + + std::string dumpSammeldeaktivierung(const N_CoPrtCnv::CoPrtCnvRadioTelegram *sammelTelegram); + + + + void getAllFinishedBroadcastsFromDb(const bool a_doRestore = false); + + + + + void removeExpiredTelegrams(); + + + + void removeWirkfeldTelegrams(const uint16_t a_kennung); + + + + void addWirkfeldTelegram(const std::shared_ptr &a_radioTelegram, + const uint16_t a_wirkfeldKennung, const gef_telegramm_id_et a_telId = GEF_BESTAETIGUNG, + const uint16_t a_minenKennung = 0); + + + + bool deactivateEinzelmineFromMinensperre(const uint16_t a_wirkfeldKennung, const uint16_t a_minenKennung, const uint16_t a_broadcastIndex); + + + + std::shared_ptr getNopTelegram(const uint16_t a_from, const uint16_t a_to); + + + void removeFromAllMaps(const std::shared_ptr &a_radioTelegram); + + + + void detachTelegram(const std::shared_ptr &a_radioTelegram); + + + + void removeFromFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung); + void removeFromTechnikFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung); + + + + void removeFromWirkfeldAndBroadcastMaps(const std::multimap>::iterator &a_wirkfeldTelegramMapByKennungIterator); + + + + void reactivateDusMine(const std::shared_ptr &a_radioTelegram); + + + + void deactivateSingleMine(const std::shared_ptr &a_radioTelegram); + + + + void prepareForSendNachforderungen(); + + + + std::shared_ptr evaluateNextNachforderungToSend(); + +Q_SIGNALS: + void areaEffectSimulationActivated(int wirkfeldKennung); + void areaEffectSimulationDeactivated(int wirkfeldKennung); + +private: + + + NGL::INGLLogger &m_logger; + NGL::INGLLogger &m_loggerBcRequest; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvCentralThread.cpp b/TetraIF/PrtCnv/PrtCnvCentralThread.cpp new file mode 100644 index 000000000..4e2b3c736 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvCentralThread.cpp @@ -0,0 +1,842 @@ + + + + + + + + + + + + + + +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvStoredCentralTelegram.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace PrtCnv +{ + + +PrtCnvCentralThread::PrtCnvCentralThread(PrtCnv::PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvCentralThread") + , m_webSocket(nullptr) + , m_SendCounter(0) + , m_RadioThread(nullptr) + , m_RadioStopped(false) + , m_CentralStopped(false) + , m_LastSendCounter(0) + , m_VirtualTeilnehmerId(0) + , m_maxEqID(50000) + , m_aliveTimer(nullptr) + , m_sendAckTimer(nullptr) + , m_reconnectTimer(nullptr) + , m_DbThread(nullptr) + , m_LogThread(nullptr) + , m_InjectionThread(nullptr) + , m_ReceiveCounter(0) + , m_ReceiveAckCounter(0) + , m_State(PrtCnvSocketThread::e_INITIAL) + , m_bDirectConnection(false) + , m_bRadioThreadInitDone(false) +{ + m_Name = QStringLiteral("Central"); +} + +PrtCnvCentralThread::~PrtCnvCentralThread() +{ + destroy(); +} + + + + +int32_t PrtCnvCentralThread::create(NGL::Settings *settings) +{ + PrtCnvThread::create(settings); + + INFO_LOG(m_logger) << "Create"; + + m_RadioThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Radio)); + m_DbThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Db)); + m_LogThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Log)); + m_InjectionThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Injection)); + connect(m_DbThread, &PrtCnvDbThread::playerLicencedChanged, + this, &PrtCnvCentralThread::onPlayerLicencedChanged, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::checkSendToCentral, this, &PrtCnvCentralThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::checkSendToRadio, m_RadioThread, &PrtCnvRadioThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::stopRadio, m_RadioThread, &PrtCnvRadioThread::doStop, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::cleanRadio, m_RadioThread, &PrtCnvRadioThread::doClean, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::startRadio, m_RadioThread, &PrtCnvRadioThread::doStart, Qt::QueuedConnection); + connect(m_RadioThread, &PrtCnvRadioThread::initDone, + this, &PrtCnvCentralThread::onRadioThreadInitDone); + connect(m_RadioThread, &PrtCnvRadioThread::areaEffectSimulationActivated, + this, &PrtCnvCentralThread::onAreaEffectSimulationActivated, Qt::QueuedConnection); + connect(m_RadioThread, &PrtCnvRadioThread::areaEffectSimulationDeactivated, + this, &PrtCnvCentralThread::onAreaEffectSimulationDeactivated, Qt::QueuedConnection); + + auto mainApp = m_Parent->getMainApp(); + connect(this, &PrtCnvCentralThread::directTextMessage, + mainApp, &PrtCnvApplication::textMessageFromPrtCnvToCentral); + connect(mainApp, &PrtCnvApplication::textMessageFromCentralToPrtCnv, + this, &PrtCnvCentralThread::onDirectTextMessageReceived); + + m_aliveTimer = new QTimer(this); + connect(m_aliveTimer, &QTimer::timeout, this, &PrtCnvCentralThread::timeoutAliveAndConnection); + + m_sendAckTimer = new QTimer(this); + connect(m_sendAckTimer, &QTimer::timeout, this, &PrtCnvCentralThread::timeoutTick); + + const int disconnectTimeout = m_Config->getInteger(getName(), QStringLiteral("DisconnectTimeout"), 10000); + m_reconnectTimer = new QTimer(this); + m_reconnectTimer->setInterval(disconnectTimeout); + m_reconnectTimer->setSingleShot(true); + connect(m_reconnectTimer, &QTimer::timeout, this, &PrtCnvCentralThread::connectSocket); + + return 0; +} + + + + + +int32_t PrtCnvCentralThread::destroy() +{ + INFO_LOG(m_logger) << "Destroy"; + PrtCnvThread::destroy(); + delete m_webSocket; m_webSocket = nullptr; + delete m_aliveTimer; m_aliveTimer = nullptr; + delete m_sendAckTimer; m_sendAckTimer = nullptr; + delete m_reconnectTimer; m_reconnectTimer = nullptr; + return 0; +} + + + + +int32_t PrtCnvCentralThread::init() +{ + INFO_LOG(m_logger) << "Init"; + PrtCnvThread::init(); + m_CentralStopped = false; + m_RadioStopped = false; + + m_aliveTimer->setInterval(m_Config->getInteger(getName(), QStringLiteral("AliveTimeout"), 3000)); + m_sendAckTimer->setInterval(m_Config->getInteger(getName(), QStringLiteral("AckTimeout"), 900)); + + m_VirtualTeilnehmerId = m_Config->getInteger(QStringLiteral("Common"), QStringLiteral("VirtualIdPrtCnv"), 90); + m_maxEqID = m_Config->getInteger(QStringLiteral("Common"), QStringLiteral("MaxEqID"), 50000); + + return 0; +} + +int32_t PrtCnvCentralThread::deinit() +{ + INFO_LOG(m_logger) << "Deinit"; + PrtCnvThread::deinit(); + return 0; +} + + + + +int32_t PrtCnvCentralThread::start() +{ + INFO_LOG(m_logger) << "Start"; + PrtCnvThread::start(); + if (m_DbThread->mustProceedCleanup()) + { + INFO_LOG(m_logger) << "Proceed cleanup DB after crash..."; + m_CentralStopped = true; + emit stopRadio(); + } + else + { + connectSocket(); + } + + return 0; +} + + + + +int32_t PrtCnvCentralThread::stop() +{ + INFO_LOG(m_logger) << "Stop"; + PrtCnvThread::stop(); + + return 0; +} + + + + + +void PrtCnvCentralThread::connected() +{ + INFO_LOG(m_logger) << "Central-Socket connected m_Socket=" << m_webSocket; + m_SendCounter = 0; + m_LastSendCounter = 0; + m_ReceiveCounter = 0; + m_ReceiveAckCounter = 0; + m_aliveTimer->start(); + if (m_bRadioThreadInitDone) + m_sendAckTimer->start(); + m_State = PrtCnvSocketThread::e_WORKING; + emit checkSendToCentral(); +} + + + + +void PrtCnvCentralThread::disconnected() +{ + INFO_LOG(m_logger) << "disconnected m_Socket=" << m_webSocket; + + + if (PrtCnvSocketThread::e_WORKING == m_State && m_webSocket) + m_webSocket->close(); + + m_State = PrtCnvSocketThread::e_DISCONNECTING; + if (m_DoCleanup) + { + INFO_LOG(m_logger) << "cleanup while disconnection"; + m_sendAckTimer->stop(); + m_CentralStopped = true; + if (m_RadioStopped) + cleanAndReinit(); + } + else + { + m_DbThread->prepareCentralTelegramsForReconnection(); + connectSocket(); + } +} + + + + + + +void PrtCnvCentralThread::radioStopped() +{ + m_RadioStopped = true; + if (m_CentralStopped) + cleanAndReinit(); +} + + + + + + +void PrtCnvCentralThread::cleanAndReinit() +{ + INFO_LOG(m_logger) << "cleanAndReinit"; + emit cleanRadio(); + + m_ReceiveAckCounter = 0; + m_DbThread->cleanAndInit(); + m_DoCleanup = false; +} + + + + + + +void PrtCnvCentralThread::radioCleant() +{ + if (!m_DoCleanup) + { + m_DbThread->setMachineState(0); + m_RadioStopped = false; + m_CentralStopped = false; + emit startRadio(); + connectSocket(); + } + else + { + ERROR_LOG(m_logger) << "Internal error: radioCleant, but central still cleaning up."; + } +} + + + + +void PrtCnvCentralThread::onTextMessageReceived(const QString &msg) +{ + + if (m_DoCleanup) + return; + if (PrtCnvSocketThread::e_WORKING != m_State) + return; + onDirectTextMessageReceived(msg.toUtf8()); +} + +void PrtCnvCentralThread::onDirectTextMessageReceived(const QByteArray &baJson) +{ + try + { + if (baJson.isEmpty()) + throw std::exception(); + const QJsonObject obj = QJsonDocument::fromJson(baJson).object(); + + const QJsonValue typeId = obj.value(QStringLiteral("typeId")); + if (!typeId.isDouble()) + throw TrainingAreaBase::TetraIcd::JsonException(obj, QStringLiteral("typeId")); + + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(baJson, obj, static_cast(typeId.toInt())); + + m_LogThread->writeCentralTelegramLog(&telegram, false, 1); + + m_aliveTimer->start(); + + + if (telegram.telegramId() == TrainingAreaBase::TetraIcd::BESTAETIGUNG) + { + + handleAck(&telegram); + } + else + { + DEBUG_LOG(m_logger) << "Received telegram '" << baJson << "'"; + + handleTelegram(&telegram); + } + } + catch (const std::exception &e) + { + ERROR_LOG(m_logger) << "JSon conversion error happenend. Error:" + << e.what() << ", msg: " << baJson; + + TrainingAreaBase::TetraIcd::CtaDataError tele; + tele.header.equipmentNumber = m_VirtualTeilnehmerId; + tele.header.timeStamp = time(nullptr) * 1000LL; + tele.reason = TrainingAreaBase::TetraIcd::CtaDataError::Reason::JsonDecodeFailure; + tele.originTelegramId = 0; + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(tele); + sendTelegram(&telegram); + } +} + + +void PrtCnvCentralThread::stateChanged(QAbstractSocket::SocketState newState) +{ + INFO_LOG(m_logger) << "Websocket changed to state " << newState; +} + + + + + +void PrtCnvCentralThread::handleTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + + + + DEBUG_LOG(m_logger) << "Receive Central-Telegram with telId=" << a_telegram->telegramId() + << "; rcounter=" << a_telegram->counter(); + if (checkAndUpdateReceiveCounter(a_telegram->counter())) + { + if (handleSpecialTelegram(a_telegram)) + { + using namespace TrainingAreaBase::TetraIcd; + if (a_telegram->telegramId() == TelegramId::DEAKTIVIERUNG_WIRKFELD) + { + const DeactivateEffectSimulation des(DeactivateEffectSimulation::fromJson(a_telegram->jsonData())); + switch (des.aesType) + { + case AreaEffectSimulationType::MineArea: + case AreaEffectSimulationType::ExplosionArea: + case AreaEffectSimulationType::ExplosionSingle: + case AreaEffectSimulationType::NContamination: + case AreaEffectSimulationType::CContamination: + case AreaEffectSimulationType::FunctionalArea: + case AreaEffectSimulationType::DusSingleMineSimulator: + if (m_deactivatedAreaEffectSimulations.contains(des.aesDdsId)) + { + INFO_LOG(m_logger) << "AES with id " << des.aesDdsId << " already deactivated - ignoring new deactivation telegram"; + return; + } + break; + case AreaEffectSimulationType::TechnicalArea: + case AreaEffectSimulationType::GasPipeDetonation: + case AreaEffectSimulationType::SpecialArea: + case AreaEffectSimulationType::Unknown: + Q_ASSERT(false); + break; + case AreaEffectSimulationType::BeStillWarning: + break; + } + } + else if (a_telegram->telegramId() == TelegramId::WIRKFELD_STATUS_MINENSPERRE) + { + const MineAreaSingleMineState msms(MineAreaSingleMineState::fromJson(a_telegram->jsonData())); + QSet &oldTriggeredMines = m_alreadyTriggeredMines[msms.aesDdsId]; + QSet newTriggeredMines; + newTriggeredMines.reserve(oldTriggeredMines.size() + 5); + bool bSomethingChanged = false; + for (int i = 0; i < msms.mineCount; ++i) + { + if (!LtsUtils::BitArray::testBit(msms.mineState, i)) + { + INFO_LOG(m_logger) << "Testing bit " << i << " ... not set = triggered"; + if (!oldTriggeredMines.contains(i)) + { + INFO_LOG(m_logger) << "not in old one"; + bSomethingChanged = true; + } + newTriggeredMines.insert(i); + } + } + if (!bSomethingChanged) + bSomethingChanged = newTriggeredMines.size() != oldTriggeredMines.size(); + if (!bSomethingChanged) + { + INFO_LOG(m_logger) << "MineState telegram contains no new informations - skipping " << msms.aesDdsId; + return; + } + INFO_LOG(m_logger) << "MineState telegram contains new informations... " << msms.aesDdsId; + oldTriggeredMines = newTriggeredMines; + } + + std::shared_ptr + radioTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(a_telegram)); + if (radioTelegram) + { + if (radioTelegram->getIdentity() <= m_maxEqID) { + + m_DbThread->storeRadioTelegram(radioTelegram, a_telegram->counter()); + } else { + WARNING_LOG(m_logger) << "Central telegram with telId=" << a_telegram->telegramId() + << " has invalid identity:" << radioTelegram->getIdentity(); + } + } + else + { + m_DbThread->centralCounterReadyForAck(a_telegram->counter()); + WARNING_LOG(m_logger) << "Central telegram with telId=" << a_telegram->telegramId() + << " could not be converted"; + } + } + } + emit checkSendToRadio(); +} + + + + + + + +bool PrtCnvCentralThread::checkAndUpdateReceiveCounter(const int32_t a_counter) +{ + TRACE_LOG(m_logger) << "checkAndUpdateReceiveCounter: " << a_counter << ", " << m_ReceiveCounter; + + if (std::numeric_limits::max() == ++m_ReceiveCounter) + m_ReceiveCounter = 0; + + + if (m_ReceiveCounter != a_counter) + { + if (m_ReceiveCounter > a_counter) + { + ERROR_LOG(m_logger) << "It seems, the telegram with counter " << a_counter << " was resent from " + << getName() << "! Expected: " << m_ReceiveCounter; + } + else + { + ERROR_LOG(m_logger) << "It seems, we lost one or several telegrams from " << getName() + << ": receive-counter of received telegram: " << a_counter << "; Expected: " << m_ReceiveCounter; + } +#if 0 + m_ReceiveCounter--; + return false; +#else + m_ReceiveCounter = a_counter; + return true; +#endif + } + return true; +} + + + + +void PrtCnvCentralThread::timeoutTick() +{ + + if (m_DoCleanup) + return; + if (PrtCnvSocketThread::e_WORKING != m_State) + return; + + + + + + try + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *centralInjectTelegram; + while ((centralInjectTelegram = m_InjectionThread->getNextCentralInjectionTelegram())) + { + sendTelegram(centralInjectTelegram); + delete centralInjectTelegram; + } + } + catch (std::exception& e) + { + ERROR_LOG(m_logger) << "Catched an unexpected exception: " << e.what() + << " => could not inject radio-telegram, but we proceed..."; + } + + + sendAck(); +} + + + + +void PrtCnvCentralThread::timeoutAliveAndConnection() +{ + INFO_LOG(m_logger) << "timeoutAliveAndConnection socketState=" + << int(m_webSocket ? m_webSocket->state() : -1) + << " m_State=" << m_State << " m_Socket=" << m_webSocket; + switch (m_State) + { + case PrtCnvSocketThread::e_CONNECTING: + connectSocket(); + break; + case PrtCnvSocketThread::e_WORKING: + if (!m_bDirectConnection) + { + disconnectSocket(); + m_reconnectTimer->start(); + } + break; + case PrtCnvSocketThread::e_DISCONNECTING: + break; + default: + ERROR_LOG(m_logger) << "timeoutAlive for m_State=" << m_State << " not implemented"; + } +} + + + + +void PrtCnvCentralThread::sendAck() +{ + TrainingAreaBase::TetraIcd::Acknowledge ack; + ack.timeStamp = time(nullptr) * 1000; + ack.ackCounter = m_ReceiveAckCounter; + N_CoPrtCnv::CoPrtCnvCentralTelegram tele(ack); + + if (m_webSocket) + m_webSocket->sendTextMessage(QString::fromUtf8(tele.data())); + else + emit directTextMessage(tele.data()); + + TRACE_LOG(m_logger) << "Wrote ack: " << tele.data(); +} + + + + + + +void PrtCnvCentralThread::sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + PrtCnvStoredCentralTelegram *handle = nullptr; + sendTelegram(a_telegram, handle); +} + + + + + + + +void PrtCnvCentralThread::sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram, + PrtCnvStoredCentralTelegram *a_handle) +{ + using namespace TrainingAreaBase::TetraIcd; + if (a_telegram->telegramId() == TelegramId::DEAKTIVIERUNG_EINZELMINE) + { + const MineTriggered tele(MineTriggered::fromJson(a_telegram->jsonData())); + m_alreadyTriggeredMines[tele.mineAreaId].insert(tele.mineIndex - 1); + INFO_LOG(m_logger) << "Adding triggered mine with id " << tele.mineIndex << " to area id " << tele.mineAreaId; + } + + + const int writeCounter = a_handle ? a_handle->writeCounter() : 0; + if (writeCounter != 0) + a_telegram->setCounter(writeCounter); + else + a_telegram->setCounter(++m_SendCounter); + + + DEBUG_LOG(m_logger) << "Send telegram to central: telId=" << a_telegram->telegramId() + << " wcounter=" << a_telegram->counter(); + + if (m_webSocket) + m_webSocket->sendTextMessage(QString::fromUtf8(a_telegram->data())); + else + emit directTextMessage(a_telegram->data()); + + + if (a_handle) + m_DbThread->centralTelegramSent(a_telegram->counter(), a_handle); + m_LogThread->writeCentralTelegramLog(a_telegram, true, 1); +} + + + + + + + +void PrtCnvCentralThread::handleAnforderungStatistikBroadcastNachforderungen() +{ + const auto nachforderungsStat = m_DbThread->getClaimStatistics(); + + + TrainingAreaBase::TetraIcd::BroadcastStatistics tele; + tele.header.equipmentNumber = m_VirtualTeilnehmerId; + tele.header.timeStamp = time(nullptr) * 1000LL; + tele.information.reserve(nachforderungsStat.size()); + for (const auto &it : nachforderungsStat) + { + TrainingAreaBase::TetraIcd::BroadcastInformation bi; + bi.equipmentNumber = it.first; + bi.broadcastRequests = it.second; + tele.information.push_back(std::move(bi)); + } + + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(tele); + sendTelegram(&telegram); +} + + + + +void PrtCnvCentralThread::checkSend() +{ + + if (m_DoCleanup) return; + if (PrtCnvSocketThread::e_WORKING != m_State) return; + PrtCnvStoredCentralTelegram *handle = nullptr; + auto *centralTelegram = m_DbThread->getNextCentralTelegram(handle); + if (centralTelegram) + { + sendTelegram(centralTelegram, handle); + delete centralTelegram; + emit checkSendToCentral(); + } +} + + + + + +void PrtCnvCentralThread::handleAck(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + TrainingAreaBase::TetraIcd::Acknowledge ack(TrainingAreaBase::TetraIcd::Acknowledge::fromJson(a_telegram->jsonData())); + + m_DbThread->ackCentralTelegrams(ack.ackCounter); +} + + + + + + +void PrtCnvCentralThread::permanentStored(int32_t a_centralCounter) +{ + if (m_DoCleanup) return; + if (PrtCnvSocketThread::e_WORKING != m_State) return; + DEBUG_LOG(m_logger) << "got permanentStored a_centralCounter=" << a_centralCounter; + if (0 != a_centralCounter && a_centralCounter > m_ReceiveAckCounter) + { + m_ReceiveAckCounter = a_centralCounter; + sendAck(); + } +} + +void PrtCnvCentralThread::onTetraConnectionState(bool bConnected) +{ + TrainingAreaBase::TetraIcd::ProxyConnectionState connState; + connState.connectedToSystem = bConnected; + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(connState); + sendTelegram(&telegram); +} + +void PrtCnvCentralThread::onPlayerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind) +{ + TrainingAreaBase::TetraIcd::ParticipantLicenseChange lc; + lc.equipmentNumber = equipNo; + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unknown; + switch (kind) + { + case N_CoPrtCnv::E_LicensingKind::Success: + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Licensed; + break; + case N_CoPrtCnv::E_LicensingKind::Rejected: + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Rejected; + break; + case N_CoPrtCnv::E_LicensingKind::Unlicense: + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unlicense; + break; + } + Q_ASSERT(lc.licenseState != TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unknown); + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(lc); + sendTelegram(&telegram); +} + +void PrtCnvCentralThread::onAreaEffectSimulationDeactivated(int wirkfeldKennung) +{ + m_deactivatedAreaEffectSimulations.insert(wirkfeldKennung); + m_alreadyTriggeredMines.remove(wirkfeldKennung); +} + +void PrtCnvCentralThread::onAreaEffectSimulationActivated(int wirkfeldKennung) +{ + m_deactivatedAreaEffectSimulations.remove(wirkfeldKennung); +} + +void PrtCnvCentralThread::onRadioThreadInitDone() +{ + m_bRadioThreadInitDone = true; + if (!m_sendAckTimer->isActive()) + m_sendAckTimer->start(); +} + + + + + +bool PrtCnvCentralThread::handleSpecialTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + using namespace TrainingAreaBase::TetraIcd; + + switch (a_telegram->telegramId()) + { + case Constraints::id(): + { + ExerciseStateData tele(ExerciseStateData::fromJson(a_telegram->jsonData())); + switch(tele.exerciseState) + { + case ExerciseStateData::ExerciseState::Terminated: + { + INFO_LOG(m_logger) << "Got Betriebszustandsmeldung Uebung_Aufraeumen => disconnect, cleanup and reconnect"; + m_DbThread->setMachineState(1); + + permanentStored(a_telegram->counter()); + m_DoCleanup = true; + m_CentralStopped = false; + m_RadioStopped = false; + + m_sendAckTimer->stop(); + m_DbThread->waitUntilDbWritten(); + disconnectSocket(); + m_RadioThread->prepareCleanUp(); + emit stopRadio(); + m_reconnectTimer->start(); + break; + } + case ExerciseStateData::ExerciseState::Started: + m_DbThread->setPause(false); + m_RadioThread->sendEnvironmentTelegramTimerNow(); + break; + case ExerciseStateData::ExerciseState::Paused: + m_DbThread->setPause(true); + m_RadioThread->sendEnvironmentTelegramTimerNow(); + break; + default: + break; + } + return false; + } + case Constraints::id(): + + m_DbThread->centralCounterReadyForAck(a_telegram->counter()); + handleAnforderungStatistikBroadcastNachforderungen(); + return false; + + case Constraints::id(): + { + const ExerciseEquipmentAssignmentComplete tele(ExerciseEquipmentAssignmentComplete::fromJson(a_telegram->jsonData())); + m_RadioThread->exerciseEquipmentChanged(tele); + return false; + } + default: + break; + } + return true; +} + + +void PrtCnvCentralThread::connectSocket() +{ + const QString host = m_Config->getString(getName(), QStringLiteral("HostName"), QStringLiteral("EXCTDS01")); + if (host == QLatin1String("directConnection")) + { + m_bDirectConnection = true; + connected(); + return; + } + m_bDirectConnection = false; + + disconnectSocket(); + m_webSocket = new QWebSocket; + + connect(m_webSocket, &QWebSocket::stateChanged, + this, &PrtCnvCentralThread::stateChanged); + connect(m_webSocket, &QWebSocket::textMessageReceived, + this, &PrtCnvCentralThread::onTextMessageReceived); + connect(m_webSocket, &QWebSocket::connected, + this, &PrtCnvCentralThread::connected); + connect(m_webSocket, &QWebSocket::disconnected, + this, &PrtCnvCentralThread::disconnected); + + const uint16_t port = static_cast(m_Config->getInteger(getName(), QStringLiteral("Port"), 4934)); + const QUrl scmUrl(QStringLiteral("ws://%1:%2").arg(host).arg(port)); + + m_webSocket->open(scmUrl); + m_State = PrtCnvSocketThread::e_CONNECTING; +} + + +void PrtCnvCentralThread::disconnectSocket() +{ + m_State = PrtCnvSocketThread::e_INITIAL; + if (!m_webSocket) + return; + + m_State = PrtCnvSocketThread::e_DISCONNECTING; + m_webSocket->disconnect(this); + m_webSocket->close(); + m_webSocket->deleteLater(); + m_webSocket = nullptr; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvCentralThread.hpp b/TetraIF/PrtCnv/PrtCnvCentralThread.hpp new file mode 100644 index 000000000..c56dee7fa --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvCentralThread.hpp @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvSocketThread.hpp" +#include "PrtCnvDbThread.hpp" +#include + +namespace N_CoPrtCnv +{ + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + class PrtCnvRadioThread; + class PrtCnvThreadStarter; + + + class PrtCnvCentralThread : public PrtCnv::PrtCnvThread + { + Q_OBJECT + +private: + + + public: + + + ~PrtCnvCentralThread(); + + + + explicit PrtCnvCentralThread(PrtCnvThreadStarter* a_parent); + + + int32_t create(NGL::Settings *settings) override; + int32_t deinit() override; + + + int32_t destroy() override; + + + int32_t init() override; + + + int32_t start() override; + + + int32_t stop() override; + + + void onDirectTextMessageReceived(const QByteArray &baJson); + + signals: + + void directTextMessage(const QByteArray &baJson); + + + + void checkSendToCentral(); + + + void checkSendToRadio(); + + + void stopRadio(); + + + void cleanRadio(); + + + void startRadio(); + + protected: + + + QWebSocket *m_webSocket; + + + + int32_t m_SendCounter; + + public slots: + + + void checkSend(); + + + void radioStopped(); + + + void radioCleant(); + + + void permanentStored(int32_t a_centralCounter); + + + void onTetraConnectionState(bool bConnected); + + void onPlayerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind); + + protected slots: + + void onAreaEffectSimulationDeactivated(int wirkfeldKennung); + void onAreaEffectSimulationActivated(int wirkfeldKennung); + + + void onRadioThreadInitDone(); + + + + void connected(); + + + void disconnected(); + + + void timeoutTick(); + + + void timeoutAliveAndConnection(); + + void onTextMessageReceived(const QString &msg); + void stateChanged(QAbstractSocket::SocketState newState); + + protected: + + + void sendAck(); + + + void handleTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + bool checkAndUpdateReceiveCounter(const int32_t a_counter); + + + void sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram, + PrtCnvStoredCentralTelegram *a_handle); + + + void handleAnforderungStatistikBroadcastNachforderungen(); + + + void handleAck(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + void cleanAndReinit(); + + + + bool handleSpecialTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + + void sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + + void connectSocket(); + + + void disconnectSocket(); + + protected: + + + PrtCnvRadioThread *m_RadioThread; + + + bool m_RadioStopped; + + + bool m_CentralStopped; + + + int32_t m_LastSendCounter; + + + uint16_t m_VirtualTeilnehmerId; + + + + uint16_t m_maxEqID; + + + QTimer *m_aliveTimer; + + + QTimer *m_sendAckTimer; + + + QTimer *m_reconnectTimer; + + + + QAtomicInt m_DoCleanup; + PrtCnvDbThread *m_DbThread; + + PrtCnvTelegramLogThread *m_LogThread; + + PrtCnvInjectionThread *m_InjectionThread; + + + + int32_t m_ReceiveCounter; + + + int32_t m_ReceiveAckCounter; + + + + PrtCnvSocketThread::E_State m_State; + + + QSet m_deactivatedAreaEffectSimulations; + + + QHash> m_alreadyTriggeredMines; + + + bool m_bDirectConnection; + + bool m_bRadioThreadInitDone; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvDbThread.cpp b/TetraIF/PrtCnv/PrtCnvDbThread.cpp new file mode 100644 index 000000000..e66bcc171 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvDbThread.cpp @@ -0,0 +1,1647 @@ + + + + + + + + + + + + + +#include "PrtCnvDbThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvMember.hpp" +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvStoredCentralTelegram.hpp" +#include "PrtCnvStoredRadioTelegram.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace PrtCnv +{ + + + + +PrtCnvDbThread::PrtCnvDbThread(const QString &dbDriver, + const QString &dbHostName, + const QString &dbDatabaseName, + const QString &schemaName, + const QString &dbUserName, + const QString &dbPassword, + PrtCnv::PrtCnvThreadStarter *a_parent) + : PrtCnvThread(a_parent, "PrtCnvDbThread") + , m_BattleFieldOpStateMutex(QMutex::Recursive) + , m_MemberListByIdMutex(QMutex::Recursive) + , m_CentralListMutex(QMutex::Recursive) + , m_OldCentralAckCounter(0) + , m_RadioListMutex(QMutex::Recursive) + , m_SqlCmdListMutex(QMutex::Recursive) + , m_BroadcastMapMutex(QMutex::Recursive) + , m_DoClean(false) + , m_DoWaitUntilSqlWritten(false) + , m_DoStorePermanent(false) + , m_ResetCounter(0) + , m_BattleFieldOperatingState(0) + , m_EnvironmentTelegram(nullptr) + , m_DoProceedCleanup(false) + , m_OldCentralCounter(0) + , m_StorePermanentPending(0) + , m_NbrOfAttempts(5) + , m_dbDriver(dbDriver.isEmpty() ? QStringLiteral("QSQLITE") : dbDriver) + , m_dbHostName(dbHostName) + , m_dbDatabaseName(dbDatabaseName) + , m_dbSchemaName(schemaName) + , m_dbUserName(dbUserName) + , m_dbPassword(dbPassword) +{ + m_Name = QStringLiteral("Db"); +} + + +PrtCnvDbThread::~PrtCnvDbThread() +{ + closeDb(); + qDeleteAll(m_BroadcastList); + qDeleteAll(m_RadioList); + qDeleteAll(m_CentralList); + for (const auto &p : m_MemberListById) + delete p.second; +} + + + + + +static const int s_iCurrentDatabaseSchemeVersion = 1; +void PrtCnvDbThread::reinitDatabase() +{ + DBTransaction trans(m_db); + NSqlQuery q(m_db); + if (m_db.driverName() == QStringLiteral("QSQLITE")) + { + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(versionTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "version integer," + "date text," + "product text," + "change text)").arg(versionTableName())); + q.exec(QStringLiteral("INSERT INTO %1 (version, date, product, change) VALUES " + "(1, '2012-11-20', 'TetraInterface', 'Initial version table');").arg(versionTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(toCentralTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "tel_id INTEGER," + "counter INTEGER DEFAULT 0," + "data BLOB);").arg(toCentralTableName())); + q.exec(QStringLiteral("CREATE INDEX counterIndex ON %1(counter);").arg(toCentralTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(toRadioTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "tel_id INTEGER," + "counter INTEGER DEFAULT 0," + "broadcast_index INTEGER DEFAULT 0," + "reset_counter INTEGER DEFAULT 0," + "data BLOB);").arg(toRadioTableName())); + q.exec(QStringLiteral("CREATE INDEX bcindex ON %1(reset_counter, broadcast_index);").arg(toRadioTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(memberTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY," + "issi INTEGER," + "licensed INTEGER DEFAULT 0," + "claims INTEGER DEFAULT 0," + "exercise_id INTEGER" + ");").arg(memberTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(statusTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY," + "reset_counter INTEGER," + "ctas_operating_state INTEGER," + "machine_state INTEGER" + ");").arg(statusTableName())); + } + + q.exec(QStringLiteral("DELETE FROM %1 WHERE id = 1;").arg(statusTableName())); + q.exec(QStringLiteral("INSERT INTO %1 " + "(id, reset_counter, ctas_operating_state, machine_state) " + "VALUES (1, %2, %3, 0);") + .arg(statusTableName()).arg(int(m_ResetCounter)).arg(int(m_BattleFieldOperatingState))); + + q.exec(QStringLiteral("DELETE FROM %1 WHERE id = 0;").arg(memberTableName())); + + trans.commit(); +} + + + + +bool PrtCnvDbThread::createDatabase() +{ + closeDb(); + + m_db = QSqlDatabase::addDatabase(m_dbDriver, QStringLiteral("PrtCnv")); + if (m_dbDriver == QLatin1String("QSQLITE")) + { + QString path = m_Config->getString(getName(), QStringLiteral("DatabaseFileName"), QStringLiteral("telegrams.db")); + if (!QDir::isAbsolutePath(path)) + { + path = QCoreApplication::applicationDirPath() + QLatin1String("/../") + path; + QFileInfo fi(path); + QDir().mkpath(fi.absolutePath()); + } + m_db.setDatabaseName(path); + INFO_LOG(m_logger) << "Use db-file: " << path; + std::cout << "Use db-file: " << qPrintable(path) << std::endl; + } + else + { + m_db.setDatabaseName(m_dbDatabaseName); + m_db.setHostName(m_dbHostName); + m_db.setUserName(m_dbUserName); + m_db.setPassword(m_dbPassword); + } + + + DEBUG_LOG(m_logger) << "Connection name: " << m_db.connectionName(); + + if (!m_db.open()) + { + FATAL_LOG(m_logger) << "Error while opening database: " << m_db.lastError().text(); + return false; + } + + if (m_DoCleanDb) + { + NOTICE_LOG(m_logger) << "Permanent data will be erased..."; + reinitDatabase(); + } + else + { + NOTICE_LOG(m_logger) << "Check database..."; + NSqlQuery q(m_db); + if (m_db.driverName() == QStringLiteral("QSQLITE")) + { + if (!q.execAndFetch(QStringLiteral("SELECT MAX(version) FROM %1;").arg(versionTableName()))) + { + ERROR_LOG(m_logger) << "Could not read version table - reinitialize database"; + reinitDatabase(); + } + else + { + + int iVersion = q.value(0).toInt(); + if (iVersion != s_iCurrentDatabaseSchemeVersion) + { + ERROR_LOG(m_logger) << "Database version does not match (is: " + << iVersion << " expected: " << s_iCurrentDatabaseSchemeVersion + << " - reinitialize database"; + reinitDatabase(); + } + } + } + + if (!q.exec(QStringLiteral("SELECT * from %1 LIMIT 1;").arg(statusTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table Status"; + std::cout << "Failure while checking DB-table Status. Start PrtCnv with --cleandb" << std::endl; + return false; + } + if (!q.exec(QStringLiteral("SELECT * from %1 LIMIT 1;").arg(toCentralTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table ToCentral"; + std::cout << "Failure while checking DB-table ToCentral. Start PrtCnv with --cleandb" << std::endl; + return false; + } + if (!q.exec(QStringLiteral("SELECT * from %1 LIMIT 1;").arg(toRadioTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table ToRadio"; + std::cout << "Failure while checking DB-table ToRadio. Start PrtCnv with --cleandb" << std::endl; + return false; + } + + if (!q.exec(QStringLiteral("SELECT issi FROM %1 WHERE id=0;").arg(memberTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table Member"; + std::cout << "Failure while checking DB-table Member. Start PrtCnv with --cleandb" << std::endl; + return false; + } + + const int broadcastIssi = m_Config->getInteger(QStringLiteral("Radio"), QStringLiteral("BroadcastISSI"), 5000); + if (q.next()) + { + const int dbBroadcastIssi = q.value(0).toInt(); + if (broadcastIssi != dbBroadcastIssi) + { + WARNING_LOG(m_logger) << "Broadcast-ISSI mismatch (DB: " << dbBroadcastIssi << "; Configfile: " << broadcastIssi << ")"; + q.exec(QStringLiteral("DELETE FROM %1 WHERE id = 0;").arg(memberTableName())); + licenseMember(addMember(0, broadcastIssi)); + } + } + else + { + licenseMember(addMember(0, broadcastIssi)); + } + + INFO_LOG(m_logger) << "Restore permanent data (after crash)..."; + m_DoStorePermanent = false; + + INFO_LOG(m_logger) << "restoreStatus"; + + if (!q.execAndFetch(QStringLiteral("SELECT reset_counter, ctas_operating_state, machine_state FROM %1;").arg(statusTableName()))) + { + ERROR_LOG(m_logger) << "Error reading Status from DB"; + std::cout << "Error reading Status from DB. Start PrtCnv with --cleandb" << std::endl; + return false; + } + m_ResetCounter = q.value(0).toInt(); + INFO_LOG(m_logger) << "Restore resetCounter=" << (int)m_ResetCounter; + + if (1 == q.value(2).toInt()) + { + INFO_LOG(m_logger) << "Crash happenend while cleaning-DB"; + + m_DoStorePermanent = true; + m_DoProceedCleanup = true; + return true; + } + m_BattleFieldOperatingState = q.value(1).toInt(); + INFO_LOG(m_logger) << "Restore battleFieldOperatingState=" << (int)m_BattleFieldOperatingState; + + + if (!q.exec(QStringLiteral("SELECT id, issi, licensed, claims, exercise_id FROM %1;").arg(memberTableName()))) + { + ERROR_LOG(m_logger) << "Error reading Member from DB"; + std::cout << "Error reading Member from DB. Start PrtCnv with --cleandb" << std::endl; + return false; + } + + while (q.next()) + { + int id = q.value(0).toInt(); + int issi = q.value(1).toInt(); + bool licensed = q.value(2).toBool(); + int claims = q.value(3).toInt(); + int exerciseId = q.value(4).toInt(); + INFO_LOG(m_logger) << "Restore member: id=" << id << " issi=" << issi << " licensed=" << licensed + << " claims=" << claims << " exerciseId " << exerciseId; + PrtCnvMember *member = addMember(id, issi); + if (member) + { + member->m_ClaimCount = claims; + member->m_loggedInExerciseId = exerciseId; + if (licensed) + { + bool ok = licenseMember(member); + if (ok) + { + + emit playerLicencedChanged(member->m_Id, N_CoPrtCnv::E_LicensingKind::Success); + } + } + } + } + + + + + + if (!q.exec(QStringLiteral("SELECT id, counter, broadcast_index, data " + "FROM %1 ORDER BY reset_counter, broadcast_index, id;").arg(toRadioTableName()))) + { + ERROR_LOG(m_logger) << "Error reading from ToRadio table"; + std::cout << "Error reading from ToRadio table. Start PrtCnv with --cleandb" << std::endl; + return false; + } + while (q.next()) + { + const qint64 id = q.value(0).toLongLong(); + const int counter = q.value(1).toInt(); + const int bcIndex = q.value(2).toInt(); + const QByteArray telData(q.value(3).toByteArray()); + + auto radioTelegram(std::make_shared(telData)); + PrtCnvStoredRadioTelegram *storedTelegram = + new PrtCnvStoredRadioTelegram(radioTelegram); + storedTelegram->m_Id = id; + + + if (0 == counter) + { + + m_RadioList.push_back(storedTelegram); + INFO_LOG(m_logger) << "Restore unsent radiotelegram: id=" << storedTelegram->m_Id + << " telId=" << storedTelegram->m_RadioTelegram->getTelID() + << " BC=" << storedTelegram->m_RadioTelegram->getBroadcastIndex() + << " counter=" << counter; + } + else + { + + if (bcIndex == 0) + { + if (radioTelegram->getTelID() == GEF_UMGEBUNGS_MELDUNG2) + m_RadioList.push_back(storedTelegram); + else + delete storedTelegram; + } + else + { + + radioTelegram->setBroadcastIndex(bcIndex); + bool dummy; + radioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + radioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + radioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + m_BroadcastList.push_back(storedTelegram); + INFO_LOG(m_logger) << "Restore broadcast-radiotelegram: id=" + << storedTelegram->m_Id << " telId=" << storedTelegram->m_RadioTelegram->getTelID() + << " BC=" << storedTelegram->m_RadioTelegram->getBroadcastIndex() + << " counter=" << counter; + } + } + } + + + q.exec(QStringLiteral("UPDATE %1 SET counter=0;").arg(toCentralTableName())); + if (!q.exec(QStringLiteral("SELECT id, data FROM %1 ORDER BY id;").arg(toCentralTableName()))) + { + ERROR_LOG(m_logger) << "Error reading from ToCentral table"; + std::cout << "Error reading from ToCentral table. Start PrtCnv with --cleandb" << std::endl; + return false; + } + while (q.next()) + { + const qint64 id = q.value(0).toLongLong(); + const QByteArray telData(q.value(1).toByteArray()); + + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(telData); + std::shared_ptr + centralTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(&radioTelegram)); + if (centralTelegram) + { + PrtCnvStoredCentralTelegram *storedTelegram = new PrtCnvStoredCentralTelegram(centralTelegram, nullptr); + storedTelegram->m_Id = id; + m_CentralList.push_back(storedTelegram); + INFO_LOG(m_logger) << "Restore unsent or unacked centraltelegram: id=" << storedTelegram->m_Id + << " telId=" << storedTelegram->m_CentralTelegram->telegramId() + << " counter=" << storedTelegram->m_WriteCounter + << " size=" << telData.size(); + + } + else + ERROR_LOG(m_logger) << "Internal error: conversion of telegram with telId=" << radioTelegram.getTelID() << " from radio to central failed"; + } + + if (m_db.driverName() == QLatin1String("QSQLITE")) + { + q.exec(QStringLiteral("VACUUM;")); + q.exec(QStringLiteral("PRAGMA journal_mode=WAL;")); + + + q.exec(QStringLiteral("PRAGMA synchronous=NORMAL;")); + } + } + m_DoStorePermanent = true; + + return true; +} + + + + +int32_t PrtCnvDbThread::create(NGL::Settings *settings) +{ + INFO_LOG(m_logger) << "create"; + PrtCnvThread::create(settings); + m_NbrOfAttempts = m_Config->getInteger(QStringLiteral("Central"), QStringLiteral("NbrOfAttempts"), 5); + if (!createDatabase()) + { + ERROR_LOG(m_logger) << "Trying to create clean database after error"; + m_DoCleanDb = true; + if (!createDatabase()) + exit(-2); + } + + connect(this, &PrtCnvDbThread::doStorePermanent, this, &PrtCnvDbThread::storePermanent, Qt::QueuedConnection); + connect(this, &PrtCnvDbThread::doClean, this, &PrtCnvDbThread::clean, Qt::QueuedConnection); + + PrtCnvCentralThread *centralThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Central)); + connect(this, &PrtCnvDbThread::permanentStored, centralThread, &PrtCnvCentralThread::permanentStored, Qt::QueuedConnection); + + return 0; +} + + + + + +int32_t PrtCnvDbThread::init() +{ + INFO_LOG(m_logger) << "init"; + PrtCnvThread::init(); + m_CentralAckCounter = 0; + m_OldCentralAckCounter = 0; + m_OldCentralCounter = 0; + m_DoClean = false; + m_DoWaitUntilSqlWritten = false; + + return 0; +} + + + + + +int32_t PrtCnvDbThread::start() +{ + INFO_LOG(m_logger) << "start"; + PrtCnvThread::start(); + + return 0; +} + + + + + +int32_t PrtCnvDbThread::stop() +{ + PrtCnvThread::stop(); + m_db.close(); + m_db = QSqlDatabase(); + + return 0; +} + + + + + + + + + + + + +void PrtCnvDbThread::storeCentralTelegram(const std::shared_ptr &a_centralTelegram, + const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + PrtCnvStoredCentralTelegram *storedTelegram = + new PrtCnvStoredCentralTelegram(a_centralTelegram, + std::make_shared(a_radioTelegram)); + QMutexLocker l(&m_CentralListMutex); + m_CentralList.push_back(storedTelegram); + + + sendStorePermanentSignal(); +} + + + + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *PrtCnvDbThread::getNextCentralTelegram(PrtCnvStoredCentralTelegram *&a_handle) +{ + + QMutexLocker l(&m_CentralListMutex); + std::vector::const_iterator iter = m_CentralList.begin(); + std::vector::const_iterator end = m_CentralList.end(); + for (; iter != end; ++iter) + { + PrtCnvStoredCentralTelegram *storedTelegram = *iter; + if (!storedTelegram || !storedTelegram->m_CentralTelegram) + continue; + if (0 == storedTelegram->m_WriteCounter || storedTelegram->m_DoResend) + { + const auto &telegram = storedTelegram->m_CentralTelegram; + storedTelegram->m_DoResend = false; + a_handle = storedTelegram; + DEBUG_LOG(m_logger) << "Next telegram to send to central: id=" << storedTelegram->m_Id + << " a_telId=" << telegram->telegramId(); + + return new N_CoPrtCnv::CoPrtCnvCentralTelegram(*telegram); + } + } + return nullptr; +} + + + + + +void PrtCnvDbThread::centralTelegramSent(const int32_t a_counter, PrtCnvStoredCentralTelegram *a_handle) +{ + + QMutexLocker l(&m_CentralListMutex); + a_handle->m_WriteCounter = a_counter; + a_handle->m_WriteCounterChanged = true; + + sendStorePermanentSignal(); +} + + + + + + +void PrtCnvDbThread::ackCentralTelegrams(int32_t a_counter) +{ + + m_CentralAckCounter = a_counter; + + sendStorePermanentSignal(); +} + + + + + + + + + + +void PrtCnvDbThread::centralTelegramCouldNotBeSent(PrtCnvStoredCentralTelegram *a_handle) +{ + if (a_handle) + { + + QMutexLocker l(&m_CentralListMutex); + if (++(a_handle->m_Attempts) >= 5) + { + WARNING_LOG(m_logger) << "Delete unsendable Central-Telegram with id=" << a_handle->m_Id + << " telId=" << a_handle->m_CentralTelegram->telegramId() + << " rc=" << a_handle->m_CentralTelegram->counter() << " wc=" << a_handle->m_WriteCounter; + a_handle->m_DoDelete = true; + + } + l.unlock(); + + waitUntilDbWritten(); + } +} + + + + + + + + +void PrtCnvDbThread::storeRadioTelegram(const std::shared_ptr &a_telegram, + const int32_t a_readCounter) +{ + PrtCnvStoredRadioTelegram *storedTelegram = new PrtCnvStoredRadioTelegram(a_telegram); + storedTelegram->m_ReadCounter = a_readCounter; + { + QMutexLocker l(&m_RadioListMutex); + m_RadioList.push_back(storedTelegram); + } + if (a_telegram) + DEBUG_LOG(m_logger) << "Store Radio-Telegram with telId=" << a_telegram->getTelID() + << " rc=" << a_readCounter + << " wc=" << int(storedTelegram->m_WriteCounter); + + if (m_DoStorePermanent) + sendStorePermanentSignal(); +} + + + + + + + + +void PrtCnvDbThread::centralCounterReadyForAck(const int32_t a_centralCounter) +{ + storeRadioTelegram(nullptr, a_centralCounter); + DEBUG_LOG(m_logger) << "No Radio-Telegram to store, but rc=" << a_centralCounter << " must be acked"; +} + + + + + + + +std::shared_ptr PrtCnvDbThread::getNextBroadcastTelegram() +{ + QMutexLocker l(&m_BroadcastMapMutex); + if (m_BroadcastList.empty()) + return nullptr; + + PrtCnvStoredRadioTelegram *storedRadioTelegram = m_BroadcastList.front(); + std::shared_ptr radioTelegram; + + if (storedRadioTelegram->m_Id != 0 && !storedRadioTelegram->m_WriteCounterChanged) + { + radioTelegram = storedRadioTelegram->m_RadioTelegram; + m_BroadcastList.pop_front(); + delete storedRadioTelegram; + } + + return radioTelegram; +} + + + + + + + +std::shared_ptr PrtCnvDbThread::getNextRadioTelegram(PrtCnvStoredRadioTelegram *&a_handle) +{ + + std::shared_ptr telegram; + uint8_t priority = 255; + + QMutexLocker l(&m_RadioListMutex); + for (PrtCnvStoredRadioTelegram *storedTelegram: m_RadioList) + { + const auto &radioTelegram = storedTelegram->m_RadioTelegram; + if (radioTelegram) + { + if (!storedTelegram->m_IsSent) + { + + uint8_t newPriority = radioTelegram->getPriority(); + if (newPriority < priority) + { + priority = newPriority; + telegram = radioTelegram; + a_handle = storedTelegram; + } + } + } + } + return telegram; +} + + + + +void PrtCnvDbThread::radioTelegramSent(const uint32_t a_sendCounter, PrtCnvStoredRadioTelegram *a_handle, const uint32_t a_broadcastIndex) +{ + QMutexLocker l(&m_RadioListMutex); + + if (a_broadcastIndex) + { + DEBUG_LOG(m_logger) << "request update radio telegramm in db - sc: " << a_sendCounter + << " telId: " << a_handle->m_RadioTelegram->getTelID() + << " BC: " << a_broadcastIndex; + } + + + a_handle->m_WriteCounter = a_sendCounter; + a_handle->m_WriteCounterChanged = true; + a_handle->m_IsSent = true; + if (a_broadcastIndex != 0) + a_handle->m_BroadcastIndex = a_broadcastIndex; + + if (a_handle->m_BroadcastIndex != 0) + { + + bool dummy; + a_handle->m_RadioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + DEBUG_LOG(m_logger) << "Move Radio-Telegram with telId=" << a_handle->m_RadioTelegram->getTelID() + << " and BC=" << a_handle->m_RadioTelegram->getBroadcastIndex() + << " to BC-List of DB"; + + + + + + QMutexLocker l2(&m_BroadcastMapMutex); + m_BroadcastList.push_back(a_handle); + } + else + { + + if (a_handle->m_RadioTelegram->isNormalTelegram() && (a_handle->m_RadioTelegram->getTelID() == GEF_UMGEBUNGS_MELDUNG2)) + { + + if (m_EnvironmentTelegram) + m_EnvironmentTelegram->m_DoDelete = true; + m_EnvironmentTelegram = a_handle; + } + else + a_handle->m_DoDelete = true; + } + + sendStorePermanentSignal(); +} + + +void PrtCnvDbThread::deleteTelegramsFromDbById(const QString &table) +{ + if (m_telegramsToDelete.empty()) + return; + + QStringList sl; + sl.reserve(m_telegramsToDelete.size()); + for (const int64_t telId : m_telegramsToDelete) + sl += QString::number(telId); + + NSqlQuery q(m_db); + q.exec(QStringLiteral("DELETE FROM %1 WHERE id IN (%2);").arg(table, sl.join(QLatin1Char(',')))); + + + m_telegramsToDelete.clear(); +} + +void PrtCnvDbThread::updateTelegramsBroadcast(const QString &table) +{ + if (m_telegramsToUpdateBC.empty()) + return; + + NSqlQuery q(m_db); + q.prepare(QStringLiteral("UPDATE %1 SET broadcast_index = :broadcast_index WHERE id = :id").arg(table)); + for (const auto &p : m_telegramsToUpdateBC) + { + const qint64 telId = p.first; + const qint32 bcIndex = p.second; + + q.bindValue(QStringLiteral(":broadcast_index"), bcIndex); + q.bindValue(QStringLiteral(":id"), telId); + q.exec(); + + DEBUG_LOG(m_logger) << "Update broadcastindex for id: " << telId << " to BC: " << bcIndex; + } + + + m_telegramsToUpdateBC.clear(); +} + +void PrtCnvDbThread::updateTelegramsWriteCounter(const QString &table) +{ + if (m_telegramsToUpdateCounter.empty()) + return; + + NSqlQuery q(m_db); + q.prepare(QStringLiteral("UPDATE %1 SET counter = :counter WHERE id = :id").arg(table)); + for (const auto &p : m_telegramsToUpdateCounter) + { + const qint64 telId = p.first; + const qint32 writeCounter = p.second; + + q.bindValue(QStringLiteral(":counter"), writeCounter); + q.bindValue(QStringLiteral(":id"), telId); + q.exec(); + + DEBUG_LOG(m_logger) << "Update WriteCounter for id: " << telId << " to wc: " << writeCounter; + } + + + m_telegramsToUpdateCounter.clear(); +} + + + +void PrtCnvDbThread::storeCentralTelegrams() +{ + QMutexLocker l(&m_CentralListMutex); + + if (m_CentralList.empty()) + return; + + + int iEmptyCount = 0; + for (auto &storedCentralTelegram : m_CentralList) + { + if (!storedCentralTelegram) + { + ++iEmptyCount; + continue; + } + const auto centralTelegram = storedCentralTelegram->m_CentralTelegram; + + if (0 == storedCentralTelegram->m_Id) + { + + m_telegramsToInsert.emplace_back(std::make_pair(storedCentralTelegram, 0)); + + DEBUG_LOG(m_logger) << "Permanent Central-Telegram with id=" << storedCentralTelegram->m_Id + << " data=" << centralTelegram->data() + << " wc=" << storedCentralTelegram->m_WriteCounter; + } + else + { + + + const int centralAckCnt = m_CentralAckCounter; + if (storedCentralTelegram->m_WriteCounterChanged) + { + m_telegramsToUpdateCounter.emplace_back(std::make_pair(storedCentralTelegram->m_Id, + storedCentralTelegram->m_WriteCounter)); + storedCentralTelegram->m_WriteCounterChanged = false; + + DEBUG_LOG(m_logger) << "Update Central-Telegram with id=" << storedCentralTelegram->m_Id + << " data=" << centralTelegram->data() + << " wc=" << storedCentralTelegram->m_WriteCounter; + } + + + else if ((storedCentralTelegram->m_WriteCounter > 0 && + storedCentralTelegram->m_WriteCounter <= centralAckCnt) || + storedCentralTelegram->m_DoDelete) + { + DEBUG_LOG(m_logger) << "Delete Central-Telegram with id=" << storedCentralTelegram->m_Id + << " data=" << storedCentralTelegram->m_CentralTelegram->data() + << " wc=" << storedCentralTelegram->m_WriteCounter; + + + if (storedCentralTelegram->m_WriteCounter > centralAckCnt) + m_telegramsToDelete.push_back(storedCentralTelegram->m_Id); + + delete storedCentralTelegram; + storedCentralTelegram = nullptr; + } + } + } + + if (iEmptyCount > 50) + { + const auto isNull = [](const PrtCnvStoredCentralTelegram *t) { return t == nullptr; }; + m_CentralList.erase(std::remove_if(m_CentralList.begin(), m_CentralList.end(), isNull), + m_CentralList.end()); + } + + l.unlock(); + + + + if (!m_telegramsToInsert.empty()) + { + l.relock(); + NSqlQuery q(m_db); + q.prepare(QStringLiteral("INSERT INTO %1 (tel_id, counter, data)" + "VALUES(:tel_id, :counter, :data);").arg(toCentralTableName())); + + + + + for (const auto &p : m_telegramsToInsert) + { + PrtCnvStoredCentralTelegram *storedCentralTelegram = p.first; + + storedCentralTelegram->m_WriteCounterChanged = false; + q.bindValue(QStringLiteral(":tel_id"), storedCentralTelegram->m_CentralTelegram->telegramId()); + q.bindValue(QStringLiteral(":counter"), storedCentralTelegram->m_WriteCounter); + q.bindValue(QStringLiteral(":data"), storedCentralTelegram->m_RadioTelegram->data()); + q.exec(); + storedCentralTelegram->m_Id = q.lastInsertId().toInt(); + } + l.unlock(); + + m_telegramsToInsert.clear(); + } + + + + updateTelegramsWriteCounter(toCentralTableName()); + + + + + + + const unsigned int centralAckCnt = static_cast(m_CentralAckCounter); + if (centralAckCnt > m_OldCentralAckCounter) + { + m_OldCentralAckCounter = centralAckCnt; + + + DEBUG_LOG(m_logger) << "Central delete all counter <= " << m_OldCentralAckCounter; + + NSqlQuery q(m_db); + q.exec(QStringLiteral("DELETE FROM %1 WHERE counter > 0 AND counter <= %2;").arg(toCentralTableName()).arg(m_OldCentralAckCounter)); + } + + + deleteTelegramsFromDbById(toCentralTableName()); +} + +int32_t PrtCnvDbThread::storeRadioTelegrams() +{ + QMutexLocker l(&m_RadioListMutex); + + if (m_RadioList.empty()) + return 0; + + + int32_t centralCounter = 0; + + NSqlQuery q(m_db); + q.prepare(QStringLiteral("INSERT INTO %1 (tel_id, counter, broadcast_index, reset_counter, data) " + "VALUES (:tel_id, :counter, :broadcast_index, :reset_counter, :data);").arg(toRadioTableName())); + + + std::list::iterator radioIter = m_RadioList.begin(); + while (radioIter != m_RadioList.end()) + { + bool doDeleteThisItem = false; + PrtCnvStoredRadioTelegram *storedRadioTelegram = *radioIter; + const auto &radioTelegram = storedRadioTelegram->m_RadioTelegram; + + if (radioTelegram) + { + DEBUG_LOG(m_logger) << "Handling Radio-Telegram with id=" << storedRadioTelegram->m_Id + << " TelID: " << radioTelegram->getTelID() + << " rc: " << int(radioTelegram->zaehler()) + << " BC: " << storedRadioTelegram->m_BroadcastIndex + << " wc: " << int(storedRadioTelegram->m_WriteCounter); + + + + if (0 == storedRadioTelegram->m_Id) + { + if (storedRadioTelegram->m_ReadCounter > centralCounter) + centralCounter = storedRadioTelegram->m_ReadCounter; + + storedRadioTelegram->m_WriteCounterChanged = false; + q.bindValue(QStringLiteral(":tel_id"), radioTelegram->getTelID()); + q.bindValue(QStringLiteral(":counter"), storedRadioTelegram->m_WriteCounter); + q.bindValue(QStringLiteral(":broadcast_index"), storedRadioTelegram->m_BroadcastIndex); + q.bindValue(QStringLiteral(":reset_counter"), int(m_ResetCounter)); + q.bindValue(QStringLiteral(":data"), radioTelegram->data()); + q.exec(); + storedRadioTelegram->m_Id = q.lastInsertId().toInt(); + + DEBUG_LOG(m_logger) << "Stored Telegramm in DB, id: " << storedRadioTelegram->m_Id; + + + + + + + if (storedRadioTelegram->m_RadioTelegram->isMovedToBroadcastList()) + { + dumpTelegram(m_logger, + radioTelegram->getBroadcastCounter(), + storedRadioTelegram->m_RadioTelegram.get()); + DEBUG_LOG(m_logger) << "Removed Telegramm from radioList (place 1), id: " << storedRadioTelegram->m_Id; + doDeleteThisItem = true; + } + } + else + { + + + + + if (storedRadioTelegram->m_DoDelete) + { + DEBUG_LOG(m_logger) << "Delete Telegramm from DB, id: " << storedRadioTelegram->m_Id; + m_telegramsToDelete.push_back(storedRadioTelegram->m_Id); + + delete storedRadioTelegram; + doDeleteThisItem = true; + } + + + else if (storedRadioTelegram->m_WriteCounterChanged) + { + m_telegramsToUpdateCounter.emplace_back(std::make_pair(storedRadioTelegram->m_Id, + storedRadioTelegram->m_WriteCounter)); + if (storedRadioTelegram->m_BroadcastIndex) + m_telegramsToUpdateBC.emplace_back(std::make_pair(storedRadioTelegram->m_Id, + storedRadioTelegram->m_BroadcastIndex)); + storedRadioTelegram->m_WriteCounterChanged = false; + + DEBUG_LOG(m_logger) << "Update Write counter in DB, id: " << storedRadioTelegram->m_Id + << " New wc: " << int(storedRadioTelegram->m_WriteCounter) + << " new bc: " << storedRadioTelegram->m_BroadcastIndex; + + if (storedRadioTelegram->m_RadioTelegram->isMovedToBroadcastList()) + { + dumpTelegram(m_logger, + storedRadioTelegram->m_BroadcastIndex, + storedRadioTelegram->m_RadioTelegram.get()); + DEBUG_LOG(m_logger) << "Removed Telegramm from radioList (place 2), id: " << storedRadioTelegram->m_Id; + doDeleteThisItem = true; + } + } + } + } + else + { + + if (storedRadioTelegram->m_ReadCounter > centralCounter) + centralCounter = storedRadioTelegram->m_ReadCounter; + delete storedRadioTelegram; + doDeleteThisItem = true; + } + + if (doDeleteThisItem) + radioIter = m_RadioList.erase(radioIter); + else + ++radioIter; + } + l.unlock(); + + + static const QString &table = toRadioTableName(); + updateTelegramsWriteCounter(table); + + + + updateTelegramsBroadcast(table); + + + deleteTelegramsFromDbById(table); + + return centralCounter; +} + +void PrtCnvDbThread::handleSqlCommandList() +{ + + std::vector sqlCommandList; + { + QMutexLocker l(&m_SqlCmdListMutex); + std::swap(m_SqlCommandList, sqlCommandList); + } + + if (sqlCommandList.empty()) + return; + NSqlQuery q(m_db); + for (const QString &sql : sqlCommandList) + { + DEBUG_LOG(m_logger) << "execute sql=" << sql; + q.exec(sql); + } +} + + + + + +void PrtCnvDbThread::storePermanent() +{ + m_StorePermanentPending = 0; + + TRACE_LOG(m_logger) << "storePermanent m_DoClean=" << m_DoClean << " m_DoWaitUntilSqlWritten=" << m_DoWaitUntilSqlWritten; + if (m_DoClean) + { + m_DoWaitUntilSqlWritten = false; + return; + } + + + + DBTransaction trans(m_db); + + + + storeCentralTelegrams(); + + + + const int32_t centralCounter = storeRadioTelegrams(); + + + + handleSqlCommandList(); + + + trans.commit(); + + + if (0 != centralCounter && centralCounter != m_OldCentralCounter) + { + m_OldCentralCounter = centralCounter; + emit permanentStored(centralCounter); + } + m_DoWaitUntilSqlWritten = false; + +} + + + + + + + + +void PrtCnvDbThread::addSqlCommand(const QString &sql) +{ + QMutexLocker l(&m_SqlCmdListMutex); + m_SqlCommandList.push_back(sql); + + sendStorePermanentSignal(); +} + + + + + + +void PrtCnvDbThread::cleanAndInit() +{ + + m_DoClean = true; + emit doClean(); + + while (m_DoClean) + QThread::sleep(1); + m_DoProceedCleanup = false; +} + + + + + +void PrtCnvDbThread::clean() +{ + NSqlQuery q(m_db); + INFO_LOG(m_logger) << "Delete CentralList"; + { + QMutexLocker l(&m_CentralListMutex); + for (PrtCnvStoredCentralTelegram *t : m_CentralList) + delete t; + m_CentralList.clear(); + q.exec(QStringLiteral("DELETE FROM %1;").arg(toCentralTableName())); + } + m_OldCentralCounter = 0; + + INFO_LOG(m_logger) << "Delete RadioList"; + m_EnvironmentTelegram = nullptr; + { + QMutexLocker l(&m_RadioListMutex); + for (PrtCnvStoredRadioTelegram *t : m_RadioList) + delete t; + m_RadioList.clear(); + q.exec(QStringLiteral("DELETE FROM %1;").arg(toRadioTableName())); + } + + INFO_LOG(m_logger) << "Delete BroadcastList"; + { + QMutexLocker l(&m_BroadcastMapMutex); + for (PrtCnvStoredRadioTelegram *t : m_BroadcastList) + delete t; + m_BroadcastList.clear(); + } + + + + { + QMutexLocker l(&m_SqlCmdListMutex); + m_MemberListByISSI.clear(); + { + QMutexLocker l2(&m_MemberListByIdMutex); + for (const auto &p : m_MemberListById) + delete p.second; + m_MemberListById.clear(); + } + INFO_LOG(m_logger) << "Delete SqlList"; + m_SqlCommandList.clear(); + q.exec(QStringLiteral("DELETE FROM %1;").arg(memberTableName())); + } + + + licenseMember(addMember(0, m_Config->getInteger(QStringLiteral("Radio"), QStringLiteral("BroadcastISSI"), 5000))); + + m_DoClean = false; +} + + + + + + + + +bool PrtCnvDbThread::resendCentralTelegrams(const int32_t a_lastSendCounter) +{ + const int centralAckCnt = m_CentralAckCounter; + if (a_lastSendCounter > centralAckCnt) + { + bool warnOnce = true; + QMutexLocker l(&m_CentralListMutex); + int iCount = 0; + std::vector::const_iterator iter = m_CentralList.begin(); + std::vector::const_iterator end = m_CentralList.end(); + for (; iter != end && iCount < 50; ++iter) + { + PrtCnvStoredCentralTelegram *storedTelegram = *iter; + if (!storedTelegram) + continue; + ++iCount; + if (storedTelegram->m_WriteCounter > centralAckCnt) + { + if (warnOnce) + { + WARNING_LOG(m_logger) << "Resend central-telegrams from wc=" << a_lastSendCounter + << " centralAckCounter=" << centralAckCnt; + warnOnce = false; + } + INFO_LOG(m_logger) << "Resend central-telegram with telId=" + << storedTelegram->m_CentralTelegram->telegramId() + << " wc=" << storedTelegram->m_WriteCounter; + storedTelegram->m_DoResend = true; + } + } + return true; + } + return false; +} + + + + + + + + +void PrtCnvDbThread::prepareCentralTelegramsForReconnection() +{ + INFO_LOG(m_logger) << "m_CentralAckCounter=" << m_CentralAckCounter; + waitUntilDbWritten(); + + INFO_LOG(m_logger) << "start"; + m_CentralAckCounter = 0; + m_OldCentralAckCounter = 0; + m_OldCentralCounter = 0; + QMutexLocker l(&m_CentralListMutex); + for (PrtCnvStoredCentralTelegram *storedTelegram : m_CentralList) + { + if (!storedTelegram) + continue; + if (storedTelegram->m_WriteCounter != 0) + { + INFO_LOG(m_logger) << "***Prepare central-telegram with id=" << storedTelegram->m_Id + << " telId=" << storedTelegram->m_CentralTelegram->telegramId() + << " wc=" << storedTelegram->m_WriteCounter << " wcChg=" + << storedTelegram->m_WriteCounterChanged + << " for resend after reconnection"; + storedTelegram->m_WriteCounter = 0; + storedTelegram->m_WriteCounterChanged = false; + storedTelegram->m_DoResend = false; + } + } + INFO_LOG(m_logger) << "Ready for reconnection"; +} + + + + + +void PrtCnvDbThread::waitUntilDbWritten() +{ + m_DoWaitUntilSqlWritten = true; + emit doStorePermanent(); + while (m_DoWaitUntilSqlWritten) + QThread::usleep(10000); + + + m_DoWaitUntilSqlWritten = true; + emit doStorePermanent(); + while (m_DoWaitUntilSqlWritten) + QThread::usleep(10000); +} + + + + + + + +PrtCnv::PrtCnvMember *PrtCnvDbThread::addMember(const int a_identity, const int a_ISSI) +{ + PrtCnvMember *newMember = new PrtCnvMember(a_identity, a_ISSI); + { + QMutexLocker lSql(&m_SqlCmdListMutex); + QMutexLocker lId(&m_MemberListByIdMutex); + m_MemberListById.insert(std::make_pair(a_identity, newMember)); + m_MemberListByISSI.insert(std::make_pair(a_ISSI, newMember)); + } + + DEBUG_LOG(m_logger) << "Adding member with eqId " << a_identity + << " and issi " << a_ISSI + << ", store in db: " << m_DoStorePermanent; + + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("INSERT INTO %1 (id, issi) VALUES(%2, %3)") + .arg(memberTableName()).arg(newMember->m_Id).arg(newMember->m_ISSI)); + + return newMember; +} + + + + + +void PrtCnvDbThread::removeMember(PrtCnv::PrtCnvMember *a_member) +{ + { + QMutexLocker lSql(&m_SqlCmdListMutex); + QMutexLocker lId(&m_MemberListByIdMutex); + auto iterId = m_MemberListById.find(a_member->m_Id); + if (iterId != m_MemberListById.end()) + m_MemberListById.erase(iterId); + else + ERROR_LOG(m_logger) << "Internal error: did not find the member by ID"; + auto iterIssi = m_MemberListByISSI.find(a_member->m_ISSI); + if (iterIssi != m_MemberListByISSI.end()) + m_MemberListByISSI.erase(iterIssi); + else + ERROR_LOG(m_logger) << "Internal error: did not find the member by ISSI"; + } + + DEBUG_LOG(m_logger) << "Removing member with eqId " << a_member->m_Id + << " and issi " << a_member->m_ISSI + << ", store in db: " << m_DoStorePermanent; + + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("DELETE FROM %1 WHERE id = %2 OR issi = %3") + .arg(memberTableName()).arg(a_member->m_Id).arg(a_member->m_ISSI)); + + delete a_member; +} + + + + + +bool PrtCnvDbThread::licenseMember(PrtCnvMember *a_member, const bool a_doLicense) +{ + if (!a_member) + return false; + a_member->m_Licensed = a_doLicense; + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET licensed = %2 WHERE id = %3") + .arg(memberTableName()).arg(a_doLicense ? 1 : 0).arg(a_member->m_Id)); + return true; +} + +void PrtCnvDbThread::updateExerciseIdForMember(PrtCnvMember *a_member, int newExerciseId) +{ + if (!a_member) + return; + a_member->m_loggedInExerciseId = newExerciseId; + DEBUG_LOG(m_logger) << "Updating exerciseId member with eqId " << a_member->m_Id + << " and issi " << a_member->m_ISSI << " to " << newExerciseId + << ", store in db: " << m_DoStorePermanent; + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET exercise_id = %2 WHERE id = %3") + .arg(memberTableName()).arg(newExerciseId).arg(a_member->m_Id)); +} + + + + + +PrtCnv::PrtCnvMember *PrtCnvDbThread::getMemberById(const uint16_t a_id) +{ + QMutexLocker l(&m_MemberListByIdMutex); + auto iter = m_MemberListById.find(a_id); + if (iter != m_MemberListById.end()) + return iter->second; + + return nullptr; +} + + + + + +PrtCnv::PrtCnvMember *PrtCnvDbThread::getMemberByISSI(const uint32_t a_ISSI) const +{ + auto iter = m_MemberListByISSI.find(a_ISSI); + if (iter != m_MemberListByISSI.end()) + return iter->second; + + return nullptr; +} + + + + + + +uint8_t PrtCnvDbThread::getResetCounter() const +{ + return m_ResetCounter; +} + + + + + +void PrtCnvDbThread::setResetCounter(uint8_t newVal) +{ + m_ResetCounter = newVal; + if (m_DoStorePermanent) + { + NSqlQuery q(m_db); + q.exec(QStringLiteral("UPDATE Status SET reset_counter = %1 WHERE id = 1") + .arg(int(newVal))); + } + INFO_LOG(m_logger) << "Update resetCounter=" << (int)m_ResetCounter << " doStorePermanent=" << m_DoStorePermanent; +} + + + + + + +uint8_t PrtCnvDbThread::getBattleFieldOperatingState() const +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + return m_BattleFieldOperatingState; +} + + + + + +void PrtCnvDbThread::setPause(const bool a_doSet) +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + if (a_doSet) + m_BattleFieldOperatingState = m_BattleFieldOperatingState | 0x80; + else + m_BattleFieldOperatingState = m_BattleFieldOperatingState & 0x7F; + + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET ctas_operating_state = %2 WHERE id = 1") + .arg(statusTableName()).arg(int(m_BattleFieldOperatingState))); + + INFO_LOG(m_logger) << "Update battleFieldOperatingState=" << (int)m_BattleFieldOperatingState << " doStorePermanent=" << m_DoStorePermanent; +} + + + + +void PrtCnvDbThread::setPositionSendTime(unsigned int sendTime) +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + if (sendTime > 31) + sendTime = 31; + if (sendTime < 1) + sendTime = 1; + + + m_BattleFieldOperatingState &= 0x83; + + m_BattleFieldOperatingState |= (sendTime << 2); +} + + + + +void PrtCnvDbThread::setAirLoad(PrtCnvRadioThread::E_TrafficLoad airLoad) +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + + m_BattleFieldOperatingState &= 0xFC; + + m_BattleFieldOperatingState |= (static_cast(airLoad) & 0x03); +} + + + + + +bool PrtCnvDbThread::isEnvironmentResetCounterOld() const +{ + QMutexLocker l(&m_RadioListMutex); + + bool isOld = false; + if (m_EnvironmentTelegram) + isOld = getResetCounter() != m_EnvironmentTelegram->m_RadioTelegram->getPayloadDataUInt8(7); + return isOld; +} + + + + + +void PrtCnvDbThread::setResetCounterOnEnvironment() +{ + QMutexLocker l(&m_RadioListMutex); + + if (m_EnvironmentTelegram) + m_EnvironmentTelegram->m_RadioTelegram->setPayloadDataWithIndex(7, getResetCounter(), 1); +} + + + + +std::shared_ptr PrtCnvDbThread::getEnvironmentTelegram() +{ + QMutexLocker l(&m_RadioListMutex); + if (m_EnvironmentTelegram) + return std::make_shared(m_EnvironmentTelegram->m_RadioTelegram->data()); + return {}; +} + + + + + +std::map PrtCnvDbThread::getClaimStatistics() const +{ + std::map ret; + QMutexLocker l(&m_MemberListByIdMutex); + for (const auto &p : m_MemberListById) + { + if (p.first != 0) + ret.insert(std::make_pair(p.first, p.second->m_ClaimCount)); + } + return ret; +} + + + + + + +void PrtCnvDbThread::incClaimCount(int a_identity) +{ + QMutexLocker l(&m_MemberListByIdMutex); + auto iter = m_MemberListById.find(a_identity); + if (iter != m_MemberListById.end()) + { + iter->second->m_ClaimCount++; + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET claims = claims + 1 WHERE id = %2") + .arg(memberTableName()).arg(iter->second->m_Id)); + } + else + ERROR_LOG(m_logger) << "Internal error: did not find TNE with id=" << a_identity; +} + + + + + + + + +void PrtCnvDbThread::setMachineState(const int a_newMachineState) +{ + NSqlQuery q(m_db); + q.exec(QStringLiteral("UPDATE %1 SET machine_state = %2 WHERE id = 1") + .arg(statusTableName()).arg(a_newMachineState)); +} + + + + + + + +bool PrtCnvDbThread::mustProceedCleanup() const +{ + return m_DoProceedCleanup; +} + + + + + + + +void PrtCnvDbThread::sendStorePermanentSignal() +{ + if (m_StorePermanentPending.testAndSetOrdered(0, 1)) + emit doStorePermanent(); +} + +void PrtCnvDbThread::closeDb() +{ + if (m_db.isOpen()) + { + m_db.close(); + m_db = QSqlDatabase(); + QSqlDatabase::removeDatabase(QStringLiteral("PrtCnv")); + } +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvDbThread.hpp b/TetraIF/PrtCnv/PrtCnvDbThread.hpp new file mode 100644 index 000000000..bad046a43 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvDbThread.hpp @@ -0,0 +1,371 @@ + + + + + + + + + + + + + + +#pragma once + +#include +#include +#include +#include +#include "PrtCnvThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include +#include +#include + +namespace N_CoPrtCnv +{ + class CoPrtCnvCentralTelegram; + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + class PrtCnvStoredCentralTelegram; + class PrtCnvStoredRadioTelegram; + class PrtCnvMember; + + + class PrtCnvDbThread : public PrtCnvThread + { + Q_OBJECT + + public: + + + PrtCnvDbThread(const QString &dbDriver, + const QString &dbHostName, + const QString &dbDatabaseName, + const QString &schemaName, + const QString &dbUserName, + const QString &dbPassword, + PrtCnvThreadStarter* a_parent); + ~PrtCnvDbThread(); + + + + int32_t start() override; + + + int32_t stop() override; + + + int32_t create(NGL::Settings *settings) override; + + + int32_t init() override; + + + void ackCentralTelegrams(int32_t a_counter); + + + + N_CoPrtCnv::CoPrtCnvCentralTelegram *getNextCentralTelegram(PrtCnvStoredCentralTelegram *& a_handle); + + + + void centralTelegramSent(const int32_t a_counter, PrtCnvStoredCentralTelegram *a_handle); + + + + void centralTelegramCouldNotBeSent(PrtCnvStoredCentralTelegram *a_handle); + + + + void radioTelegramSent(const uint32_t a_sendCounter, PrtCnvStoredRadioTelegram *a_handle, const uint32_t a_broadcastIndex); + + + + std::shared_ptr getNextRadioTelegram(PrtCnvStoredRadioTelegram *&a_handle); + + + + std::shared_ptr getNextBroadcastTelegram(); + + + + void storeCentralTelegram(const std::shared_ptr &a_centralTelegram, + const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + + void storeRadioTelegram(const std::shared_ptr &a_telegram, const int32_t a_readCounter); + + + + void centralCounterReadyForAck(const int32_t a_centralCounter); + + + + void addSqlCommand(const QString &sql); + + + + + void cleanAndInit(); + + + + bool resendCentralTelegrams(const int32_t a_lastSendCounter); + + + + void prepareCentralTelegramsForReconnection(); + + + + void waitUntilDbWritten(); + + + + PrtCnvMember* getMemberByISSI(const uint32_t a_ISSI) const; + + + + PrtCnvMember* getMemberById(const uint16_t a_id); + + + + bool licenseMember(PrtCnvMember *a_member, const bool a_doLicense = true); + + + + void updateExerciseIdForMember(PrtCnvMember *a_member, int newExerciseId); + + + + PrtCnvMember* addMember(const int a_identity, const int a_ISSI); + + + + void removeMember(PrtCnvMember* a_member); + + + + uint8_t getResetCounter() const; + + + + void setResetCounter(uint8_t newVal); + + + + uint8_t getBattleFieldOperatingState() const; + + + + void setPause(const bool a_doSet = true); + + + + void setPositionSendTime(unsigned int sendTime); + + + + void setAirLoad(PrtCnvRadioThread::E_TrafficLoad airLoad); + + + + bool isEnvironmentResetCounterOld() const; + + + + std::shared_ptr getEnvironmentTelegram(); + + + + void setResetCounterOnEnvironment(); + + + + void incClaimCount(int a_identity); + + + + std::map getClaimStatistics() const; + + + + void setMachineState(const int a_newMachineState); + + + + bool mustProceedCleanup() const; + + protected: + void closeDb(); + + + + std::vector m_CentralList; + + + + mutable QMutex m_BattleFieldOpStateMutex; + + + + mutable QMutex m_MemberListByIdMutex; + + + + mutable QMutex m_CentralListMutex; + + + + QSqlDatabase m_db; + + + + QAtomicInt m_CentralAckCounter; + + + unsigned int m_OldCentralAckCounter; + + + std::list m_RadioList; + + + mutable QMutex m_RadioListMutex; + + + std::vector m_SqlCommandList; + + + mutable QMutex m_SqlCmdListMutex; + + + mutable QMutex m_BroadcastMapMutex; + + + std::list m_BroadcastList; + + + bool m_DoClean; + + + bool m_DoWaitUntilSqlWritten; + + + std::unordered_map m_MemberListById; + + + std::unordered_map m_MemberListByISSI; + + + bool m_DoStorePermanent; + + + uint8_t m_ResetCounter; + + + uint8_t m_BattleFieldOperatingState; + + + PrtCnvStoredRadioTelegram* m_EnvironmentTelegram; + + + bool m_DoProceedCleanup; + + + int32_t m_OldCentralCounter; + + + QBasicAtomicInt m_StorePermanentPending; + + + + uint32_t m_NbrOfAttempts; + + + + bool createDatabase(); + + + + void sendStorePermanentSignal(); + + + + void storeCentralTelegrams(); + + + + int32_t storeRadioTelegrams(); + + + + void handleSqlCommandList(); + + + + void deleteTelegramsFromDbById(const QString &table); + + + void updateTelegramsWriteCounter(const QString &table); + + + + void updateTelegramsBroadcast(const QString &table); + + + + void reinitDatabase(); + + QString toCentralTableName() const { return tableName(QStringLiteral("prtcnv_to_central")); } + QString toRadioTableName() const { return tableName(QStringLiteral("prtcnv_to_radio")); } + QString memberTableName() const { return tableName(QStringLiteral("prtcnv_member")); } + QString statusTableName() const { return tableName(QStringLiteral("prtcnv_status")); } + QString versionTableName() const { return tableName(QStringLiteral("prtcnv_version")); } + QString tableName(const QString &table) const { return m_dbSchemaName.isEmpty() ? table : m_dbSchemaName + QLatin1Char('.') + table; } + protected slots: + + + void storePermanent(); + + + void clean(); + + public: + signals: + + + void doStorePermanent(); + + + void permanentStored(int32_t a_centralCounter); + + + void doClean(); + + void playerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind); + + private: + + + + std::vector m_telegramsToDelete; + std::vector > m_telegramsToUpdateCounter; + std::vector > m_telegramsToUpdateBC; + std::vector > m_telegramsToInsert; + QString m_dbDriver; + QString m_dbHostName; + QString m_dbDatabaseName; + QString m_dbSchemaName; + QString m_dbUserName; + QString m_dbPassword; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp b/TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp new file mode 100644 index 000000000..b8d586cbc --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + +#include "PrtCnvInjectionSocket.hpp" +#include +#include +#include "PrtCnvInjectionThread.hpp" +#include +#include + +namespace PrtCnv +{ + +PrtCnvInjectionSocket::PrtCnvInjectionSocket() + : m_Socket(nullptr) + , m_Server(nullptr) + , m_logger(getLogger("PrtCnvInjectionSocket")) +{} + +PrtCnvInjectionSocket::~PrtCnvInjectionSocket() +{ + delete m_Socket; +} + + + + +void PrtCnvInjectionSocket::disconnectClient() +{ + INFO_LOG(m_logger) << "A client has disconnected from the injection-server"; + emit disconnected(this); +} + + + + + +void PrtCnvInjectionSocket::processInputData() +{ + INFO_LOG(m_logger) << "Injection-server has data received"; + N_CoPrtCnv::CoPrtCnvInjectionHeader injectionHeader; + qint64 bytesRead = m_Socket->peek((char*)&injectionHeader, sizeof(injectionHeader)); + if (sizeof(injectionHeader) == bytesRead) + { + if (injectionHeader.isIdCorrect()) + { + + qint64 available = m_Socket->bytesAvailable(); + if (available < (injectionHeader.m_Size+sizeof(injectionHeader))) + { + INFO_LOG(m_logger) << "not enough bytes available - waiting for more data: " + << "headersize=" << sizeof(injectionHeader) << " id1=" + << injectionHeader.m_Id1 << " id2=" << injectionHeader.m_Id2 + << " kind=" << (int)injectionHeader.m_Kind << " size=" + << injectionHeader.m_Size; + return; + } + + m_Socket->read((char*)&injectionHeader, sizeof(injectionHeader)); + if (injectionHeader.isIdCorrect()) + { + + + + QByteArray data(injectionHeader.m_Size, Qt::Uninitialized); + m_Socket->read(data.data(), injectionHeader.m_Size); + + switch (injectionHeader.m_Kind) + { + case N_CoPrtCnv::CoPrtCnvInjectionHeader::eCentral: + case N_CoPrtCnv::CoPrtCnvInjectionHeader::eRadio: + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = new N_CoPrtCnv::CoPrtCnvCentralTelegram(data); + + if (N_CoPrtCnv::CoPrtCnvInjectionHeader::eCentral == injectionHeader.m_Kind && + tele->telegramId() != TrainingAreaBase::TetraIcd::TelegramId::DATENVERKEHR_TDS_SRT) + { + INFO_LOG(m_logger) << "Got an injection-central-telegram with telId=" << tele->telegramId(); + m_Server->addToCentralList(tele); + } + else + { + INFO_LOG(m_logger) << "Got an injection-radio-telegram with telId=" << tele->telegramId(); + m_Server->addToRadioList(tele); + } + } + break; + + default: + ERROR_LOG(m_logger) << "Unknown kind (" << injectionHeader.m_Kind << ") of injection-telegram"; + break; + } + } + } + else + { + ERROR_LOG(m_logger) << "Corrupt injection-telegram received => reconnect"; + m_Socket->disconnectFromHost(); + } + } +} + + +void PrtCnvInjectionSocket::setSocket(QTcpSocket* a_socket, PrtCnvInjectionThread* a_server) +{ + m_Socket = a_socket; + m_Server = a_server; + connect(this, &PrtCnvInjectionSocket::disconnected, m_Server, &PrtCnvInjectionThread::disconnectClient, Qt::QueuedConnection); + if (m_Socket) + { + connect(m_Socket, &QTcpSocket::readyRead, this, &PrtCnvInjectionSocket::processInputData, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::disconnected, this, &PrtCnvInjectionSocket::disconnectClient, Qt::QueuedConnection); + } +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp b/TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp new file mode 100644 index 000000000..a5921191e --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp @@ -0,0 +1,66 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "logger.h" + +class QTcpSocket; + +namespace PrtCnv +{ + class PrtCnvInjectionThread; + + + class PrtCnvInjectionSocket : public QObject + { + Q_OBJECT + public: + + PrtCnvInjectionSocket(); + ~PrtCnvInjectionSocket(); + + + + void setSocket(QTcpSocket* a_socket, PrtCnvInjectionThread* a_server); + + protected: + QTcpSocket *m_Socket; + + PrtCnvInjectionThread *m_Server; + + + + NGL::INGLLogger &m_logger; + + protected slots: + + + void disconnectClient(); + + + + void processInputData(); + + + public: + signals: + + + void disconnected(PrtCnvInjectionSocket* a_injectSocket); + + + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvInjectionThread.cpp b/TetraIF/PrtCnv/PrtCnvInjectionThread.cpp new file mode 100644 index 000000000..98e06717d --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionThread.cpp @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvInjectionSocket.hpp" + +#include +#include +#include +#include + + +namespace PrtCnv +{ + +PrtCnvInjectionThread::PrtCnvInjectionThread(PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvInjectionThread") + , m_Port(46666) + , m_Enabled(false) + , m_Server(nullptr) + , m_CentralListMutex(nullptr) + , m_RadioListMutex(nullptr) +{ + m_Name = QStringLiteral("Injection"); +} + +PrtCnvInjectionThread::~PrtCnvInjectionThread() +{ + delete m_CentralListMutex; + delete m_RadioListMutex; +} + + +int32_t PrtCnvInjectionThread::create(NGL::Settings *settings) +{ + INFO_LOG(m_logger) << "create"; + PrtCnvThread::create(settings); + + m_CentralListMutex = new QMutex; + m_RadioListMutex = new QMutex; + + m_Enabled = m_Config->getBoolean(getName(), QStringLiteral("Enable"), false); + + + if (m_Enabled) + { + m_Server = new QTcpServer(this); + if (m_Server) + connect(m_Server, &QTcpServer::newConnection, this, &PrtCnvInjectionThread::connectClient, Qt::QueuedConnection); + } + + return 0; +} + + + +int32_t PrtCnvInjectionThread::init() +{ + INFO_LOG(m_logger) << "init"; + PrtCnvThread::init(); + m_Port = m_Config->getInteger(getName(), QStringLiteral("Port"), 46666); + + return 0; +} + + + + + + +int32_t PrtCnvInjectionThread::start() +{ + INFO_LOG(m_logger) << "Start"; + PrtCnvThread::start(); + + + if (m_Enabled) + { + m_Server->setMaxPendingConnections(1); + m_Server->listen(QHostAddress::Any, m_Port); + INFO_LOG(m_logger) << "Injection-Server is listening on port " << m_Port; + } + + return 0; +} + + + + + + +void PrtCnvInjectionThread::connectClient() +{ + INFO_LOG(m_logger) << "A client has connected to the injection-server"; + PrtCnvInjectionSocket* injectSocket = new PrtCnvInjectionSocket; + m_SocketList.insert(injectSocket); + INFO_LOG(m_logger) << "Now are " << m_SocketList.size() << " injection-client(s) connected"; + injectSocket->setSocket(m_Server->nextPendingConnection(), this); +} + + + + + + +void PrtCnvInjectionThread::disconnectClient(PrtCnvInjectionSocket *a_injectionSocket) +{ + auto it = m_SocketList.find(a_injectionSocket); + if (it != m_SocketList.end()) + m_SocketList.erase(it); + INFO_LOG(m_logger) << "Now are " << m_SocketList.size() << " injection-client(s) connected"; + delete a_injectionSocket; +} + + + + + + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *PrtCnvInjectionThread::getNextCentralInjectionTelegram() +{ + QMutexLocker l(m_CentralListMutex); + + if (m_CentralTelegramList.empty()) + return nullptr; + auto centralTelegram = m_CentralTelegramList.front(); + m_CentralTelegramList.pop(); + return centralTelegram; +} + + + + + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *PrtCnvInjectionThread::getNextRadioInjectionTelegram() +{ + QMutexLocker l(m_RadioListMutex); + + if (m_RadioTelegramList.empty()) + return nullptr; + auto radioTelegram = m_RadioTelegramList.front(); + m_RadioTelegramList.pop(); + return radioTelegram; +} + + + +void PrtCnvInjectionThread::addToCentralList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + QMutexLocker l(m_CentralListMutex); + m_CentralTelegramList.push(a_telegram); +} + + + +void PrtCnvInjectionThread::addToRadioList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + QMutexLocker l(m_RadioListMutex); + m_RadioTelegramList.push(a_telegram); +} + +} + diff --git a/TetraIF/PrtCnv/PrtCnvInjectionThread.hpp b/TetraIF/PrtCnv/PrtCnvInjectionThread.hpp new file mode 100644 index 000000000..52cf3ac1d --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionThread.hpp @@ -0,0 +1,101 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" +#include +#include + +class QTcpServer; +class QMutex; + +namespace N_CoPrtCnv +{ +class CoPrtCnvCentralTelegram; +} + +namespace PrtCnv +{ + class PrtCnvInjectionSocket; + + + class PrtCnvInjectionThread : public PrtCnvThread + { + Q_OBJECT + public: + + ~PrtCnvInjectionThread(); + + + + explicit PrtCnvInjectionThread(PrtCnvThreadStarter* a_parent); + + + int32_t create(NGL::Settings *settings) override; + + + int32_t init() override; + + + + int32_t start() override; + + + + N_CoPrtCnv::CoPrtCnvCentralTelegram *getNextCentralInjectionTelegram(); + + + + N_CoPrtCnv::CoPrtCnvCentralTelegram *getNextRadioInjectionTelegram(); + + + + void addToCentralList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + + void addToRadioList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + protected: + + uint16_t m_Port; + + + bool m_Enabled; + QTcpServer *m_Server; + + + std::queue m_CentralTelegramList; + QMutex *m_CentralListMutex; + + + std::queue m_RadioTelegramList; + QMutex *m_RadioListMutex; + + + std::set m_SocketList; + + + + public slots: + + + void connectClient(); + + + void disconnectClient(PrtCnvInjectionSocket* a_injectionSocket); + + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvMain.cpp b/TetraIF/PrtCnv/PrtCnvMain.cpp new file mode 100644 index 000000000..627585784 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvMain.cpp @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + +#include "PrtCnvApplication.hpp" +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#include +#endif + + + + +static void daemonize() +{ +#ifndef WIN32 + pid_t pid, sid; + + + if ( getppid() == 1 ) + return; + + + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + + + + umask(0); + + + sid = setsid(); + if (sid < 0) { + exit(EXIT_FAILURE); + } + + + + if ((chdir("/")) < 0) { + exit(EXIT_FAILURE); + } + + + freopen( "/dev/null", "r", stdin); + freopen( "/dev/null", "w", stdout); + freopen( "/dev/null", "w", stderr); +#endif +} + +class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser +{ +public: + CmdLineParser() + : LtsCommandLineParser(ProvideCommandLineParameterOptions(ExerciseId|CustomConfigFile)) + { + addOption( { QStringList() << QStringLiteral("d") << QStringLiteral("daemonize"), + QStringLiteral("Start in background") } ); + addOption( { QStringList() << QStringLiteral("c") << QStringLiteral("cleandb"), + QStringLiteral("Start over with clean database") } ); + } + + bool daemonize() const + { + return isSet(QStringLiteral("d")); + } + bool cleanDb() const + { + return isSet(QStringLiteral("c")); + } +}; + +int main(int argc, char** argv) +{ + QNetworkProxy::setApplicationProxy(QNetworkProxy()); + NGLCoreApplication app(argc, argv); + + CmdLineParser options; + if (!options.init()) + return -1; + app.createLogger("PrtCnv", options.exerciseId()); + + if (options.daemonize()) + daemonize(); + + PrtCnv::PrtCnvApplication prtCnvApp; + prtCnvApp.setCleanDb(options.cleanDb()); + prtCnvApp.setExerciseId(options.exerciseId()); + if (options.iniFileSet()) + prtCnvApp.setConfigFile(options.iniFile()); + + STARTUP_LOG(app.baseLogger()); + + prtCnvApp.startApp(); + int ret = app.exec(); + prtCnvApp.shutdownApp(); + + SHUTDOWN_LOG(app.baseLogger()); + + return ret; +} diff --git a/TetraIF/PrtCnv/PrtCnvMember.cpp b/TetraIF/PrtCnv/PrtCnvMember.cpp new file mode 100644 index 000000000..8be0b0767 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvMember.cpp @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + +#include "PrtCnvMember.hpp" +#include + +namespace PrtCnv +{ + + + + +PrtCnvMember::PrtCnvMember(int a_id, int a_issi) + : m_ISSI(a_issi) + , m_ClaimCount(0) + , m_loggedInExerciseId(0) + , m_Id(a_id) + , m_Licensed(false) +{} + +PrtCnvMember::~PrtCnvMember() +{ + clearFragmentedList(); +} + + + + + +void PrtCnvMember::addFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + m_FragmentedTelegramList.insert(std::make_pair(a_radioTelegram.getFragmentCounter(), + new N_CoPrtCnv::CoPrtCnvRadioTelegram(a_radioTelegram))); +} + + + + + + + + +gef_telegramm_id_et PrtCnvMember::getFragmentedTelegramId() const +{ + + for (auto rit = m_FragmentedTelegramList.rbegin(); rit != m_FragmentedTelegramList.rend(); ++rit) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram *firstFragment = rit->second; + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment == firstFragment->getFragmentStatus()) + return firstFragment->getTelID(); + } + return GEF_BESTAETIGUNG; +} + + + + + + +void PrtCnvMember::clearFragmentedList() +{ + for (auto it : m_FragmentedTelegramList) + delete it.second; + m_FragmentedTelegramList.clear(); +} + + + + + + + +QByteArray PrtCnvMember::getUnfragmentedTelegramData() const +{ + return N_CoPrtCnv::CoPrtCnvRadioTelegram::getUnfragmentedData(m_FragmentedTelegramList); +} + + + + + +bool PrtCnvMember::isFragmentedListEmpty() const +{ + return m_FragmentedTelegramList.empty(); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvMember.hpp b/TetraIF/PrtCnv/PrtCnvMember.hpp new file mode 100644 index 000000000..ebe580760 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvMember.hpp @@ -0,0 +1,84 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include + + + + +namespace N_CoPrtCnv +{ + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + + + class PrtCnvMember final + { + public: + + + + enum E_MemberStatus + { + e_Ok, + e_AlreadyLoggedIn, + e_MasteringLogIn, + e_NotLoggedIn + }; + ~PrtCnvMember(); + + + + PrtCnvMember(int a_id, int a_issi); + + + + void addFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + gef_telegramm_id_et getFragmentedTelegramId() const; + + + void clearFragmentedList(); + + + QByteArray getUnfragmentedTelegramData() const; + + + bool isFragmentedListEmpty() const; + + public: + + int m_ISSI; + + int m_ClaimCount; + + int m_loggedInExerciseId; + + int m_Id; + + bool m_Licensed; + + private: + + std::multimap m_FragmentedTelegramList; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioThread.cpp b/TetraIF/PrtCnv/PrtCnvRadioThread.cpp new file mode 100644 index 000000000..3cfca6dd0 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioThread.cpp @@ -0,0 +1,2267 @@ + + + + + + + + + + + + + + +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvRadioTrafficThread.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvMember.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvDbThread.hpp" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace PrtCnv +{ + +static BiteError getBiteError(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram, + size_t iOffset) +{ + BiteError ret; + ret.canDeviceNumber = a_radioTelegram.getPayloadDataUInt8(iOffset + 0); + ret.subdeviceNumber = a_radioTelegram.getPayloadDataUInt8(iOffset + 1); + ret.uniqueId = a_radioTelegram.getPayloadDataUInt32(iOffset + 2, 4); + ret.errorNumber = a_radioTelegram.getPayloadDataUInt8(iOffset + 6); + + return ret; +} + +PrtCnvRadioThread::PrtCnvRadioThread(int exerciseId, PrtCnvThreadStarter *a_parent) + : PrtCnvSocketThread(a_parent, "PrtCnvRadioThread"), + m_CentralThread(nullptr), + m_radioTrafficThread(nullptr), + m_SendCounter(0), + m_HostISSI(0), + START_COUNTER(0), + END_COUNTER(256), + m_EnvironmentTelegramTimer(nullptr), + m_BroadcastISSI(0), + m_LoginPathWithPrefix(QString()), + m_ExerciseId(exerciseId), + m_DoLicenseDespiteSelftestOrConfigFailure(false), + m_DoCheckIdentity(true), + m_DoDumpReceivedTelegrams(false), + m_DoDumpSentTelegrams(false), + m_DoUseSDSTL(false), + m_EmergencyCallISSI(0), + m_EnvironmentTelegram(nullptr), + m_SendLoad(E_TrafficLoad::Unknown), + m_SendQueueFullLoad(0), + m_SendQueueHighLoad(0), + m_SendTelegramsNormalLoad(100), + m_SendTelegramsHighLoad(50), + m_SendTelegramsFullLoad(10), + m_SentTelegrams(0), + m_SentBytes(0), + m_TickCounter(0), + m_TicksPerSecond(0), + m_AverageIndex(0), + m_ReceivedTelegrams(0), + m_ReceivedBytes(0), + m_bUseScrambling(false), + m_loggerStats(getLogger("PrtCnvRadioThread.statistic")), + m_exerciseEquipmentAssignmentMutex(QMutex::Recursive) +{ + m_Name = QStringLiteral("Radio"); + for (int i = 0; i < AVERAGE_COUNT; ++i) + { + m_SentBytesAverage[i] = 0; + m_ReceivedBytesAverage[i] = 0; + } + qRegisterMetaType("N_CoPrtCnv::E_LicensingKind"); +} + + + + +int32_t PrtCnvRadioThread::create(NGL::Settings *settings) +{ + INFO_LOG(m_logger) << "create"; + PrtCnvSocketThread::create(settings); + m_BroadcastManager.create(settings); + + m_CentralThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Central)); + connect(this, &PrtCnvRadioThread::checkSendToRadio, + this, &PrtCnvRadioThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::checkMemberForValidLogin, + this, &PrtCnvRadioThread::onCheckMemberForValidLogin, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::checkSendToCentral, + m_CentralThread, &PrtCnvCentralThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::stopped, + m_CentralThread, &PrtCnvCentralThread::radioStopped, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::cleant, + m_CentralThread, &PrtCnvCentralThread::radioCleant, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::tetraConnectionState, + m_CentralThread, &PrtCnvCentralThread::onTetraConnectionState, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::playerLicencedChanged, + m_CentralThread, &PrtCnvCentralThread::onPlayerLicencedChanged, Qt::QueuedConnection); + connect(&m_BroadcastManager, &PrtCnvBroadcastMgr::areaEffectSimulationDeactivated, + this, &PrtCnvRadioThread::areaEffectSimulationDeactivated); + connect(&m_BroadcastManager, &PrtCnvBroadcastMgr::areaEffectSimulationActivated, + this, &PrtCnvRadioThread::areaEffectSimulationActivated); + + auto mainApp = m_Parent->getMainApp(); + connect(mainApp, &PrtCnvApplication::outgoingBroadcastTelegramsRequest, + this, &PrtCnvRadioThread::onBroadcastTelegramsRequestFromCentral); + + connect(this, &PrtCnvRadioThread::warehouseMessageFromPtrCnv, + mainApp, &PrtCnvApplication::warehouseMessageFromPtrCnv); + + static_assert(sizeof(N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader) == 4, + "This code expects a size of 4 for CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader (otherwise it will not work correct)" + ); + return 0; +} + + + + + +int32_t PrtCnvRadioThread::destroy() +{ + INFO_LOG(m_logger) << "Destroy"; + PrtCnvSocketThread::destroy(); + delete m_EnvironmentTelegramTimer; m_EnvironmentTelegramTimer = nullptr; + return 0; +} + + + + + +int32_t PrtCnvRadioThread::init() +{ + INFO_LOG(m_logger) << "init"; + PrtCnvSocketThread::init(); + m_BroadcastManager.setDbThread(m_DbThread); + m_TickTimeout = m_Config->getInteger(QStringLiteral("Broadcast"), QStringLiteral("SendGap"), 500); + m_TicksPerSecond = 1000 / m_TickTimeout; + m_BroadcastManager.init(); + + N_CoPrtCnv::CoPrtCnvRadioTelegram::setEtsMode(m_Config->getBoolean(getName(), QStringLiteral("EtsMode"), false)); + + m_HostISSI = m_Config->getInteger(getName(), QStringLiteral("HostISSI"), 9998); + m_BroadcastISSI = m_Config->getInteger(getName(), QStringLiteral("BroadcastISSI"), 5000); + m_EmergencyCallISSI = m_Config->getInteger(getName(), QStringLiteral("EmergencyCallISSI"), 9000); + if (m_DoCleanDb) + m_DbThread->licenseMember(m_DbThread->addMember(0, m_BroadcastISSI)); + + QString groupString = m_Config->getString(getName(), QStringLiteral("ListenGroups"), QString()); + const QVector groups = groupString.splitRef(QLatin1Char(','), QString::SkipEmptyParts); + for (const QStringRef &sr : groups) + { + uint32_t group = sr.toUInt(); + if (group > 0) + m_ListenGroups.insert(group); + } + if (m_ListenGroups.size() > 5) + { + while (m_ListenGroups.size() > 5) + m_ListenGroups.erase(m_ListenGroups.end()); + WARNING_LOG(m_logger) << "More than 5 ListenGroups defined - ignoring all except the first 5"; + } + + m_LoginPathWithPrefix = m_Config->getString(QStringLiteral("Login"), QStringLiteral("LoginFilePathWithPrefix"), QStringLiteral("login")); + if (!QDir::isAbsolutePath(m_LoginPathWithPrefix)) + m_LoginPathWithPrefix = QCoreApplication::applicationDirPath() + QLatin1String("/../") + m_LoginPathWithPrefix; + + m_LoginPathWithPrefix = QDir::cleanPath(QDir::fromNativeSeparators(m_LoginPathWithPrefix)); + QString path = m_LoginPathWithPrefix.left(m_LoginPathWithPrefix.lastIndexOf(QLatin1Char('/'))); + QDir().mkpath(path); + + m_DoLicenseDespiteSelftestOrConfigFailure = m_Config->getBoolean(QStringLiteral("Login"), QStringLiteral("DoLicenseDespiteSelftestOrConfigFailure"), false); + initIdentityArray(); + + m_bUseScrambling = m_Config->getBoolean(getName(), QStringLiteral("UseScrambling"), false); + m_DoDumpReceivedTelegrams = m_Config->getBoolean(getName(), QStringLiteral("DumpReceivedTelegrams"), false); + m_DoDumpSentTelegrams = m_Config->getBoolean(getName(), QStringLiteral("DumpSentTelegrams"), false); + m_DoUseSDSTL = m_Config->getBoolean(getName(), QStringLiteral("UseSDS_TL"), false); + + const QString trafficControl(QStringLiteral("TrafficControl")); + m_SendQueueHighLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendQueueHighLoad"), 1000); + m_SendQueueFullLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendQueueFullLoad"), 2000); + m_SendTelegramsNormalLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendTelegramsNormalLoad"), 100); + m_SendTelegramsHighLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendTelegramsHighLoad"), 50); + m_SendTelegramsFullLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendTelegramsFullLoad"), 10); + m_SendLoad = E_TrafficLoad::Unknown; + + if (!m_DoCleanDb) + m_BroadcastManager.restoreAfterCrash(); + + emit initDone(); + + return 0; +} + + + + + +int32_t PrtCnvRadioThread::start() +{ + INFO_LOG(m_logger) << "Start"; + PrtCnvSocketThread::start(); + connectSocket(); + return 0; +} + + + + + + +void PrtCnvRadioThread::connected() +{ + INFO_LOG(m_logger) << "Radio-Socket connected m_Socket=" << m_Socket; + m_ReceiveCounter = END_COUNTER - 1; + m_SendCounter = END_COUNTER; + m_SentTelegrams = 0; + m_SentBytes = 0; + m_ReceivedTelegrams = 0; + m_ReceivedBytes = 0; + m_TickCounter = 0; + for (int i = 0; i < AVERAGE_COUNT; i++) + { + m_SentBytesAverage[i] = 0; + m_ReceivedBytesAverage[i] = 0; + } + m_AverageIndex = 0; + doRegister(); + startTickTimer(); + m_ConnectionTimer->stop(); + m_State = PrtCnvSocketThread::e_REGISTERING; +} + + + + + + +void PrtCnvRadioThread::prepareCleanUp() +{ + m_DoCleanup = true; +} + + + + + +void PrtCnvRadioThread::doStop() +{ + m_DoCleanup = true; + if (m_EnvironmentTelegramTimer) + m_EnvironmentTelegramTimer->stop(); + m_TickTimer->stop(); + disconnectSocket(); +} + + + + +void PrtCnvRadioThread::onBroadcastTelegramsRequestFromCentral(int equipmentNumber, int broadcastIndex, int resetCounter) +{ + m_BroadcastManager.handleNachforderungBroadcastTelegram(equipmentNumber, broadcastIndex, resetCounter); +} + + + + +void PrtCnvRadioThread::doClean() +{ + INFO_LOG(m_logger) << "doClean"; + m_BroadcastManager.cleanAndInit(true); + m_DbThread->setResetCounter(m_DbThread->getResetCounter() + 1); + emit cleant(); +} + + + + + +void PrtCnvRadioThread::doStart() +{ + m_DoCleanup = false; + connectSocket(); + if (m_EnvironmentTelegramTimer && m_EnvironmentTelegramTimer->interval() > 0) + m_EnvironmentTelegramTimer->start(); +} + + + + + +void PrtCnvRadioThread::disconnected() +{ + INFO_LOG(m_logger) << "Radio-Socket disconnected m_Socket=" << m_Socket; + + + if (e_WORKING == m_State || e_REGISTERING == m_State) + { + m_Socket->disconnectFromHost(); + if (m_Socket->state() != QAbstractSocket::UnconnectedState) + m_Socket->waitForDisconnected(); + } + m_State = e_DISCONNECTING; + if (m_DoCleanup) + { + m_ConnectionTimer->stop(); + emit stopped(); + } + else + connectSocket(); + + emit tetraConnectionState(false); +} + + + + + +void PrtCnvRadioThread::readyRead() +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; + + while (true) + { + if (m_DoCleanup) + break; + + + qint64 bytesRead = m_Socket->peek(reinterpret_cast(&header), sizeof(header)); + + + if (0 == bytesRead) + break; + + + if (sizeof(header) != bytesRead) + break; + + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) + { + ERROR_LOG(m_logger) << "Reconnect because radio-Telegram does not begin with magic-number 0xA5: I got 0x" + << QString::number(header.m_MagicNumber, 16); + disconnectSocket(); + break; + } + + + if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) + WARNING_LOG(m_logger) << "Radio-Telegram length to big: " << header.m_Length + << ", but I proceed with this telegram."; + + + uint16_t dataSize = header.m_Length + sizeof(header); + if (m_Socket->bytesAvailable() < dataSize) + { + INFO_LOG(m_logger) << "not enough bytes available - waiting for more data"; + break; + } + QByteArray buf(dataSize, Qt::Uninitialized); + + bytesRead = 0; + while (bytesRead < dataSize) + { + qint64 br = m_Socket->read(&buf.data()[bytesRead], dataSize - bytesRead); + bytesRead += br; + } + + if (!checkAndUpdateReceiveCounter(header.m_Counter, END_COUNTER, START_COUNTER)) + { + + m_LogThread->writeRadioTelegramLog(buf, true, 1); + ERROR_LOG(m_logger) << "Reconnect because frame-counter of received radio-telegram was wrong"; + disconnectSocket(); + break; + } + + + + handleReceivedTelegram(buf); + + + m_ReceivedTelegrams++; + m_ReceivedBytes += dataSize; + } +} + + + + + + + +void PrtCnvRadioThread::handleReceivedTelegram(const QByteArray &data) +{ + if (m_DoDumpReceivedTelegrams) + { + INFO_LOG(m_logger) << "Received radio-telegram:"; + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, data); + } + + switch (data.at(4)) + { + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: + handleRegisterRsp(data.at(5)); + m_State = e_WORKING; + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: + handleDataIndReq(data, true); + emit checkSendToCentral(); + return; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: + handleReportIndReq(data); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_StatusIndReq: + handleStatusIndReq(data); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: + handleAirInterfaceLoadReq(data); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirLoadHyterra: + break; + + default: + ERROR_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << data.at(4) + << " not implemented!"; + break; + } + m_LogThread->writeRadioTelegramLog(data, true, 1); +} + + + + + +void PrtCnvRadioThread::handleDataIndReq(const QByteArray &data, bool bIsMaybeScrambled) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(data); + const uint32_t dstISSI = radioTelegram.getDestISSI(); + + if (m_bUseScrambling && bIsMaybeScrambled && m_EmergencyCallISSI != dstISSI) + { + if (!unscrambleContent(radioTelegram)) + return; + } + + + m_LogThread->writeRadioTelegramLog(radioTelegram.data(), true, 1); + + + if (radioTelegram.isNormalTelegram() && radioTelegram.getTelID() == GEF_ESW_MELDUNG) + return; + + if (m_HostISSI == dstISSI || m_ListenGroups.find(dstISSI) != m_ListenGroups.end()) + { + if (!m_radioTrafficThread) + m_radioTrafficThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_RadioTraffic)); + if (m_radioTrafficThread) + m_radioTrafficThread->newTelegramArrived(radioTelegram.getPayloadSize()); + + + PrtCnvMember *member = m_DbThread->getMemberByISSI(radioTelegram.getSrcISSI()); + if (radioTelegram.isLoginTelegram() || (member != nullptr)) + { + switch (radioTelegram.getFragmentStatus()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: + + if (member->m_Licensed) + handleFragmentedTelegram(radioTelegram); + else + { + + sendLizenzierungTneToRadio(member->m_Id, member->m_ISSI, + N_CoPrtCnv::E_LicensingKind::Unlicense, + N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLicensed, + N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment == radioTelegram.getFragmentStatus() ? + radioTelegram.getTelID() : GEF_BESTAETIGUNG); + WARNING_LOG(m_logger) << "TNE with id=" << member->m_Id + << " tries to send a fragmented telegramm without beeing licensed"; + } + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_NotFragmented: + if (radioTelegram.isLoginTelegram()) + handleLoginTelegram(radioTelegram); + else if (radioTelegram.isNormalTelegram()) + { + if (radioTelegram.isCrcOk()) + { + radioTelegram.fixupTelegramIdForEts(false); + + gef_telegramm_id_et telId = radioTelegram.getTelID(); + + bool bIsBite = (GEF_BITE_MELDUNG2 == telId); + + if (member->m_Licensed || bIsBite) + { + + if (radioTelegram.isContentValid()) + { + + if (m_BroadcastManager.handleRadioTelegram(radioTelegram)) + { + std::shared_ptr + centralTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(&radioTelegram)); + if (centralTelegram) + { + + + + if (sendAnswer(radioTelegram)) + { + + + m_DbThread->storeCentralTelegram(centralTelegram, radioTelegram); + } + } + } + } + else + { + + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::InvalidByteCount, + telId); + ERROR_LOG(m_logger) << "The content of received telegram is wrong => thrown away"; + } + } + else + { + + sendLizenzierungTneToRadio(member->m_Id, member->m_ISSI, + N_CoPrtCnv::E_LicensingKind::Unlicense, + N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLicensed, + telId); + WARNING_LOG(m_logger) << "TNE with id=" << member->m_Id + << " tries to send a telegramm without beeing licensed"; + } + } + else + { + ERROR_LOG(m_logger) << "CRC of received telegram is wrong => thrown away"; + sendFehlermeldungGefechtsfeldToCentral(radioTelegram.getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::WrongCrc, + radioTelegram.getTelID()); + } + } + else + { + ERROR_LOG(m_logger) << "Unknown non-fragmented telegram-type: 0x" + << QString::number(radioTelegram.getFragmentCounter(), 16); + sendFehlermeldungGefechtsfeldToCentral(radioTelegram.getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + radioTelegram.getTelID()); + } + break; + default: + ERROR_LOG(m_logger) << "Unknown payload-status: " << radioTelegram.getFragmentStatus(); + sendFehlermeldungGefechtsfeldToCentral(radioTelegram.getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + radioTelegram.getTelID()); + break; + } + } + else + { + ERROR_LOG(m_logger) << "The TPU with id=" << radioTelegram.getIdentity() + << " and ISSI=" << radioTelegram.getSrcISSI() + << " has sent a telegram without be logged in"; + + bool hasId = !(radioTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment || radioTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment); + sendLoginResponse(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginReject, hasId ? radioTelegram.getIdentity() : 0, radioTelegram.getSrcISSI()); + } + } + else + { + if (m_EmergencyCallISSI == dstISSI) + { + + + uint32_t arr[10]; + + for (int i = 0; i < 10; ++i) + arr[i] = static_cast(radioTelegram.getPayloadDataUInt8(i - 1)); + for (int i = 0; i < 10; ++i) + DEBUG_LOG(m_logger) << "arr[" << i << "] = 0x" << QString::number(arr[i], 16); + + uint32_t x, y; + x = (arr[0] << 24) + (arr[1] << 16) + (arr[2] << 8) + arr[3]; + x = (x >> 3) & 0x1FFFFFF; + y = (arr[3] << 24) + (arr[4] << 16) + (arr[5] << 8) + arr[6]; + y = (y >> 3) & 0xFFFFFF; + + TrainingAreaBase::TetraIcd::EmergencyCall data; + double longitude = x * (360 / pow(2, 25)); + double latitude = y * (180 / pow(2, 24)); + data.absPosition.lon = longitude * (M_PI / 180.0); + data.absPosition.lat = latitude * (M_PI / 180.0); + data.issi = radioTelegram.getSrcISSI(); + data.timeStamp = QDateTime::currentMSecsSinceEpoch(); + auto tele(std::make_shared(data)); + + DEBUG_LOG(m_logger) << "Notruf lon: " << data.absPosition.lon << ", lat: " << data.absPosition.lat << ", issi: " << data.issi; + + m_DbThread->storeCentralTelegram(tele, radioTelegram); + } + else + { + ERROR_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << QString::number(data.at(4)) + << " and telId=" << radioTelegram.getTelID() + << " is for another host: " << radioTelegram.getDestISSI() + << " (we are " << m_HostISSI << ")"; + + } + } +} + + + + + +void PrtCnvRadioThread::handleLoginTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram) +{ + using namespace N_CoPrtCnv; + + uint16_t identity = a_loginTelegram.getIdentity(); + uint32_t issi = a_loginTelegram.getSrcISSI(); + + if (CoPrtCnvRadioTelegram::e_LoginRequest != (a_loginTelegram.getPayloadDataUInt8(2) & CoPrtCnvRadioTelegram::e_LoginStatusMask)) + { + ERROR_LOG(m_logger) << QStringLiteral("Unexpected login-status: 0x%1").arg(a_loginTelegram.getPayloadDataUInt8(2), 2, 16, QLatin1Char('0')); + return; + } + + + if (0 == identity || m_BroadcastISSI == issi) + { + sendLoginResponse(CoPrtCnvRadioTelegram::e_LoginReject, identity, issi); + sendFehlermeldungGefechtsfeldToCentral(identity, TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorLoginEquipmentNumber); + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: New TPU with Id=%1 and ISSI=%2 tries to use broadcast-id or -issi => rejected").arg(identity).arg(issi)); + return; + } + + const bool bIsMasteringFlag = (a_loginTelegram.getPayloadDataUInt8(2) & CoPrtCnvRadioTelegram::e_LoginMastering) == CoPrtCnvRadioTelegram::e_LoginMastering; + PrtCnvMember *member = m_DbThread->getMemberById(identity); + PrtCnvMember *issiMember = m_DbThread->getMemberByISSI(issi); + DEBUG_LOG(m_logger) << "TPU with id=" << identity << " and ISSI=" + << issi << " tries to log in, mastering: " << bIsMasteringFlag; + + if (bIsMasteringFlag && member != issiMember) + { + removeMasteringMember(a_loginTelegram, member, issiMember, identity, issi); + member = nullptr; + issiMember = nullptr; + } + + const int tpuExId = exerciseIdForIdentity(identity); + TRACE_LOG(m_logger) << "Exercise Id for EqId " << identity << " is: " << tpuExId; + + + if (member || issiMember) + { + + + if (member && (issi == uint32_t(member->m_ISSI))) + { + + + + if (member->m_Licensed) + m_DbThread->licenseMember(member, false); + m_DbThread->updateExerciseIdForMember(member, m_ExerciseId); + + sendLoginAccept(identity, issi, tpuExId, bIsMasteringFlag); + } + else + { + if (bIsMasteringFlag) + { + + m_DbThread->addMember(identity, issi); + + sendLoginAccept(identity, issi, tpuExId, bIsMasteringFlag); + sendFehlermeldungGefechtsfeldToCentral(identity, TrainingAreaBase::TetraIcd::CtaDataError::Reason::InfoLoginMasteringFlag); + } + else + { + + + int rejectCause = 0; + if (issiMember) + rejectCause |= CoPrtCnvRadioTelegram::e_LoginOtherISSI; + else if (member) + rejectCause |= CoPrtCnvRadioTelegram::e_LoginOtherEqId; + else + rejectCause |= CoPrtCnvRadioTelegram::e_LoginMastering; + rejectCause |= CoPrtCnvRadioTelegram::e_LoginReject; + + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(rejectCause), + identity, issi); + sendFehlermeldungGefechtsfeldToCentral(identity, TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorLoginEquipmentNumber); + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: Another TPU with Id=%1 and ISSI=%2 without mastering tried to log in => rejected").arg(identity).arg(issi)); + } + } + } + else + { + + + m_DbThread->addMember(identity, issi); + m_DbThread->updateExerciseIdForMember(issiMember, m_ExerciseId); + + sendLoginAccept(identity, issi, tpuExId, bIsMasteringFlag); + } +} + + + + + +void PrtCnvRadioThread::handleFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_fragmentedTelegram) +{ + PrtCnvMember *member = m_DbThread->getMemberByISSI(a_fragmentedTelegram.getSrcISSI()); + if (member) + { + if (a_fragmentedTelegram.isCrcOk()) + { + bool doAddFragment = true; + if (a_fragmentedTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment) + { + + + if (!member->isFragmentedListEmpty()) + { + ERROR_LOG(m_logger) << "Did not get the last radio-telegram-fragment"; + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + member->getFragmentedTelegramId()); + member->clearFragmentedList(); + } + } + else if (a_fragmentedTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment) + { + + + if (member->isFragmentedListEmpty()) + { + ERROR_LOG(m_logger) << "Got a lonely last radio-telegram-fragment"; + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + member->getFragmentedTelegramId()); + } + else + { + + member->addFragmentedTelegram(a_fragmentedTelegram); + const QByteArray unfragmentedRadioTelegramData = member->getUnfragmentedTelegramData(); + if (!unfragmentedRadioTelegramData.isEmpty()) + { + + + handleDataIndReq(unfragmentedRadioTelegramData, false); + } + else + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + member->getFragmentedTelegramId()); + } + member->clearFragmentedList(); + doAddFragment = false; + } + else + { + + + if (member->isFragmentedListEmpty()) + { + ERROR_LOG(m_logger) << "Did not get the first radio-telegram-fragment"; + + member->clearFragmentedList(); + doAddFragment = false; + } + } + + + if (doAddFragment) + { + member->addFragmentedTelegram(a_fragmentedTelegram); + } + } + else + ERROR_LOG(m_logger) << "CRC of received fragmented telegram is wrong => thorw away"; + } + else + ERROR_LOG(m_logger) << "Internal error: Did not found the TNE with ISSI=" << a_fragmentedTelegram.getSrcISSI() << " in member-list"; +} + + + + + +bool PrtCnvRadioThread::handleBITEEXT_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram) +{ + auto anmeldeart = static_cast(a_BITE_RadioTelegram.getPayloadDataUInt32(7, 1)); + uint32_t ergebnisCAN = a_BITE_RadioTelegram.getPayloadDataUInt32(8, 3); + uint32_t ergebnisAusstattung = a_BITE_RadioTelegram.getPayloadDataUInt8(11); + uint32_t konfigurationsvergleich = a_BITE_RadioTelegram.getPayloadDataUInt8(23); + uint32_t aktuelleKonfiguration = a_BITE_RadioTelegram.getPayloadDataUInt32(24, 3); + + QList fehlerListe; + const auto nonDynamic = getBiteError(a_BITE_RadioTelegram, 12); + if (nonDynamic.errorNumber != 0 || + nonDynamic.canDeviceNumber != 0 || + nonDynamic.subdeviceNumber != 0 || + nonDynamic.uniqueId != 0) + fehlerListe.append(nonDynamic); + + const uint8_t fehlerLen = a_BITE_RadioTelegram.getPayloadDataUInt8(19); + for (uint8_t i = 0; i < fehlerLen; ++i) + { + const uint8_t iPos = 27 + i * 7; + fehlerListe.append(getBiteError(a_BITE_RadioTelegram, iPos)); + } + + return handleBITE_Telegram(a_BITE_RadioTelegram, + anmeldeart, + ergebnisCAN, + ergebnisAusstattung, + aktuelleKonfiguration, + konfigurationsvergleich, + fehlerListe + ); +} + +bool PrtCnvRadioThread::handleBITE_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram, + TrainingAreaBase::TetraIcd::BiteReport::LoginType anmeldeart, + uint32_t ergebnisCAN, + uint32_t ergebnisAusstattung, + uint32_t aktuelleKonfiguration, + uint32_t konfigurationsvergleich, + const QList &fehlerListe + ) +{ + switch (anmeldeart) + { + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::InvalidLogin: + return true; + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::NoLogin: + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::NewLogin: + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::Relogin: + { + const uint16_t identity = a_BITE_RadioTelegram.getIdentity(); + bool doForwardBiteMeldung = true; + QString logText(QStringLiteral("Licensing: The TPU with Id=%1 and ISSI=%2").arg(identity).arg(a_BITE_RadioTelegram.getSrcISSI())); + + + PrtCnvMember *member = m_DbThread->getMemberById(identity); + if (member) + { + + + if (a_BITE_RadioTelegram.getSrcISSI() == uint32_t(member->m_ISSI)) + { + + + if (isIdentityValid(identity)) + { + m_DbThread->updateExerciseIdForMember(member, m_ExerciseId); + + if (!member->m_Licensed) + { + m_DbThread->licenseMember(member); + if (TrainingAreaBase::TetraIcd::BiteReport::LoginType::NewLogin == anmeldeart) + logText += QStringLiteral(" is now licensed"); + else + logText += QStringLiteral(" is now licensed (WIEDER_ANMELDUNG instead NEUE_ANMELDUNG used!)"); + } + else + { + if (TrainingAreaBase::TetraIcd::BiteReport::LoginType::NewLogin == anmeldeart) + logText += QStringLiteral(" is now relicensed (NEUE_ANMELDUNG instead WIEDER_ANMELDUNG used!)"); + else + logText += QStringLiteral(" is now relicensed"); + } + + N_CoPrtCnv::E_LicensingErrorCode errorCode = N_CoPrtCnv::E_LicensingErrorCode::Ok; + + if (ergebnisAusstattung != 1) + { + + errorCode = N_CoPrtCnv::E_LicensingErrorCode::Battery; + logText += QStringLiteral(", has battery-Warning"); + } + if ((ergebnisCAN & aktuelleKonfiguration) != aktuelleKonfiguration) + { + + errorCode = N_CoPrtCnv::E_LicensingErrorCode::Selftest; + logText += QStringLiteral(", but selftest is failed"); + } + if (konfigurationsvergleich != 0) + { + + errorCode = N_CoPrtCnv::E_LicensingErrorCode::Configuration; + logText += QStringLiteral(", but has configuration-failure: "); + } + bool selftestOrConfigError = (errorCode == N_CoPrtCnv::E_LicensingErrorCode::Configuration || errorCode == N_CoPrtCnv::E_LicensingErrorCode::Selftest); + bool doLicense = !(selftestOrConfigError && !m_DoLicenseDespiteSelftestOrConfigFailure); + + prepareWareHouseMessage(identity, doLicense, ergebnisCAN, ergebnisAusstattung, aktuelleKonfiguration, konfigurationsvergleich, fehlerListe); + if (anmeldeart == TrainingAreaBase::TetraIcd::BiteReport::LoginType::NoLogin) + return true; + + + sendLizenzierungTneToRadio(identity, member->m_ISSI, + doLicense ? N_CoPrtCnv::E_LicensingKind::Success : N_CoPrtCnv::E_LicensingKind::Rejected, + errorCode); + + + if (doLicense) + m_DoNeedActPosResp.insert(identity); + if (selftestOrConfigError) + sendFehlermeldungGefechtsfeldToCentral(identity, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorConfigSelfTest, + a_BITE_RadioTelegram.getTelID()); + + + + if (selftestOrConfigError && !m_DoLicenseDespiteSelftestOrConfigFailure) + { + logText = QStringLiteral("Licensing: The TPU with Id=%1 and ISSI=%2").arg(identity).arg(a_BITE_RadioTelegram.getSrcISSI()); + logText += QStringLiteral(" could not be licensed, because "); + if (errorCode == N_CoPrtCnv::E_LicensingErrorCode::Configuration) + logText += QStringLiteral("of configuration-failure"); + else + logText += QStringLiteral("selftest failed"); + } + } + else + { + + sendLizenzierungTneToRadio(identity, member->m_ISSI, N_CoPrtCnv::E_LicensingKind::Rejected, N_CoPrtCnv::E_LicensingErrorCode::IdentityDenied); + sendFehlermeldungGefechtsfeldToCentral(identity, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorSendingNamelist, + a_BITE_RadioTelegram.getTelID()); + logText += QStringLiteral(" could not be licensed because PlayerID is not allowed"); + } + } + else + { + + sendLoginResponse(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginReject, identity, a_BITE_RadioTelegram.getSrcISSI()); + logText += QStringLiteral(" could not be licensed because ISSI is wrong"); + doForwardBiteMeldung = false; + } + } + else + { + + sendLoginResponse(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginReject, identity, a_BITE_RadioTelegram.getSrcISSI()); + logText += QStringLiteral(" wants to be licensed but is not logged in"); + doForwardBiteMeldung = false; + } + writeLoginLog(a_BITE_RadioTelegram, logText); + return doForwardBiteMeldung; + } + } + ERROR_LOG(m_logger) << "BITE-Meldung contains unknown anmeldeart: " << static_cast(anmeldeart); + return true; +} + + + + + +void PrtCnvRadioThread::checkSend() +{ + + if (m_DoCleanup) + return; + if (PrtCnvSocketThread::e_WORKING != m_State) + return; + + if (isSendLimitReached()) + return; + + PrtCnvStoredRadioTelegram *handle = nullptr; + const auto radioTelegram = m_DbThread->getNextRadioTelegram(handle); + if (radioTelegram) + { + + + if (radioTelegram->isNormalTelegram()) + { + switch (radioTelegram->getTelID()) + { + case GEF_UMGEBUNGS_MELDUNG2: + { + const int exerciseId = radioTelegram->getPayloadDataUInt32(5, 2); + if (m_ExerciseId != exerciseId) + { + ERROR_LOG(m_logger) << "Started with exercise Id " << m_ExerciseId << " but got environment telegram for exercise " << exerciseId; + exit(5); + } + + if (m_ExerciseId > 0 && !m_EnvironmentTelegramTimer) + { + m_EnvironmentTelegramTimer = new QTimer(this); + connect(m_EnvironmentTelegramTimer, &QTimer::timeout, this, &PrtCnvRadioThread::timeoutEnvironmentTelegram, Qt::QueuedConnection); + } + + if (m_EnvironmentTelegramTimer) + { + INFO_LOG(m_logger) << "I got the Umgebungsmeldung-Telegram => I start now sending Umgebungsmeldung periodically"; + m_EnvironmentTelegramTimer->setInterval(m_Config->getInteger(getName(), QStringLiteral("CyclicEnvironmentTime"), 30) * 1000); + m_EnvironmentTelegramTimer->start(); + } + + radioTelegram->setPayloadDataWithIndex(7, m_DbThread->getResetCounter(), 1); + break; + } + case GEF_WIRKFELD_STATUS_MINENSPERRE: + { + uint16_t wirkfeldKennung = radioTelegram->getPayloadDataUInt32(5, 2); + if (m_BroadcastManager.isEffectSimulationIdDeactivated(wirkfeldKennung)) + { + WARNING_LOG(m_logger) << "Special Handling for GEF_WIRKFELD_STATUS_MINENSPERRE with id " << wirkfeldKennung + << " -> do not send to CTA"; + m_DbThread->radioTelegramSent(m_SendCounter, handle, 0); + return; + } + break; + } + default: + + break; + } + } + + sendTelegram(radioTelegram, handle); + + emit checkSendToRadio(); + } +} + + + + + + +void PrtCnvRadioThread::timeoutTick() +{ + + + + + + if (m_DoCleanup) return; + startTickTimer(); + + checkSend(); + if (!isSendLimitReached()) + { + time_t currentTime = time(nullptr); + auto broadcastTelegram = m_BroadcastManager.getNextBroadcastTelegramToSend(0, currentTime); + while (broadcastTelegram) + { + uint16_t broadcastIndex = broadcastTelegram->getBroadcastIndex(); + sendTelegram(broadcastTelegram, nullptr, false); + + if (isSendLimitReached()) + broadcastTelegram = nullptr; + else + broadcastTelegram = m_BroadcastManager.getNextBroadcastTelegramToSend(broadcastIndex, currentTime); + } + } + else + INFO_LOG(m_logger) << "send limit reached"; + + m_BroadcastManager.incTickAndSetTrafficLoad(E_TrafficLoad::HighLoad == m_SendLoad, E_TrafficLoad::FullLoad == m_SendLoad); + if (!isSendLimitReached()) + { + auto radioTelegram = m_BroadcastManager.getNextNachforderungTelegramToSend(); + if (radioTelegram) + sendTelegram(radioTelegram, nullptr, false); + } + + + try + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *radioInjectTelegram; + while ((radioInjectTelegram = m_InjectionThread->getNextRadioInjectionTelegram())) + { + if (radioInjectTelegram->telegramId() == TrainingAreaBase::TetraIcd::TelegramId::NACHFORDERUNG_BROADCAST_TELEGRAMME) + { + const auto tele = TrainingAreaBase::TetraIcd::RequestBroadcastTelegrams::fromJson(radioInjectTelegram->jsonData()); + onBroadcastTelegramsRequestFromCentral(tele.header.equipmentNumber, tele.broadcastIndex, tele.resetCounter); + delete radioInjectTelegram; + continue; + } + std::shared_ptr + radioTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(radioInjectTelegram)); + if (radioTelegram) + sendTelegram(radioTelegram, nullptr, false); + delete radioInjectTelegram; + } + } + catch (std::exception &e) + { + ERROR_LOG(m_logger) << "Catched an unexpected exception: " << e.what() << " => could not inject radio-telegram, but we proceed..."; + } + + + if (m_DbThread->isEnvironmentResetCounterOld()) + timeoutEnvironmentTelegram(); + computeAndLogTrafficStatistics(); +} + + + + + +void PrtCnvRadioThread::timeoutAliveAndConnection() +{ + INFO_LOG(m_logger) << "timeoutAliveAndConnection socketState=" << m_Socket->state() << " m_State=" << m_State; + switch (m_State) + { + case e_CONNECTING: + connectSocket(); + break; + case e_REGISTERING: + case e_WORKING: + break; + case e_DISCONNECTING: + m_Socket->abort(); + break; + default: + ERROR_LOG(m_logger) << "timeoutAlive for m_State=" << m_State << " not implemented"; + } +} + + + + + + + + + + + +void PrtCnvRadioThread::sendTelegram(const std::shared_ptr &a_telegram, + PrtCnvStoredRadioTelegram *a_handle, + const bool a_doCheckWhetherExpired) +{ + uint16_t broadcastIndex = 0; + + bool isSpecialTelegram = !a_telegram->isNormalTelegram(); + bool isLicensing = false; + PrtCnvMember *member = nullptr; + if (!isSpecialTelegram) + { + member = m_DbThread->getMemberById(a_telegram->getIdentity()); + isLicensing = (GEF_LIZENSIERUNG_TNE == a_telegram->getTelID()); + } + + if (member || isSpecialTelegram || isLicensing) + { + + if (!a_telegram->needsLicensing() || (member && member->m_Licensed)) + { + if (!a_telegram->hasExpired() || !a_doCheckWhetherExpired) + { + if (a_telegram->isContentValid()) + { + + if (a_telegram->mustBeFragmented()) + sendFragmentedTelegram(a_telegram); + else + broadcastIndex = sendToSocket(a_telegram); + + m_LogThread->writeRadioTelegramLog(a_telegram->data(), false, a_telegram->getPriority()); + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::WrongParameter, + a_telegram->getTelID()); + INFO_LOG(m_logger) << "Telegram with telId=" << a_telegram->getTelID() << " is invalid => thrown away"; + } + } + else + { + if (a_telegram->getBroadcastIndex() == 0) + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::TelegramOutdated, + a_telegram->getTelID()); + INFO_LOG(m_logger) << "Telegram with telId=" << a_telegram->getTelID() << " has expired => thrown away"; + } + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLicensed, + a_telegram->getTelID()); + ERROR_LOG(m_logger) << "Central tries to send a telegram with telId=" << a_telegram->getTelID() << " to TNE with id=" << a_telegram->getIdentity() << ", but the TNE is not licensed!"; + } + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLoggedIn, + a_telegram->getTelID()); + ERROR_LOG(m_logger) << "Central tries to send a telegram to TNE with id=" << a_telegram->getIdentity() << ", but the TNE is not logged in!"; + + } + + if (a_handle) + m_DbThread->radioTelegramSent(m_SendCounter, a_handle, broadcastIndex); + + if (broadcastIndex >= MAX_BROADCAST_INDEX) + { + m_BroadcastManager.handleOverrunOfBroadcastCounter(); + sendFehlermeldungGefechtsfeldToCentral(0, TrainingAreaBase::TetraIcd::CtaDataError::Reason::BroadcastCounterOverflow); + timeoutEnvironmentTelegram(); + } +} + + + + + +void PrtCnvRadioThread::doRegister() +{ + auto registerIndTelegram(std::make_shared(m_HostISSI)); + sendTelegram(registerIndTelegram, nullptr); + INFO_LOG(m_logger) << "Send Radio-Telegram Register-Ind with hostISSI=" << m_HostISSI; +} + + + + + +void PrtCnvRadioThread::registerGroups() +{ + if (m_ListenGroups.empty()) + return; + auto registerGroupIndTelegram(std::make_shared(m_HostISSI, m_ListenGroups)); + sendTelegram(registerGroupIndTelegram, nullptr); +} + + + + +void PrtCnvRadioThread::handleRegisterRsp(const uint8_t a_regsitrationStatus) +{ + INFO_LOG(m_logger) << "Got Radio-Telegram Register-Rsp with status=" << std::to_string(a_regsitrationStatus); + std::stringstream logText; + switch (a_regsitrationStatus) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered: + emit tetraConnectionState(true); + registerGroups(); + return; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DuplicateISSI: + logText << "TETRA: Register-Response: Status=Duplicate ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidISSI: + logText << "TETRA: Register-Response: Status=Invalid ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidIpAddress: + logText << "TETRA: Register-Response: Status=Invalid IP address => Configure TETRA for accepting our IP-address ("; + { + const QList ipList = QNetworkInterface::allAddresses(); + for (const QHostAddress &addr : ipList) + logText << addr.toString().toStdString() << ", "; + logText << ")..."; + } + break; + default: + logText << "Unknown registration status: " << std::to_string(a_regsitrationStatus); + break; + } + emit tetraConnectionState(false); + + FATAL_LOG(m_logger) << logText.str(); + std::cerr << logText.str() << std::endl; + exit(1); +} + +std::ostream &operator<<(std::ostream &os, const PrtCnvRadioThread::E_TrafficLoad tl) +{ + switch (tl) + { + case PrtCnvRadioThread::E_TrafficLoad::FullLoad: + os << "E_TrafficLoad::FullLoad"; + return os; + case PrtCnvRadioThread::E_TrafficLoad::HighLoad: + os << "E_TrafficLoad::HighLoad"; + return os; + case PrtCnvRadioThread::E_TrafficLoad::NormalLoad: + os << "E_TrafficLoad::NormalLoad"; + return os; + case PrtCnvRadioThread::E_TrafficLoad::Unknown: + os << "E_TrafficLoad::Unknown"; + return os; + } + Q_ASSERT(false); + os << std::to_string(static_cast(tl)); + return os; +} + + + + + + + + +bool PrtCnvRadioThread::sendAnswer(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + switch (a_radioTelegram.getTelID()) + { + case GEF_BITE_MELDUNG2: + return handleBITEEXT_Telegram(a_radioTelegram); + case GEF_DEAKTIVIERUNG_EINZELMINE: + { + + + auto radioTelegram(std::make_shared(GEF_DEAKTIVIERUNG_EINZELMINE, 13, 0)); + radioTelegram->setPayload2Byte(0); + radioTelegram->setPayloadData(a_radioTelegram.getPayloadDataPtr(5), 8); + storeRadioTelegram(radioTelegram, 0); + emit checkSendToRadio(); + break; + } + case GEF_POSITIONS_MELDUNG: + case GEF_POSITIONS_MELDUNG_LFZ: + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + case GEF_IPS_POSITIONSDATEN: + { + auto it = m_DoNeedActPosResp.find(a_radioTelegram.getIdentity()); + if (it != m_DoNeedActPosResp.end()) + { + auto radioTelegram(std::make_shared(GEF_ALLGEMEINE_NACHRICHT, 9, a_radioTelegram.getIdentity())); + radioTelegram->setPayload2Byte(0); + radioTelegram->setPayload1Byte(3); + radioTelegram->setPayload1Byte(0); + radioTelegram->setPayload2Byte(8); + storeRadioTelegram(radioTelegram, 0); + emit checkSendToRadio(); + m_DoNeedActPosResp.erase(it); + } + break; + } + default: + + break; + } + return true; +} + + + + + +uint32_t PrtCnvRadioThread::getDestinationISSI(const uint16_t a_TNE_Id) const +{ + + PrtCnvMember *member = m_DbThread->getMemberById(a_TNE_Id); + if (member) + return member->m_ISSI; + ERROR_LOG(m_logger) << "TPU with id=" << a_TNE_Id << " not logged in."; + return 0; +} + + + + + +void PrtCnvRadioThread::timeoutEnvironmentTelegram() +{ + + if (m_DoCleanup) return; + if (PrtCnvSocketThread::e_WORKING != m_State) return; + + auto envTelegram = m_DbThread->getEnvironmentTelegram(); + if (envTelegram) + { + INFO_LOG(m_logger) << "It is time to send the Umgebungsmeldung"; + sendTelegram(envTelegram, nullptr); + } + else + { + WARNING_LOG(m_logger) << "Got no Umgebungsmeldung from DB-Thread..."; + } +} + + + + + +void PrtCnvRadioThread::sendFehlermeldungGefechtsfeldToCentral(const uint16_t a_identity, + const TrainingAreaBase::TetraIcd::CtaDataError::Reason a_errorCause, + const gef_telegramm_id_et a_telegramId) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(GEF_FEHLERMELDUNG_GFD, 9, a_identity); + radioTelegram.setPayload4Byte(time(nullptr)); + radioTelegram.setPayload1Byte(static_cast(a_errorCause)); + radioTelegram.setPayload1Byte(a_telegramId); + + std::shared_ptr + centralTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(&radioTelegram)); + if (centralTelegram) + { + m_DbThread->storeCentralTelegram(centralTelegram, radioTelegram); + emit checkSendToCentral(); + } +} + + + + + +void PrtCnvRadioThread::writeLoginLog(uint32_t identity, uint32_t issi, const QString &a_prosaText) +{ + const QDateTime dtCur(QDateTime::currentDateTimeUtc()); + QString txt = + QString::number(dtCur.toSecsSinceEpoch()) + QLatin1Char(';') + + QString::number(issi) + QLatin1Char(';') + + QString::number(identity) + QLatin1Char(';') + + QLatin1Char(';') + + a_prosaText + QLatin1Char(';') + dtCur.toString(); + writeLoginLog(nullptr, txt); +} + +void PrtCnvRadioThread::writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram, const QString &a_prosaText) +{ + writeLoginLog(&a_radioTelegram, a_prosaText); +} + +void PrtCnvRadioThread::writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const QString &a_prosaText) +{ + QByteArray logData; + if (a_radioTelegram) + { + + int len = 3; + if (a_radioTelegram->getTelID() == GEF_BITE_MELDUNG2) + len = 27; + QStringList sl; + sl.reserve(len); + for (int i = 0; i < len; i++) + { + uint8_t data = a_radioTelegram->getPayloadDataUInt8(i); + sl += QStringLiteral("0x%1").arg(data, 2, 16, QLatin1Char('0')); + } + + const QDateTime dtCur(QDateTime::currentDateTimeUtc()); + + logData = + QByteArray::number(dtCur.toSecsSinceEpoch()) + ";" + + QByteArray::number(a_radioTelegram->getSrcISSI()) + ";" + + QByteArray::number(a_radioTelegram->getIdentity()) + ";" + + sl.join(QLatin1Char(',')).toUtf8() + ";" + + a_prosaText.toUtf8() + ";" + dtCur.toString().toUtf8(); + } + else + { + logData = a_prosaText.toUtf8(); + } + logData += "\n"; + + INFO_LOG(m_logger) << logData; + + + QString date = QDate::currentDate().toString(QLatin1String("yyyyMMdd")); + QString fileName = m_LoginPathWithPrefix + date + QLatin1Char('_') + QString::number(m_ExerciseId) + QLatin1String(".log"); + + + QFile file(fileName); + file.open(QIODevice::Append); + file.write(logData); + file.close(); +} + + + + + +void PrtCnvRadioThread::sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, + const uint16_t a_identity, const uint32_t a_ISSI) +{ + auto answerTelegram(std::make_shared(a_loginTelegramStatus, a_identity, a_ISSI)); + storeRadioTelegram(answerTelegram, 0); + emit checkSendToRadio(); +} + +void PrtCnvRadioThread::sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, + const uint16_t a_identity, const uint32_t a_ISSI, const TrainingAreaBase::TetraIcd::GroupIssiInformation &group) +{ + using namespace N_CoPrtCnv; + + auto answerTelegram(std::make_shared(a_loginTelegramStatus, a_identity, a_ISSI)); + if ((a_loginTelegramStatus & CoPrtCnvRadioTelegram::e_LoginOtherExercise) == CoPrtCnvRadioTelegram::e_LoginOtherExercise) + { + NOTICE_LOG(m_logger) << "sendLoginResponse for " << a_identity << " with issi " << a_ISSI + << " and groups " << group.serverIssi << "/" << group.broadcastIssi1 + << "/" << group.broadcastIssi2; + answerTelegram->setLoginIssis(group.serverIssi, group.broadcastIssi1, group.broadcastIssi2); + } + storeRadioTelegram(answerTelegram, 0); + emit checkSendToRadio(); +} + + + + + + + +void PrtCnvRadioThread::sendLizenzierungTneToRadio(const uint16_t a_identity, const uint32_t a_issi, + const N_CoPrtCnv::E_LicensingKind a_licensingKind, + const N_CoPrtCnv::E_LicensingErrorCode a_errorCause) +{ + auto radioTelegram(std::make_shared(GEF_LIZENSIERUNG_TNE, 7, a_identity)); + radioTelegram->setPayload1Byte(static_cast(a_licensingKind)); + radioTelegram->setPayload1Byte(static_cast(a_errorCause)); + radioTelegram->setPayload2Byte(0x0013); + radioTelegram->setDestISSI(a_issi); + storeRadioTelegram(radioTelegram, 0); + emit checkSendToRadio(); + emit playerLicencedChanged(a_identity, a_licensingKind); +} + + + + + + +void PrtCnvRadioThread::initIdentityArray() +{ + const QString loginGroup(QStringLiteral("login")); + + if (m_Config->getBoolean(loginGroup, QStringLiteral("DoCheckPlayerId"), true)) + { + + m_AllowedIdentities.clear(); + + QString identifyFileName = m_Config->getString(loginGroup, QStringLiteral("PlayerIdFilePath"), QString()); + if (identifyFileName.isEmpty()) + { + + uint32_t lowest = m_Config->getInteger(loginGroup, QStringLiteral("LowestPlayerId"), 1); + uint32_t highest = m_Config->getInteger(loginGroup, QStringLiteral("HighestPlayerId"), MAX_IDENTITY); + for (uint32_t i = lowest; i <= highest; i++) + setIdentityVaild(i); + INFO_LOG(m_logger) << "PlayerIds from " << lowest << " .. " << highest << " will be used."; + } + else + { + + INFO_LOG(m_logger) << "PlayerId-file '" << identifyFileName << "' will be used."; + + + QString path = identifyFileName; + if (!QDir::isAbsolutePath(path)) + path = QCoreApplication::applicationDirPath() + QLatin1Char('/') + path; + + + QFile file(path); + if (file.open(QIODevice::ReadOnly)) + { + uint32_t lineCount = 0; + while (!file.atEnd()) + { + lineCount++; + QByteArray line(file.readLine()); + int hashPos = line.indexOf('#'); + if (-1 != hashPos) + line = line.left(hashPos); + if (!line.trimmed().isEmpty()) + { + int pos = line.indexOf('-'); + if (-1 == pos) + { + + setIdentityVaild(readIdentity(line, lineCount, identifyFileName)); + } + else + { + + QByteArray playerId = line.left(pos).trimmed(); + uint16_t left = readIdentity(playerId, lineCount, identifyFileName); + playerId = line.right(line.length() - pos - 1).trimmed(); + uint16_t right = readIdentity(playerId, lineCount, identifyFileName); + for (int i = left; i <= right; i++) + setIdentityVaild(i); + } + } + } + file.close(); + } + else + { + ERROR_LOG(m_logger) << "Could not open the PlayerId-file '" << identifyFileName << "'!"; + std::cout << std::endl << "Error: Could not open the PlayerId-file '" << qPrintable(identifyFileName) << "'!" << std::endl; + exit(-1); + } + } + } + else + { + + for (uint32_t i = 0; i <= MAX_IDENTITY; i++) + setIdentityVaild(i); + } +} + + + + + + +uint16_t PrtCnvRadioThread::readIdentity(const QByteArray &a_idAsText, const uint32_t a_line, const QString &a_fileName) +{ + ulong playerId = a_idAsText.toULong(); + if (0 == playerId || playerId > MAX_IDENTITY) + { + + if (0 == playerId) + { + FATAL_LOG(m_logger) << a_fileName << ":" << a_line << ": could not read playerID - '" + << a_idAsText << "'"; + } + else + { + FATAL_LOG(m_logger) << a_fileName << ":" << a_line << ": PlayerID too big - '" + << a_idAsText << "'"; + } + exit(1); + } + return playerId; +} + + + + + +bool PrtCnvRadioThread::isIdentityValid(uint16_t a_identity) const +{ + return m_AllowedIdentities.find(a_identity) != m_AllowedIdentities.end(); +} + + + + +void PrtCnvRadioThread::setIdentityVaild(uint16_t a_identity) +{ + m_AllowedIdentities.insert(a_identity); +} + + + + +void PrtCnvRadioThread::sendFragmentedTelegram(const std::shared_ptr &a_telegram) +{ + + uint8_t fragmentCounter = 0; + N_CoPrtCnv::CoPrtCnvRadioTelegram::E_FragmentStatus fragmentStatus; + do + { + bool error = false; + auto fragmentedTelegram(std::make_shared(a_telegram, fragmentCounter++, error)); + if (!error) + { + fragmentedTelegram->setDestISSI(getDestinationISSI(a_telegram->getIdentity())); + + sendTelegram(fragmentedTelegram, nullptr); + fragmentStatus = fragmentedTelegram->getFragmentStatus(); + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + a_telegram->getTelID()); + return; + } + } + while (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment != fragmentStatus); +} + + + + + + +uint16_t PrtCnvRadioThread::sendToSocket(const std::shared_ptr &a_telegram) +{ + + if (++m_SendCounter >= END_COUNTER) + m_SendCounter = START_COUNTER; + a_telegram->setZaehler(m_SendCounter); + + a_telegram->setSrcISSI(m_HostISSI); + uint16_t broadcastIndex = 0; + gef_telegramm_id_et telId = a_telegram->isNormalTelegram() ? a_telegram->getTelID() : GEF_BESTAETIGUNG; + if (a_telegram->isNormalTelegram()) + { + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq == a_telegram->getPDU_Type()) + { + if (GEF_LIZENSIERUNG_TNE != a_telegram->getTelID()) + a_telegram->setDestISSI(getDestinationISSI(a_telegram->getIdentity())); + } + if (GEF_TEILNEHMERMODE_SETZEN == telId && a_telegram->getDestISSI() != m_BroadcastISSI) + { + DEBUG_LOG(m_logger) << "Got MODE with bci: " << a_telegram->getBroadcastIndex(); + if (a_telegram->getBroadcastIndex()<= 0) + a_telegram->setBroadcastIndex(m_BroadcastManager.getBroadcastIndex()); + DEBUG_LOG(m_logger) << "MODE with bci is now: " << a_telegram->getBroadcastIndex(); + } + + if (GEF_UMGEBUNGS_MELDUNG2 == telId) + { + + a_telegram->setBroadcastIndex(m_BroadcastManager.getBroadcastIndex()); + a_telegram->setPayloadDataWithIndex(7, m_DbThread->getResetCounter(), 1); + a_telegram->setPayloadDataWithIndex(8, m_DbThread->getBattleFieldOperatingState(), 1); + a_telegram->setPayloadDataWithIndex(16, (uint32_t)time(nullptr), 4); + m_DbThread->setResetCounterOnEnvironment(); + } + else + { + + + if (GEF_INIT != telId && + a_telegram->mustBroadcastBeSet()) + { + broadcastIndex = m_BroadcastManager.getNextBroadcastIndex(); + a_telegram->setBroadcastIndex(broadcastIndex); + } + } + a_telegram->fixupTelegramIdForEts(true); + } + + + DEBUG_LOG(m_logger) << "Send telegram to radio: telId=" << telId << " wcounter=" << int(a_telegram->zaehler()) << " size=" << a_telegram->getSize(); + if (m_DoUseSDSTL && N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq == a_telegram->getPDU_Type()) + { + a_telegram->setProtocolIdentifier(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_SimpleTextMessagingUsingSDS_TL); + a_telegram->setMessageReference(telId); + } + + if (m_DoDumpSentTelegrams) + { + INFO_LOG(m_logger) << "Send radio-telegram with size " << a_telegram->getSize() + << " and payload size " << a_telegram->getPayloadSize(); + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, a_telegram->data()); + } + + Q_ASSERT(QThread::currentThreadId() == m_currentThreadId); + + if (m_bUseScrambling && a_telegram->getPDU_Type() == N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type::e_DataIndReq) + sendScrambledContent(a_telegram); + else + m_Socket->write(a_telegram->data()); + + + m_SentTelegrams++; + m_SentBytes += a_telegram->getSize(); + + if (a_telegram->isNormalTelegram()) + a_telegram->fixupTelegramIdForEts(false); + return broadcastIndex; +} + + +static inline void scramble(const unsigned char *dataIn, unsigned char *dataOut, size_t len, uint32_t initial, uint32_t polynom) +{ + uint32_t lfsr = initial; + for (size_t j = 0; j < len; ++j) + { + for (int i = 0; i < 8; ++i) + { + unsigned char lsbBit = (lfsr & 0x01); + lfsr >>= 1; + if (lsbBit) + lfsr ^= polynom; + } + dataOut[len - j - 1] = dataIn[len - j - 1] ^ static_cast(lfsr); + } +} + + +void PrtCnvRadioThread::sendScrambledContent(const std::shared_ptr &a_telegram) const +{ + const uint32_t initial = (a_telegram->getSrcISSI() % 0xFFFF) + 1; + constexpr uint32_t polynom = 0x8016; + unsigned char dataOut[N_CoPrtCnv::CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH]; + const uint32_t payloadOffset = N_CoPrtCnv::CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH - 1; + const uint32_t scrambleLen = a_telegram->getSize() - payloadOffset; + const unsigned char *dataIn = reinterpret_cast(a_telegram->getData() + payloadOffset); + + scramble(dataIn, dataOut, scrambleLen, initial, polynom); + + QByteArray tmp (reinterpret_cast(dataOut), scrambleLen); + + DEBUG_LOG(m_logger) << "Raw scrambled data: " << tmp.toHex(' '); + + m_Socket->write(a_telegram->getData(), payloadOffset); + m_Socket->write(reinterpret_cast(dataOut), scrambleLen); +} + + +bool PrtCnvRadioThread::unscrambleContent(N_CoPrtCnv::CoPrtCnvRadioTelegram &a_telegram) const +{ + const uint32_t initial = (a_telegram.getSrcISSI() % 0xFFFF) + 1; + constexpr uint32_t polynom = 0x8016; + const uint32_t payloadOffset = N_CoPrtCnv::CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH - 1; + const uint32_t scrambleLen = a_telegram.getSize() - payloadOffset; + unsigned char *dataIn = reinterpret_cast(a_telegram.getData() + payloadOffset); + unsigned char dataOut[N_CoPrtCnv::CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH]; + + if (scrambleLen > N_CoPrtCnv::CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH) + { + ERROR_LOG(m_logger) << "Telegram length does not match - can't unscramble content, len: " << scrambleLen; + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Error, a_telegram.data()); + Q_ASSERT(false); + return false; + } + + + + + scramble(dataIn, dataOut, scrambleLen, initial, polynom); + + memcpy(dataIn, dataOut, scrambleLen); + + + + + return true; +} + + + + + +void PrtCnvRadioThread::handleReportIndReq(const QByteArray &data) +{ + const uint8_t *a_data = reinterpret_cast(data.data()); + + uint32_t srcISSI = *(uint32_t *)&a_data[5]; + uint32_t destISSI = *(uint32_t *)&a_data[9]; + if (m_HostISSI == destISSI) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report delivery = (N_CoPrtCnv::CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report)a_data[16]; + switch (delivery) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DeliveryFailed: + { + uint8_t messageReference = a_data[14]; + uint16_t identity = 0; + PrtCnvMember *member = m_DbThread->getMemberByISSI(srcISSI); + if (member) + identity = member->m_Id; + sendFehlermeldungGefechtsfeldToCentral(identity, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorSendingToExerciseControl, + static_cast(messageReference)); + break; + } + default: + ERROR_LOG(m_logger) << "reaction to delivery " << (int)a_data[16] << " not implemented"; + break; + } + } + else + ERROR_LOG(m_logger) << "Radio-Ack-Telegram from " << srcISSI << " is for another host: " << destISSI << " (we are " << m_HostISSI << ")"; +} + +void PrtCnvRadioThread::prepareWareHouseMessage(qint32 equipNr, bool doLicence, qint64 ergebnisCAN, qint64 ergebnisAusstattung, qint64 aktuelleKonfiguration, qint64 konfigurationsvergleich, const QList &fehlerListe) +{ + QJsonObject obj; + obj.insert(QStringLiteral("equipNo"), equipNr); + obj.insert(QStringLiteral("doLicence"), doLicence); + obj.insert(QStringLiteral("biteState"), ergebnisCAN); + obj.insert(QStringLiteral("batteryState"), ergebnisAusstattung); + obj.insert(QStringLiteral("configState"), aktuelleKonfiguration); + obj.insert(QStringLiteral("configError"), konfigurationsvergleich); + QJsonArray errorArr; + + for (const auto &error: fehlerListe) + { + QJsonObject errorObj; + errorObj.insert(QStringLiteral("errorNumber"), error.errorNumber); + errorObj.insert(QStringLiteral("canDeviceNumber"), error.canDeviceNumber); + errorObj.insert(QStringLiteral("subdeviceNumber"), error.subdeviceNumber); + errorObj.insert(QStringLiteral("uniqueId"), error.uniqueId); + errorArr.append(errorObj); + } + obj.insert(QStringLiteral("biteError"), errorArr); + + + QJsonDocument doc(obj); + emit warehouseMessageFromPtrCnv(doc.toJson()); +} + + + + + +void PrtCnvRadioThread::handleStatusIndReq(const QByteArray &data) +{ + const uint8_t *a_data = reinterpret_cast(data.data()); + uint32_t srcISSI = *(uint32_t *)&a_data[5]; + uint32_t dstISSI = *(uint32_t *)&a_data[9]; + uint16_t status = *(uint16_t *)&a_data[13]; + INFO_LOG(m_logger) << "Received Status from " << srcISSI << " for " + << dstISSI << " - status: " << status; +} + + + + +void PrtCnvRadioThread::handleAirInterfaceLoadReq(const QByteArray &data) +{ + const uint8_t *a_data = reinterpret_cast(data.data()); + + + uint16_t nbrOfReports = *(uint16_t *)&a_data[5]; + INFO_LOG(m_logger) << "Number of AirInterface-reports: " << nbrOfReports; + + uint16_t sdsQueueLength = 0; + uint16_t index = 7; + for (int i = 0; i < nbrOfReports; i++) + { + uint8_t networkIndex = a_data[index++]; + uint16_t baseStationID = *(uint16_t *)&a_data[index]; + index += 2; + uint8_t channelID = a_data[index++]; + uint8_t queueLength = a_data[index++]; + INFO_LOG(m_logger) << "AirInterface-report[" << i << "]: networkIndex=" << (int)networkIndex << " baseStationID=" << baseStationID << " channelID=" << (int)channelID << " queueLength=" << (int)queueLength; + if (1 == networkIndex) + sdsQueueLength = queueLength; + } + E_TrafficLoad newLoad; + + if (sdsQueueLength > m_SendQueueFullLoad) + { + newLoad = E_TrafficLoad::FullLoad; + INFO_LOG(m_logger) << "Set send-load to Full"; + } + else if (sdsQueueLength > m_SendQueueHighLoad) + { + newLoad = E_TrafficLoad::HighLoad; + INFO_LOG(m_logger) << "Set send-load to High"; + } + else + { + newLoad = E_TrafficLoad::NormalLoad; + INFO_LOG(m_logger) << "Set send-load to Normal"; + } + + m_SendLoad = newLoad; +} + + + + +void PrtCnvRadioThread::computeAndLogTrafficStatistics() +{ + if (++m_TickCounter >= m_TicksPerSecond) + { + m_TickCounter = 0; + m_SentBytesAverage[m_AverageIndex] = m_SentBytes; + m_ReceivedBytesAverage[m_AverageIndex] = m_ReceivedBytes; + if (++m_AverageIndex >= AVERAGE_COUNT) m_AverageIndex = 0; + uint32_t sendAverage = 0; + uint32_t receiveAverage = 0; + for (int i = 0; i < AVERAGE_COUNT; i++) + { + sendAverage += m_SentBytesAverage[i]; + receiveAverage += m_ReceivedBytesAverage[i]; + } + DEBUG_LOG(m_loggerStats) << "Send-Statistics: " << m_SentTelegrams << " telegrams (" << m_SentBytes << "/" << sendAverage << " bytes) sent; " << (sendAverage / 10) << " kB/s"; + DEBUG_LOG(m_loggerStats) << "Receive-Statistics: " << m_ReceivedTelegrams << " telegrams (" << m_ReceivedBytes << "/" << receiveAverage << " bytes) received; " << (receiveAverage / 10) << " kB/s"; + m_SentBytes = 0; + m_SentTelegrams = 0; + m_ReceivedBytes = 0; + m_ReceivedTelegrams = 0; + } +} + + + + + + + +bool PrtCnvRadioThread::isSendLimitReached() const +{ + switch (m_SendLoad) + { + case E_TrafficLoad::NormalLoad: + return m_SentTelegrams >= m_SendTelegramsNormalLoad; + case E_TrafficLoad::HighLoad: + return m_SentTelegrams >= m_SendTelegramsHighLoad; + case E_TrafficLoad::FullLoad: + return m_SentTelegrams >= m_SendTelegramsFullLoad; + case E_TrafficLoad::Unknown: + return false; + } + Q_ASSERT(false); + return false; +} + + + + + +void PrtCnvRadioThread::sendEnvironmentTelegramTimerNow() +{ + + QTimer::singleShot(0, this, &PrtCnvRadioThread::onSendEnvironmentTelegramTimerNow); +} + +void PrtCnvRadioThread::onSendEnvironmentTelegramTimerNow() +{ + if (!m_EnvironmentTelegramTimer || !m_EnvironmentTelegramTimer->isActive()) + return; + timeoutEnvironmentTelegram(); +} + +template +void removeFromContainer(T &cont, int id) +{ + auto it = cont.find(id); + if (it != cont.end()) + cont.erase(it); +} + +void PrtCnvRadioThread::exerciseEquipmentChanged(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data) +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + m_exerciseEquipmentAssignments = data.exerciseEquipmentAssignments; + for (const auto &info : data.groupIssiInformation) + m_groupIssiInformation[info.exerciseId] = info; + + emit checkMemberForValidLogin(-1, -1); +} + +void PrtCnvRadioThread::onCheckMemberForValidLogin(int identity, int issi) +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + if (identity == -1) + { + const auto knownIdentities = m_DbThread->getClaimStatistics(); + for (const auto &p : knownIdentities) + { + if (p.first <= 0) + continue; + onCheckMemberForValidLogin(p.first, -1); + } + } + else + { + if (isIdentityInCurrentExercise(identity)) + { + DEBUG_LOG(m_logger) << "onCheckMemberForValidLogin: eqid: " << identity << " is in current exercise " << m_ExerciseId; + return; + } + PrtCnv::PrtCnvMember *member = m_DbThread->getMemberById(identity); + if (!member) + return; + issi = member->m_ISSI; + + const int newExerciseId = exerciseIdForIdentity(identity); + if (newExerciseId != 0 && newExerciseId != member->m_loggedInExerciseId) + sendLoginAccept(identity, issi, newExerciseId, false); + } +} + +void PrtCnvRadioThread::sendLoginAccept(int identity, int issi, int exerciseId, bool bWithMastering) +{ + using namespace N_CoPrtCnv; + auto response = 0; + if (bWithMastering) + response |= CoPrtCnvRadioTelegram::e_LoginMastering; + + PrtCnvMember *member = m_DbThread->getMemberById(identity); + const auto it = m_groupIssiInformation.find(exerciseId); + if (it == m_groupIssiInformation.end() || exerciseId == 0) + { + + QString log; + if (exerciseId == 0) + log = QStringLiteral("Denied Login of TPU with Id=%1 and ISSI=%2 - Id is not assigned in any exercise.") + .arg(identity).arg(issi); + else + log = QStringLiteral("TPU with Id=%1 and ISSI=%2 should be in exercise %3 but could not find valid group information for this exercise!") + .arg(identity).arg(issi).arg(exerciseId); + if (bWithMastering) + log += QStringLiteral(" Mastering-Bit is set"); + WARNING_LOG(m_logger) << log; + writeLoginLog(identity, issi, log); + if (m_ExerciseId != exerciseId) + response |= CoPrtCnvRadioTelegram::e_LoginNoExerciseAssignment; + response |= CoPrtCnvRadioTelegram::e_LoginReject; + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(response), identity, issi); + if (m_ExerciseId == 0) + m_DbThread->updateExerciseIdForMember(member, exerciseId); + else + m_DbThread->removeMember(member); + return; + } + + const TrainingAreaBase::TetraIcd::GroupIssiInformation &gi = it->second; + QString log; + if (m_ExerciseId != exerciseId) + log = QStringLiteral("TPU with Id=%1 and ISSI=%2 should switch to exercise %3 (%4/%5).") + .arg(identity).arg(issi).arg(exerciseId).arg(gi.broadcastIssi1).arg(gi.broadcastIssi2); + else + log = QStringLiteral("(Re)Login of TPU with Id=%1 and ISSI=%2.") + .arg(identity).arg(issi); + if (bWithMastering) + log += QStringLiteral(" Mastering-Bit is set"); + DEBUG_LOG(m_logger) << log; + writeLoginLog(identity, issi, log); + + if (m_ExerciseId != exerciseId) + response |= CoPrtCnvRadioTelegram::e_LoginOtherExercise; + response |= CoPrtCnvRadioTelegram::e_LoginAccept; + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(response), identity, issi, gi); + if (m_ExerciseId == 0) + m_DbThread->updateExerciseIdForMember(member, exerciseId); +} + +bool PrtCnvRadioThread::isIdentityInCurrentExercise(int identity) const +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + if (m_exerciseEquipmentAssignments.empty()) + return true; + const auto it = m_exerciseEquipmentAssignments.find(m_ExerciseId); + if (it == m_exerciseEquipmentAssignments.end()) + return false; + const auto itIdentity = it->second.find(identity); + return (itIdentity != it->second.end()); +} + +int PrtCnvRadioThread::exerciseIdForIdentity(int identity) const +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + for (const auto &s : m_exerciseEquipmentAssignments) + { + auto it = s.second.find(identity); + if (it != s.second.end()) + return s.first; + } + return 0; +} + +void PrtCnvRadioThread::removeMasteringMember(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram, + PrtCnvMember *member, + PrtCnvMember *issiMember, + int masterIdentity, + int masterIssi) +{ + using namespace N_CoPrtCnv; + + + if (member) + { + m_DbThread->updateExerciseIdForMember(member, 0); + + if (member->m_Licensed) + { + sendLizenzierungTneToRadio(member->m_Id, member->m_ISSI, N_CoPrtCnv::E_LicensingKind::Unlicense, N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + INFO_LOG(m_logger) << "Unlicense TPU with already used ID. Id=" + << member->m_Id << " ISSI=" << member->m_ISSI; + } + + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(CoPrtCnvRadioTelegram::e_LoginReject | CoPrtCnvRadioTelegram::e_LoginOtherEqId), + member->m_Id, member->m_ISSI); + INFO_LOG(m_logger) << "Reject TPU with already used ID. Id=" + << member->m_Id << " ISSI=" << member->m_ISSI; + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: TPU with Id=%1 and ISSI=%2 was removed from TETRA due to Mastering-Bit from Id=%3 and ISSI=%4") + .arg(member->m_Id).arg(member->m_ISSI).arg(masterIdentity).arg(masterIssi)); + m_DbThread->removeMember(member); + } + + + if (issiMember) + { + m_DbThread->updateExerciseIdForMember(issiMember, 0); + + if (issiMember->m_Licensed) + { + sendLizenzierungTneToRadio(issiMember->m_Id, issiMember->m_ISSI, N_CoPrtCnv::E_LicensingKind::Unlicense, N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + INFO_LOG(m_logger) << "Unlicense TPU with already used ISSI. Id=" + << issiMember->m_Id << " ISSI=" << issiMember->m_ISSI; + } + + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(CoPrtCnvRadioTelegram::e_LoginReject | CoPrtCnvRadioTelegram::e_LoginOtherISSI), + issiMember->m_Id, issiMember->m_ISSI); + INFO_LOG(m_logger) << "Reject TPU with already used ISSI. Id=" + << issiMember->m_Id << " ISSI=" << issiMember->m_ISSI; + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: TPU with Id=%1 and ISSI=%2 was removed from TETRA due to Mastering-Bit from Id=%3 and ISSI=%4") + .arg(issiMember->m_Id).arg(issiMember->m_ISSI).arg(masterIdentity).arg(masterIssi)); + m_DbThread->removeMember(issiMember); + } +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioThread.hpp b/TetraIF/PrtCnv/PrtCnvRadioThread.hpp new file mode 100644 index 000000000..94dfaae1b --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioThread.hpp @@ -0,0 +1,419 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvSocketThread.hpp" +#include "PrtCnvBroadcastMgr.hpp" +#include +#include +#include +#include +#include + +#define MAX_IDENTITY 65535 + +namespace PrtCnv +{ +struct BiteError +{ + int errorNumber = 0; + int canDeviceNumber = 0; + int subdeviceNumber = 0; + int uniqueId = 0; +}; + + class PrtCnvCentralThread; + class PrtCnvMember; + class PrtCnvRadioTrafficThread; + class PrtCnvStoredRadioTelegram; + + + class PrtCnvRadioThread : public PrtCnv::PrtCnvSocketThread + { + Q_OBJECT + +public: + + PrtCnvRadioThread(int exerciseId, PrtCnvThreadStarter* a_parent); + + + int32_t create(NGL::Settings *settings) override; + + + int32_t destroy() override; + + + int32_t init() override; + + + int32_t start() override; + + + + void prepareCleanUp(); + + + + void sendEnvironmentTelegramTimerNow(); + + void exerciseEquipmentChanged(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data); + protected: + void onCheckMemberForValidLogin(int identity, int issi); + void sendLoginAccept(int identity, int issi, int exerciseId, bool bWithMastering); + bool isIdentityInCurrentExercise(int identity) const; + int exerciseIdForIdentity(int identity) const; + void removeMasteringMember(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram, PrtCnvMember *member, + PrtCnvMember *issiMember, + int masterIdentity, + int masterIssi); + + protected: + + + PrtCnvCentralThread *m_CentralThread; + + + + PrtCnvRadioTrafficThread *m_radioTrafficThread; + +public: + + Q_SIGNALS: + + + void checkSendToCentral(); + + + void checkSendToRadio(); + + + void cleant(); + + + void stopped(); + + + + void checkMemberForValidLogin(int identity, int issi); + + + + void tetraConnectionState(bool connected); + + + void areaEffectSimulationActivated(int wirkfeldKennung); + void areaEffectSimulationDeactivated(int wirkfeldKennung); + + + void initDone(); + + + void playerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind); + void warehouseMessageFromPtrCnv(const QByteArray &jsonData); + protected: + + + uint32_t m_SendCounter; + + + uint32_t m_HostISSI; + + + const uint32_t START_COUNTER; + + + const uint32_t END_COUNTER; + + + QTimer *m_EnvironmentTelegramTimer; + + + uint32_t m_BroadcastISSI; + + + QString m_LoginPathWithPrefix; + + + int m_ExerciseId; + + + std::set m_AllowedIdentities; + + + bool m_DoLicenseDespiteSelftestOrConfigFailure; + + + bool m_DoCheckIdentity; + PrtCnvBroadcastMgr m_BroadcastManager; + + + bool m_DoDumpReceivedTelegrams; + + + bool m_DoDumpSentTelegrams; + + + bool m_DoUseSDSTL; + + + + std::set m_DoNeedActPosResp; + + + + uint32_t m_EmergencyCallISSI; + + + + void sendTelegram(const std::shared_ptr &a_telegram, + PrtCnvStoredRadioTelegram *a_handle, + const bool a_doCheckWhetherExpired = true); + + + + + void doRegister(); + + + + void registerGroups(); + + + + void handleRegisterRsp(const uint8_t a_regsitrationStatus); + + public: + + + + enum class E_TrafficLoad + { + Unknown = -1, + NormalLoad = 0, + HighLoad, + FullLoad + }; + protected: + + + N_CoPrtCnv::CoPrtCnvRadioTelegram *m_EnvironmentTelegram; + + + + E_TrafficLoad m_SendLoad; + + uint32_t m_SendQueueFullLoad; + uint32_t m_SendQueueHighLoad; + uint32_t m_SendTelegramsNormalLoad; + uint32_t m_SendTelegramsHighLoad; + uint32_t m_SendTelegramsFullLoad; + + + uint32_t m_SentTelegrams; + + + uint32_t m_SentBytes; + + + uint32_t m_TickCounter; + + + uint32_t m_TicksPerSecond; + + + static const int AVERAGE_COUNT = 10; + + + uint32_t m_SentBytesAverage[AVERAGE_COUNT]; + + + uint8_t m_AverageIndex; + + + uint32_t m_ReceivedTelegrams; + + + uint32_t m_ReceivedBytes; + + + uint32_t m_ReceivedBytesAverage[AVERAGE_COUNT]; + + + + std::set m_ListenGroups; + + + + bool m_bUseScrambling; + + + NGL::INGLLogger &m_loggerStats; + + + std::unordered_map> m_exerciseEquipmentAssignments; + std::unordered_map m_groupIssiInformation; + mutable QMutex m_exerciseEquipmentAssignmentMutex; + + private: + + + bool sendAnswer(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + void handleReceivedTelegram(const QByteArray &data); + + + void handleDataIndReq(const QByteArray &data, bool bIsMaybeScrambled); + + + void handleLoginTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram); + + + void handleFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_fragmentedTelegram); + + + void sendFehlermeldungGefechtsfeldToCentral(const uint16_t a_identity, + const TrainingAreaBase::TetraIcd::CtaDataError::Reason a_errorCause, + const gef_telegramm_id_et a_telegramId = GEF_BESTAETIGUNG); + + + uint32_t getDestinationISSI(const uint16_t a_TNE_Id) const; + + + bool handleBITEEXT_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram); + bool handleBITE_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram, + TrainingAreaBase::TetraIcd::BiteReport::LoginType anmeldeart, + uint32_t ergebnisCAN, + uint32_t ergebnisAusstattung, + uint32_t aktuelleKonfiguration, + uint32_t konfigurationsvergleich, + const QList &fehlerListe + ); + + + + void sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, const uint32_t a_ISSI); + void sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, + const uint16_t a_identity, const uint32_t a_ISSI, const TrainingAreaBase::TetraIcd::GroupIssiInformation &group); + + + + void sendLizenzierungTneToRadio(const uint16_t a_identity, const uint32_t a_issi, + const N_CoPrtCnv::E_LicensingKind a_licensingKind, + const N_CoPrtCnv::E_LicensingErrorCode a_errorCause); + + + + void writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram, const QString &a_prosaText); + void writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const QString &a_prosaText); + void writeLoginLog(uint32_t identity, uint32_t issi, const QString &a_prosaText); + + + void initIdentityArray(); + + + uint16_t readIdentity(const QByteArray& a_idAsText, const uint32_t a_line, const QString& a_fileName); + + + bool isIdentityValid(uint16_t a_identity) const; + + + + void setIdentityVaild(uint16_t a_identity); + + + + void sendFragmentedTelegram(const std::shared_ptr &a_telegram); + + + + uint16_t sendToSocket(const std::shared_ptr &a_telegram); + + + + void handleReportIndReq(const QByteArray &data); + void prepareWareHouseMessage(qint32 equipNr, + bool doLicence, + qint64 ergebnisCAN, + qint64 ergebnisAusstattung, + qint64 aktuelleKonfiguration, + qint64 konfigurationsvergleich, + const QList &fehlerListe); + + protected Q_SLOTS: + + + void onSendEnvironmentTelegramTimerNow(); + + + void timeoutAliveAndConnection() override; + + + void timeoutTick() override; + + + void checkSend(); + + + void readyRead() override; + + + void disconnected() override; + + + void connected() override; + + + void timeoutEnvironmentTelegram(); + + + void doClean(); + + + void doStart(); + + + void doStop(); + + + + void onBroadcastTelegramsRequestFromCentral(int equipmentNumber, int broadcastIndex, int resetCounter); + + private: + + + void handleStatusIndReq(const QByteArray &data); + + + + void handleAirInterfaceLoadReq(const QByteArray &data); + + + + void computeAndLogTrafficStatistics(); + + + + bool isSendLimitReached() const; + + + void sendScrambledContent(const std::shared_ptr &a_telegram) const; + bool unscrambleContent(N_CoPrtCnv::CoPrtCnvRadioTelegram &a_telegram) const; + + + friend class PrtCnvCentralThread; + }; + + std::ostream &operator<<(std::ostream &os, const PrtCnvRadioThread::E_TrafficLoad tl); +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp new file mode 100644 index 000000000..78359487f --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + +#include "PrtCnvRadioTrafficThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include +#include +#include +#include + +namespace PrtCnv +{ + +PrtCnvRadioTrafficThread::PrtCnvRadioTrafficThread(PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvRadioTrafficThread") + , m_receiveLoad(PrtCnvRadioThread::E_TrafficLoad::Unknown) + , m_fullLoad(100) + , m_highLoad(50) + , m_hystLoad(5) + , m_calcTimeout(1000) + , m_cleanupTimeout(5000) + , m_mutex(QMutex::Recursive) +{} + +void PrtCnvRadioTrafficThread::newTelegramArrived(unsigned int size) +{ + time_t curTime = time(nullptr); + + QMutexLocker l(&m_mutex); + DEBUG_LOG(m_logger) << "newTelegramArrived with size " << size << " at " << curTime; + m_data[curTime] += size; + m_telegrams[curTime]++; +} + +int32_t PrtCnvRadioTrafficThread::start() +{ + + const QString trafficControlGroup(QStringLiteral("TrafficControl")); + int highLoad = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveQueueHighLoad"), 60); + int fullLoad = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveQueueFullLoad"), 80); + int hystLoad = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveQueueHysteresis"), 5); + int avgTime = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveAveragingTime"), 5); + float trafficPerReceiverKB = m_Config->getFloat(trafficControlGroup, QStringLiteral("ReceiveThroughput"), 3.6f); + int cntTransceiver = m_Config->getInteger(trafficControlGroup, QStringLiteral("TransceiverCount"), 6); + + + if (highLoad < 0 || highLoad > 100) + highLoad = 60; + if (fullLoad < highLoad || fullLoad > 100) + fullLoad = 80; + if (hystLoad < 0 || hystLoad > 10) + hystLoad = 5; + if (avgTime <= 0 || avgTime > 60) + avgTime = 5; + if (trafficPerReceiverKB < 1 || trafficPerReceiverKB > 1000) + trafficPerReceiverKB = 3.6f; + if (cntTransceiver < 1 || cntTransceiver > 100) + cntTransceiver = 6; + + float maxTrafficBytes = trafficPerReceiverKB * cntTransceiver * 1024; + + m_fullLoad = maxTrafficBytes * fullLoad / 100.f; + m_highLoad = maxTrafficBytes * highLoad / 100.f; + m_hystLoad = maxTrafficBytes * hystLoad / 100.f; + m_cleanupTimeout = avgTime * 1000; + + DEBUG_LOG(m_logger) << "Read config ReceiveQueueHighLoad: " << highLoad; + DEBUG_LOG(m_logger) << "Read config ReceiveQueueFullLoad: " << fullLoad; + DEBUG_LOG(m_logger) << "Read config ReceiveQueueHysteresis: " << hystLoad; + DEBUG_LOG(m_logger) << "Read config ReceiveAveragingTime: " << avgTime; + DEBUG_LOG(m_logger) << "Read config ReceiveThroughput: " << trafficPerReceiverKB; + DEBUG_LOG(m_logger) << "Read config TransceiverCount: " << cntTransceiver; + + INFO_LOG(m_logger) << "Using to following limits: high - " << m_highLoad + << " full - " << m_fullLoad + << " hyst - " << m_hystLoad + << " avg. time - " << m_cleanupTimeout / 1000; + + QTimer::singleShot(m_calcTimeout, this, &PrtCnvRadioTrafficThread::onCalculateTrafficLoad); + QTimer::singleShot(m_cleanupTimeout, this, &PrtCnvRadioTrafficThread::onCleanupTimeout); + return 0; +} + +void PrtCnvRadioTrafficThread::onCalculateTrafficLoad() +{ + const time_t curTime = time(nullptr); + + unsigned int payload = 0; + { + QMutexLocker l(&m_mutex); + + for (int i = 1; i <= m_cleanupTimeout / 1000; ++i) + payload += m_data.value(curTime - i); + } + + + payload /= (m_cleanupTimeout / 1000); + + INFO_LOG(m_logger) << "Average Payload in the last " + << m_cleanupTimeout << " Milliseconds: " + << payload << " Bytes/sec, last sec: " + << m_data[curTime - 1] << " Bytes, #telegrams: " << m_telegrams[curTime - 1]; + + PrtCnvRadioThread::E_TrafficLoad newReceiveLoad; + if (payload >= m_fullLoad) + { + + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::FullLoad; + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::HighLoad) + { + + + if(payload < m_fullLoad + m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::HighLoad; + } + } + else if (payload >= m_highLoad) + { + + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::HighLoad; + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::NormalLoad) + { + + + if (payload < m_highLoad + m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::NormalLoad; + } + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::FullLoad) + { + + + if (payload >= m_fullLoad - m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::FullLoad; + } + } + else + { + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::NormalLoad; + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::HighLoad) + { + + + if(payload >= m_highLoad - m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::HighLoad; + } + } + if (m_receiveLoad != newReceiveLoad) + { + m_receiveLoad = newReceiveLoad; + + unsigned int wartezeit_posmldg = (static_cast(m_receiveLoad) * 10) + 1; + + INFO_LOG(m_logger) << "New traffic load: " << m_receiveLoad; + PrtCnvDbThread *dbThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Db)); + if (dbThread) + { + dbThread->setAirLoad(m_receiveLoad); + dbThread->setPositionSendTime(wartezeit_posmldg); + + Q_ASSERT(QThread::currentThreadId() == m_currentThreadId); + } + else + ERROR_LOG(m_logger) << "Could not get PrtCnvDbThread!"; + } + + QTimer::singleShot(m_calcTimeout, this, &PrtCnvRadioTrafficThread::onCalculateTrafficLoad); +} + +void PrtCnvRadioTrafficThread::onCleanupTimeout() +{ + const time_t curTime = time(nullptr); + { + QMutexLocker l(&m_mutex); + QMap::iterator it = m_data.begin(); + while (it != m_data.end()) + { + const time_t key = it.key(); + + if (key < curTime - m_cleanupTimeout - 10) + { + m_data.erase(it++); + m_telegrams.remove(key); + continue; + } + break; + } + } + + QTimer::singleShot(m_cleanupTimeout, this, &PrtCnvRadioTrafficThread::onCleanupTimeout); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp new file mode 100644 index 000000000..84953cfb7 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp @@ -0,0 +1,82 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include +#include + +namespace PrtCnv +{ + + +class PrtCnvRadioTrafficThread final : public PrtCnvThread +{ + Q_OBJECT +public: + explicit PrtCnvRadioTrafficThread(PrtCnvThreadStarter* a_parent); + + + + void newTelegramArrived(unsigned int size); + + + + int32_t start() override; + +protected Q_SLOTS: + + + void onCalculateTrafficLoad(); + + + + void onCleanupTimeout(); + +protected: + + + PrtCnvRadioThread::E_TrafficLoad m_receiveLoad; + + + + unsigned int m_fullLoad; + + + + unsigned int m_highLoad; + + + + unsigned int m_hystLoad; + + + + int m_calcTimeout; + + + + int m_cleanupTimeout; + + + + QMutex m_mutex; + + + + QMap m_data; + QMap m_telegrams; +}; +} diff --git a/TetraIF/PrtCnv/PrtCnvSocketThread.cpp b/TetraIF/PrtCnv/PrtCnvSocketThread.cpp new file mode 100644 index 000000000..0b8584273 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvSocketThread.cpp @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + +#include "PrtCnvSocketThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvInjectionThread.hpp" + +#include +#include + +namespace PrtCnv +{ + + + + +PrtCnvSocketThread::PrtCnvSocketThread(PrtCnv::PrtCnvThreadStarter* a_parent, const char *loggerName) + : PrtCnvThread(a_parent, loggerName) + , m_ConnectionTimer(nullptr) + , m_Socket(nullptr) + , m_TickTimer(nullptr) + , m_ReceiveCounter(0) + , m_ReceiveAckCounter(0) + , m_State(PrtCnvSocketThread::e_INITIAL) + , m_DbThread(nullptr) + , m_ConnectTimeout(2000) + , m_DisconnectTimeout(10000) + , m_AliveTimeout(3000) + , m_TickTimeout(900) + , m_DoCleanup(false) + , m_LogThread(nullptr) + , m_InjectionThread(nullptr) + , m_currentHostAdressIndex(0) +{} + + + +PrtCnvSocketThread::~PrtCnvSocketThread() +{ + cleanup(); +} + + + + +int32_t PrtCnvSocketThread::create(NGL::Settings *settings) +{ + PrtCnvThread::create(settings); + + createNewSocket(); + + m_ConnectionTimer = new QTimer(this); + connect(m_ConnectionTimer, &QTimer::timeout, this, &PrtCnvSocketThread::timeoutAliveAndConnection); + + m_TickTimer = new QTimer(this); + connect(m_TickTimer, &QTimer::timeout, this, &PrtCnvSocketThread::timeoutTick); + + m_DbThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Db)); + m_LogThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Log)); + m_InjectionThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Injection)); + + return 0; +} + + + + + +void PrtCnvSocketThread::createNewSocket() +{ + INFO_LOG(m_logger) << "createNewSocket m_oldSocket=" << m_Socket; + Q_ASSERT(QThread::currentThreadId() == m_currentThreadId); + + if (m_Socket) + { + m_Socket->disconnectFromHost(); + m_Socket->disconnect(); + if (m_Socket->state() != QAbstractSocket::UnconnectedState) + m_Socket->waitForDisconnected(); + m_Socket->deleteLater(); + } + + m_Socket = new QTcpSocket(this); + qRegisterMetaType("QAbstractSocket::SocketError"); + qRegisterMetaType("QAbstractSocket::SocketState"); + + connect(m_Socket, &QTcpSocket::connected, this, &PrtCnvSocketThread::connected, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::disconnected, this, &PrtCnvSocketThread::disconnected, Qt::QueuedConnection); + connect(m_Socket, QOverload::of(&QTcpSocket::error), this, &PrtCnvSocketThread::error, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::hostFound, this, &PrtCnvSocketThread::hostFound, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::stateChanged, this, &PrtCnvSocketThread::stateChanged); + connect(m_Socket, &QTcpSocket::readyRead, this, &PrtCnvSocketThread::readyRead, Qt::QueuedConnection); +} + + + + +int32_t PrtCnvSocketThread::destroy() +{ + PrtCnvThread::destroy(); + cleanup(); + return 0; +} + +void PrtCnvSocketThread::cleanup() +{ + delete m_Socket; m_Socket = nullptr; + delete m_ConnectionTimer; m_ConnectionTimer = nullptr; + delete m_TickTimer; m_TickTimer = nullptr; + +} + + + + +int32_t PrtCnvSocketThread::init() +{ + INFO_LOG(m_logger) << "PrtCnvSocketThread::init()"; + PrtCnvThread::init(); + m_State = e_INITIAL; + + m_ConnectTimeout = m_Config->getInteger(getName(), QStringLiteral("ConnectTimeout"), 2000); + m_DisconnectTimeout = m_Config->getInteger(getName(), QStringLiteral("DisconnectTimeout"), 10000); + m_AliveTimeout = m_Config->getInteger(getName(), QStringLiteral("AliveTimeout"), 3000); + + return 0; +} + + + + + +void PrtCnvSocketThread::connectSocket() +{ + int sockState = m_Socket ? m_Socket->state() : -1; + INFO_LOG(m_logger) << "connectSocket m_Socket=" << m_Socket << " state=" << m_State << " socketState=" << sockState; + if (e_WORKING != m_State && e_REGISTERING != m_State) + { + if (m_Socket) + { + m_Socket->disconnectFromHost(); + if (m_Socket->state() != QAbstractSocket::UnconnectedState) + m_Socket->waitForDisconnected(); + } + + createNewSocket(); + + if(m_hostAdresses.isEmpty()) + readHostAdresses(); + const QString hostname = m_hostAdresses.at(m_currentHostAdressIndex).first; + const uint16_t port = m_hostAdresses.at(m_currentHostAdressIndex).second; + m_currentHostAdressIndex = ((m_currentHostAdressIndex + 1) % m_hostAdresses.size()); + INFO_LOG(m_logger) << "Connecting to " << hostname << ":" << port << " m_Socket=" << m_Socket; + m_Socket->connectToHost(hostname, port); + m_State = e_CONNECTING; + startConnectionTimer(); + } + else + { + WARNING_LOG(m_logger) << getName() << ": connectSocket called, but m_State is " << m_State; + } +} + + + + +void PrtCnvSocketThread::disconnectSocket() +{ + m_Socket->disconnectFromHost(); + startDisconnectionTimer(); + m_State = e_DISCONNECTING; +} + + + + + + +void PrtCnvSocketThread::connected() +{ + INFO_LOG(m_logger) << "connected (implement connected() in inherited class, if you want use this signal...)"; +} + + + + + +void PrtCnvSocketThread::disconnected() +{ + INFO_LOG(m_logger) << "got signal 'disconnected' (implement disconnected() in inherited class, if you want use this signal...)"; +} + + + + + +void PrtCnvSocketThread::readyRead() +{ + INFO_LOG(m_logger) << "got signal 'newData' (implement newData() in inherited class, if you want use this signal...)"; +} + + + + + + +void PrtCnvSocketThread::timeoutAliveAndConnection() +{ + INFO_LOG(m_logger) << "got signal 'reconnectTimeout' (implement reconnectTimeout() in inherited class, if you want use this signal...)"; +} + + + + +void PrtCnvSocketThread::error(QAbstractSocket::SocketError a_socketError) +{ + switch (a_socketError) + { + case QAbstractSocket::ConnectionRefusedError: + ERROR_LOG(m_logger) << getName() << ": ConnectionRefusedError m_State=" << m_State; + break; + case QAbstractSocket::RemoteHostClosedError: + ERROR_LOG(m_logger) << getName() << ": RemoteHostClosedError"; + break; + case QAbstractSocket::HostNotFoundError: + + break; + default: + ERROR_LOG(m_logger) << getName() << ": got signal 'error(QAbstractSocket::SocketError=" << a_socketError << ")'"; + } +} + + + + + +void PrtCnvSocketThread::hostFound() +{ + +} + + + + + +void PrtCnvSocketThread::stateChanged(QAbstractSocket::SocketState a_socketState) +{ + Q_UNUSED(a_socketState); + +} + + + + + +void PrtCnvSocketThread::storeRadioTelegram(const std::shared_ptr &a_telegram, + const uint32_t a_readCounter) +{ + m_DbThread->storeRadioTelegram(a_telegram, a_readCounter); +} + + + + + +void PrtCnvSocketThread::startAliveTimer() +{ + m_ConnectionTimer->setInterval(m_AliveTimeout); + m_ConnectionTimer->start(); +} + + + + + +void PrtCnvSocketThread::startConnectionTimer() +{ + m_ConnectionTimer->setInterval(m_ConnectTimeout); + m_ConnectionTimer->start(); +} + + + + + + +void PrtCnvSocketThread::startDisconnectionTimer() +{ + m_ConnectionTimer->setInterval(m_DisconnectTimeout); + m_ConnectionTimer->start(); +} + + + + + + +void PrtCnvSocketThread::startTickTimer() +{ + + m_TickTimer->setInterval(m_TickTimeout); + m_TickTimer->start(); +} + + + + + + + + +bool PrtCnvSocketThread::checkAndUpdateReceiveCounter(const uint32_t a_counter, const uint32_t a_maxCounter, const uint32_t a_startCounter) +{ + TRACE_LOG(m_logger) << "checkAndUpdateReceiveCounter: " << a_counter << ", " << m_ReceiveCounter; + + if (a_maxCounter == ++m_ReceiveCounter) + { + m_ReceiveCounter = a_startCounter; + } + + if (m_ReceiveCounter != a_counter) + { + + { + if (m_ReceiveCounter > a_counter) + { + ERROR_LOG(m_logger) << "It seems, the telegram with counter " << a_counter << " was resent from " + << getName() << "! Expected: " << m_ReceiveCounter; + } + else + { + ERROR_LOG(m_logger) << "It seems, we lost one or several telegrams from " << getName() + << ": receive-counter of received telegram: " << a_counter << "; Expected: " << m_ReceiveCounter; + } + } +#if 0 + m_ReceiveCounter--; + return false; +#else + m_ReceiveCounter = a_counter; + return true; +#endif + } + return true; +} + +void PrtCnvSocketThread::readHostAdresses() +{ + QString host = m_Config->getString(getName(), QStringLiteral("HostName"), QStringLiteral("127.0.0.1")); + uint16_t port = m_Config->getInteger(getName(), QStringLiteral("Port"), 4934); + m_hostAdresses.push_back(qMakePair(host, port)); + for (int i = 1; i < 10; ++i) { + const QString hostName = QLatin1String("HostName") + QString::number(i); + const QString portName = QLatin1String("Port") + QString::number(i); + host = m_Config->getString(getName(), hostName, QString()); + port = m_Config->getInteger(getName(), portName, 0); + if (host.isEmpty() || port == 0) + continue; + m_hostAdresses.push_back(qMakePair(host, port)); + } + for (const auto &p : qAsConst(m_hostAdresses)) { + INFO_LOG(m_logger) << "Read Host Adress " << p.first + << ":" << p.second + << " from settings"; + } +} + + +} diff --git a/TetraIF/PrtCnv/PrtCnvSocketThread.hpp b/TetraIF/PrtCnv/PrtCnvSocketThread.hpp new file mode 100644 index 000000000..7cb436fe1 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvSocketThread.hpp @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" + +#include +#include + +class QTimer; +class QTcpSocket; + +namespace N_CoPrtCnv +{ + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + class PrtCnvDbThread; + class PrtCnvTelegramLogThread; + class PrtCnvInjectionThread; + + + class PrtCnvSocketThread : public PrtCnvThread + { + Q_OBJECT + public: + + + + enum E_State + { + e_INITIAL, + e_CONNECTING, + e_REGISTERING, + e_WORKING, + e_DISCONNECTING, + e_REINIT + }; + + + PrtCnvSocketThread(PrtCnvThreadStarter* a_parent, const char *loggerName); + ~PrtCnvSocketThread(); + + + int32_t create(NGL::Settings *settings) override; + + + + void createNewSocket(); + + + + int32_t init() override; + + + int32_t destroy() override; + void cleanup(); + + protected: + + + QTimer *m_ConnectionTimer; + + + + + QTcpSocket *m_Socket; + + + + void readHostAdresses(); + + protected slots: + + + virtual void connected(); + + + virtual void readyRead(); + + + virtual void timeoutAliveAndConnection(); + + + virtual void timeoutTick() {} + + + virtual void error(QAbstractSocket::SocketError a_socketError); + + + virtual void hostFound(); + + + virtual void stateChanged(QAbstractSocket::SocketState a_socketState); + + protected: + + + QTimer *m_TickTimer; + + + uint32_t m_ReceiveCounter; + + + uint32_t m_ReceiveAckCounter; + + + PrtCnvSocketThread::E_State m_State; + + + PrtCnvDbThread *m_DbThread; + + + + int32_t m_ConnectTimeout; + + + int32_t m_DisconnectTimeout; + + + int32_t m_AliveTimeout; + + + int32_t m_TickTimeout; + + + QAtomicInt m_DoCleanup; + + + PrtCnvTelegramLogThread *m_LogThread; + + PrtCnvInjectionThread *m_InjectionThread; + + + + QVector > m_hostAdresses; + + + + int m_currentHostAdressIndex; + + + + virtual void disconnected(); + + + void startAliveTimer(); + + + void startConnectionTimer(); + + + void startDisconnectionTimer(); + + + + void connectSocket(); + + + void disconnectSocket(); + + + + void startTickTimer(); + + + + bool checkAndUpdateReceiveCounter(const uint32_t a_counter, const uint32_t a_maxCounter, const uint32_t a_startCounter); + + + + void storeRadioTelegram(const std::shared_ptr &a_telegram, const uint32_t a_readCounter); + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvStoredCentralTelegram.hpp b/TetraIF/PrtCnv/PrtCnvStoredCentralTelegram.hpp new file mode 100644 index 000000000..23b8e634a --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvStoredCentralTelegram.hpp @@ -0,0 +1,39 @@ + + + +#pragma once + +#include "PrtCnvStoredTelegram.hpp" +#include + +namespace PrtCnv +{ +class PrtCnvStoredCentralTelegram : public PrtCnv::PrtCnvStoredTelegram +{ +public: + PrtCnvStoredCentralTelegram(const std::shared_ptr &a_centralTelegram, + const std::shared_ptr &a_radioTelegram) + : PrtCnvStoredTelegram(a_radioTelegram) + , m_CentralTelegram(a_centralTelegram) + {} + + int writeCounter() const { return m_WriteCounter; } + + + + std::shared_ptr m_CentralTelegram; + + + uint32_t m_Attempts = 0; + + + int m_WriteCounter = 0; + + + bool m_DoResend = false; + + + bool m_DoDelete = false; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp b/TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp new file mode 100644 index 000000000..92a114971 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp @@ -0,0 +1,32 @@ + + + +#pragma once + +#include "PrtCnvStoredTelegram.hpp" + +namespace PrtCnv +{ +class PrtCnvStoredRadioTelegram : public PrtCnv::PrtCnvStoredTelegram +{ +public: + using PrtCnv::PrtCnvStoredTelegram::PrtCnvStoredTelegram; + + + + int32_t m_ReadCounter = 0; + + + uint16_t m_BroadcastIndex = 0; + + + uint8_t m_WriteCounter = 0; + + + bool m_DoDelete = false; + + + bool m_IsSent = false; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp b/TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp new file mode 100644 index 000000000..55c421840 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp @@ -0,0 +1,23 @@ + + + +#pragma once + +#include +#include + +namespace PrtCnv +{ +class PrtCnvStoredTelegram +{ +public: + explicit PrtCnvStoredTelegram(const std::shared_ptr &a_telegram) + : m_RadioTelegram(a_telegram) + {} + + std::shared_ptr m_RadioTelegram; + int64_t m_Id = 0; + bool m_WriteCounterChanged = false; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp new file mode 100644 index 000000000..d70c034df --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + +#include "PrtCnvTelegramLogThread.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include + +static int gettimeofday(struct timeval *__p, void *__t) +{ + union { + unsigned long long ns100; + FILETIME ft; + } now; + + constexpr long long SECONDS_SINCE_1601 = 11644473600LL; + constexpr long long USEC_IN_SEC = 1000000LL; + + GetSystemTimeAsFileTime(&now.ft); + __p->tv_usec = (long)((now.ns100 / 10LL) % USEC_IN_SEC); + __p->tv_sec = (long)(((now.ns100 / 10LL) / USEC_IN_SEC) - SECONDS_SINCE_1601); + + return (0); +} +#else +#include +#endif + +namespace PrtCnv +{ + + +PrtCnvTelegramLogThread::PrtCnvTelegramLogThread(PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvTelegramLogThread") + , m_DoLogCentralTelegram(true) + , m_DoLogWlsTelegram(true) + , m_DoLogRadioTelegram(true) +{ + m_Name = QStringLiteral("TelegramLog"); +} + + +int32_t PrtCnvTelegramLogThread::create(NGL::Settings *settings) +{ + PrtCnvThread::create(settings); + + connect(this, &PrtCnvTelegramLogThread::telegramLogReceived, + this, &PrtCnvTelegramLogThread::writeTelegramLog, + Qt::QueuedConnection); + + return 0; +} + + + +int32_t PrtCnvTelegramLogThread::init() +{ + PrtCnvThread::init(); + m_DoLogCentralTelegram = m_Config->getBoolean(QStringLiteral("Common"), QStringLiteral("LogCentralTelegrams"), true); + m_DoLogWlsTelegram = m_Config->getBoolean(QStringLiteral("Common"), QStringLiteral("LogWlsTelegrams"), true); + m_DoLogRadioTelegram = m_Config->getBoolean(QStringLiteral("Common"), QStringLiteral("LogRadioTelegrams"), true); + QString path = m_Config->getString(QStringLiteral("Common"), QStringLiteral("LogTelegramPath"), QStringLiteral(".")); + if (!QDir::isAbsolutePath(path)) + path = QCoreApplication::applicationDirPath() + QStringLiteral("/../") + path; + + m_LogTelegramPathWithPrefix = path + QLatin1Char('/') + m_Config->getString(QStringLiteral("Common"), QStringLiteral("LogTelegramPrefix"), QStringLiteral("PrtCnv_")); + if (!m_LogTelegramPathWithPrefix.endsWith(QLatin1Char('_'))) + m_LogTelegramPathWithPrefix += QLatin1Char('_'); + + + QFileInfo fileInfo(m_LogTelegramPathWithPrefix); + QDir dir; + dir.mkpath(fileInfo.absolutePath()); + + INFO_LOG(m_logger); + + return 0; +} + +static inline int setSend(int protocol, bool bIsSend) +{ + return (protocol | (bIsSend ? N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend : N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive)); +} + + + + +void PrtCnvTelegramLogThread::writeCentralTelegramLog(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_centralTelegram, bool a_isSend, int a_priority) +{ + if (!m_DoLogCentralTelegram) + return; + + emit telegramLogReceived(a_centralTelegram->data(), + setSend(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral, a_isSend), + a_priority); +} + + + + + +void PrtCnvTelegramLogThread::writeWlsTelegramLog(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool a_isSend, int a_priority) +{ + if (!m_DoLogWlsTelegram) + return; + + N_CoPrtCnv::CoPrtCnvCentralTelegram central(*tele); + emit telegramLogReceived(central.data(), + setSend(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls, a_isSend), + a_priority); +} + + + + + +void PrtCnvTelegramLogThread::writeRadioTelegramLog(const QByteArray &tele, bool a_isSend, int a_priority) +{ + if (!m_DoLogRadioTelegram) + return; + + emit telegramLogReceived(tele, + setSend(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra, a_isSend), + a_priority); +} + + + + + +void PrtCnvTelegramLogThread::writeTelegramLog(const QByteArray &a_data, int a_protocolType, int a_priority) +{ + + timeval tv; + gettimeofday(&tv, nullptr); + uint64_t exactTime = tv.tv_sec; + exactTime = exactTime << 32; + exactTime += tv.tv_usec; + + + QString fileName = QStringLiteral("%1%2.krlog") + .arg(m_LogTelegramPathWithPrefix, QDateTime::fromSecsSinceEpoch(tv.tv_sec).toString(QStringLiteral("yyMMdd_hh"))); + + + QFile telegramFile(fileName); + telegramFile.open(QIODevice::WriteOnly | QIODevice::Append); + + + N_CoPrtCnv::CoPrtCnvLogHeader lh; + lh.m_Length = a_data.size() + sizeof(N_CoPrtCnv::CoPrtCnvLogHeader); + lh.m_Version = 3; + lh.m_Priority = a_priority; + lh.m_Protocol = a_protocolType; + lh.m_Time = exactTime; + lh.m_Reserved = 0; + telegramFile.write(reinterpret_cast(&lh), sizeof(N_CoPrtCnv::CoPrtCnvLogHeader)); + + + telegramFile.write(a_data); + telegramFile.close(); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp new file mode 100644 index 000000000..95cdc1cf9 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp @@ -0,0 +1,87 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" + +namespace N_CoPrtCnv +{ +class CoPrtCnvCentralTelegram; +} + +namespace TrainingAreaBase +{ +namespace TetraIcd +{ +struct TrainingAreaTelegram; +} +} + +namespace PrtCnv +{ + + + class PrtCnvTelegramLogThread final : public PrtCnvThread + { + Q_OBJECT + + public: + + + explicit PrtCnvTelegramLogThread(PrtCnvThreadStarter* a_parent); + + int32_t create(NGL::Settings *settings) override; + + int32_t init() override; + + public slots: + + + void writeCentralTelegramLog(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_centralTelegram, bool a_isSend, int a_priority); + + + + void writeWlsTelegramLog(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool a_isSend, int a_priority); + + + + void writeRadioTelegramLog(const QByteArray &tele, bool a_isSend, int a_priority); + + private: + signals: + + + void telegramLogReceived(const QByteArray &a_data, int a_protocolType, int a_priority); + + private slots: + + + void writeTelegramLog(const QByteArray &a_data, int a_protocolType, int a_priority); + + protected: + + + QString m_LogTelegramPathWithPrefix; + + + bool m_DoLogCentralTelegram; + + + bool m_DoLogWlsTelegram; + + + bool m_DoLogRadioTelegram; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvThread.cpp b/TetraIF/PrtCnv/PrtCnvThread.cpp new file mode 100644 index 000000000..ebd26852b --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThread.cpp @@ -0,0 +1,74 @@ + + + + + + + + + + + + + +#include "PrtCnvThread.hpp" +#include + +namespace PrtCnv +{ + + +bool PrtCnvThread::m_DoCleanDb = false; + + + + +PrtCnvThread::PrtCnvThread(PrtCnv::PrtCnvThreadStarter* a_parent, const char *loggerName) + : m_Parent(a_parent) + , m_currentThreadId(nullptr) + , m_logger(getLogger(loggerName)) +{} + +int32_t PrtCnvThread::create(NGL::Settings *settings) +{ + m_currentThreadId = QThread::currentThreadId(); + m_Config = settings; + + INFO_LOG(m_logger) << "create " << m_Name + << " - current thread id is " << m_currentThreadId; + return 0; +} + + +int32_t PrtCnvThread::init() +{ + INFO_LOG(m_logger) << "init " << m_Name; + return 0; +} + + +int32_t PrtCnvThread::start() +{ + INFO_LOG(m_logger) << "start " << m_Name; + return 0; +} + + +int32_t PrtCnvThread::stop() +{ + return 0; +} + + +int32_t PrtCnvThread::deinit() +{ + return 0; +} + + +int32_t PrtCnvThread::destroy() +{ + return 0; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvThread.hpp b/TetraIF/PrtCnv/PrtCnvThread.hpp new file mode 100644 index 000000000..134f40134 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThread.hpp @@ -0,0 +1,71 @@ + + + + + + + + + + + + + +#pragma once + +#include "IAppComponent.hpp" +#include "logger.h" +#include + + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + + + class PrtCnvThread : public QObject, public N_AppComponent::IAppComponent + { + Q_OBJECT +protected: + + + NGL::Settings* m_Config; + + + PrtCnvThreadStarter *m_Parent; + + + Qt::HANDLE m_currentThreadId; + + + NGL::INGLLogger &m_logger; + + public: + + + static bool m_DoCleanDb; + + + PrtCnvThread(PrtCnvThreadStarter* a_parent, const char *loggerName); + + + int32_t create(NGL::Settings *settings) override; + + + int32_t init() override; + + + int32_t start() override; + + + int32_t stop() override; + + + int32_t deinit() override; + + + int32_t destroy() override; + + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvThreadStarter.cpp b/TetraIF/PrtCnv/PrtCnvThreadStarter.cpp new file mode 100644 index 000000000..b4ad8008c --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThreadStarter.cpp @@ -0,0 +1,125 @@ + + + + + + + + + + + + + +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvRadioTrafficThread.hpp" +#include "PrtCnvApplication.hpp" + +namespace PrtCnv +{ + + + + +PrtCnvThreadStarter::PrtCnvThreadStarter(const PrtCnv::PrtCnvApplication::E_ThreadId a_id, + const QString &configFileName, + PrtCnv::PrtCnvApplication* a_mainApp) + : m_Thread(nullptr) + , m_Application(a_mainApp) + , m_Id(a_id) + , m_settings(new NGL::Settings(configFileName)) + , m_logger(getLogger("PrtCnvThreadStarter")) +{ + DEBUG_LOG(m_logger) << "Using Config file '" << configFileName << "'"; +} + + +PrtCnvThreadStarter::~PrtCnvThreadStarter() +{ + delete m_settings; +} + + + + + + +void PrtCnvThreadStarter::run() +{ + INFO_LOG(m_logger) << "Entering event loop for thread " << this << ", id: " << m_Id; + + switch (m_Id) + { + case PrtCnvApplication::e_Central: + m_Thread = new PrtCnvCentralThread(this); + break; + + case PrtCnvApplication::e_Radio: + m_Thread = new PrtCnvRadioThread(m_Application->exerciseId(), this); + break; + + case PrtCnvApplication::e_Db: + m_Thread = new PrtCnvDbThread(m_Application->databaseDriver(), + m_Application->databaseHostName(), + m_Application->databaseName(), + m_Application->databaseSchemaName(), + m_Application->databaseUserName(), + m_Application->databasePassword(), + this); + break; + + case PrtCnvApplication::e_Log: + m_Thread = new PrtCnvTelegramLogThread(this); + break; + + case PrtCnvApplication::e_Injection: + m_Thread = new PrtCnvInjectionThread(this); + break; + + case PrtCnvApplication::e_RadioTraffic: + m_Thread = new PrtCnvRadioTrafficThread(this); + break; + + case PrtCnvApplication::e_ThreadIdMax: + break; + } + + if (!m_Thread) + { + ERROR_LOG(m_logger) << "Unknown threadId: " << m_Id; + return; + } + + while (!m_Application) + sleep(1); + + m_Application->waitForCreate(m_Id); + m_Thread->create(m_settings); + m_Application->waitForInit(m_Id); + m_Thread->init(); + m_Application->waitForStart(m_Id); + m_Thread->start(); + m_Application->waitForExec(m_Id); + + exec(); + + INFO_LOG(m_logger) << "Leaving event loop for thread " << this << ", id: " << m_Id; + delete m_Thread; + m_Thread = nullptr; +} + + + + + +PrtCnvThread *PrtCnvThreadStarter::getOtherThread(PrtCnvApplication::E_ThreadId a_threadId) const +{ + return m_Application->getThreadStarter(a_threadId)->m_Thread; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvThreadStarter.hpp b/TetraIF/PrtCnv/PrtCnvThreadStarter.hpp new file mode 100644 index 000000000..1b03103b6 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThreadStarter.hpp @@ -0,0 +1,68 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvApplication.hpp" +#include + +namespace NGL { + class Settings; +} + +namespace PrtCnv +{ + class PrtCnvThread; + + + class PrtCnvThreadStarter : public QThread + { + Q_OBJECT +protected: + + + PrtCnvThread *m_Thread; + + + PrtCnvApplication *m_Application; + + + PrtCnvApplication::E_ThreadId m_Id; + + + NGL::Settings *m_settings; + + + NGL::INGLLogger &m_logger; + + public: + + + PrtCnvThreadStarter(const PrtCnvApplication::E_ThreadId a_id, + const QString &settingsFile, + PrtCnvApplication *a_mainApp); + + ~PrtCnvThreadStarter(); + + PrtCnvThread *getThread() const { return m_Thread; } + PrtCnvApplication *getMainApp() const { return m_Application; } + + + PrtCnvThread *getOtherThread(PrtCnvApplication::E_ThreadId a_threadId) const; + protected: + + + void run() override; + }; + +} diff --git a/TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt b/TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt new file mode 100644 index 000000000..b70ddfb5a --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt @@ -0,0 +1,29 @@ +SET(tts_SRCS + main.cpp + server.cpp + worker.cpp + + log4cxx_tetratestserver.props +) + +SET(tts_HDRS + server.h + worker.h +) + +NGL_ADD_EXECUTABLE(AAR SV tts ${tts_SRCS} ${tts_HDRS}) +NGL_TARGET_LINK_LIBRARIES(tts + CoPrtCnv + NGLLogger + LtsCommandLineParser + nglsettings + nglcoreapplication + Qt5::Network +) +NGL_INSTALL_TARGET(tts) + +SET(LOG4CXX_PROPS_FILE log4cxx_tetratestserver.props) +NGL_INSTALL(FILES SV ${CMAKE_CURRENT_SOURCE_DIR}/${LOG4CXX_PROPS_FILE} DESTINATION "bin") + + + diff --git a/TetraIF/PrtCnv/TetraTestServer/log4cxx_tetratestserver.props b/TetraIF/PrtCnv/TetraTestServer/log4cxx_tetratestserver.props new file mode 100644 index 000000000..fff09ffca --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/log4cxx_tetratestserver.props @@ -0,0 +1,81 @@ +log4j.reset=true +log4j.rootLogger=WARN, stdout +#log4j.rootLogger=WARN, file, stdout + +log4j.logger.TTWorker=INFO +log4j.logger.TTServer=INFO + + + +# Appnd_File +########################################################### +log4j.appender.file=org.apache.log4j.RollingFileAppender +log4j.appender.file.MaxFileSize=1MB +log4j.appender.file.MaxBackupIndex=9 +log4j.appender.file.file=${LOG4QT_LOGDIR}/${LOG4QT_USER}_TetraTestServer.log +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n + + +# Appnd_Console +########################################################### +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern= %d %-5p %c{1} |#| %m (%-.30F:%L) %n + +#log4j.appender.stdout.layout.ConversionPattern= %d %-5p %-30c |#| %m (%-.30F:%L) %n + + +# Appnd_Syslog +########################################################### +log4j.appender.syslog=org.apache.log4j.SyslogAppender +log4j.appender.syslog.Threshold=ERROR +log4j.appender.syslog.SysLogHost=localhost +log4j.appender.syslog.Facility=LOCAL7 +log4j.appender.syslog.layout=org.apache.log4j.PatternLayout +log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m +log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true +log4j.appender.syslog.LevelRangeFilter.LevelMin=FATAL +log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL + + +########################################################### +########################################################### +########################################################### +# 1) Available Levels in LOG4CXX Version 0.10.0: +# TRACE, +# DEBUG, +# INFO, +# WARN, +# ERROR +# FATAL +# +# d = date/time +# p = priority (Level) +# c = category/channel +# m = message +# F = file +# L = line +# n = platform dependent line separator character or characters. +# .... +# +# Examples for console: +# a) +# %d %p %c #%m# (%.50F:%L)%n +# date/time +# priority +# category/channel +# #message# +# (Maximal 50Character des Filename von rechts:Line) +# line separator +# +# b) +# %d (%.15F:%L) %-5p %c |#| %m%n +# date/time +# (Maximal 15Character des Filename von rechts:Line) +# priority, Right pad with spaces if the priority name is less than 5 characters long. +# category/channel +# message +# line separator +# + diff --git a/TetraIF/PrtCnv/TetraTestServer/main.cpp b/TetraIF/PrtCnv/TetraTestServer/main.cpp new file mode 100644 index 000000000..39608ac96 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/main.cpp @@ -0,0 +1,188 @@ + + + +#include +#include +#include +#include +#include +#include + +#include + +#include "server.h" + +int main(int argc, char **argv) +{ + QCoreApplication::setApplicationName(QLatin1String("TTS")); + QCoreApplication::setOrganizationName(QLatin1String("RME")); + NGLCoreApplication app(argc, argv); + + app.createLogger("tts", "log4cxx_tetratestserver.props"); + NGL::INGLLogger &logger = app.baseLogger(); + QScopedPointer settings(new QSettings(app.organizationName(), app.applicationName())); + + ERROR_LOG(logger) << "Settings Directory: " << settings->fileName(); + + LtsCommandLineParser::LtsCommandLineParser options(LtsCommandLineParser::LtsCommandLineParser::CustomConfigFile); + + options.addOption({ QStringList() << QLatin1String("p") << QLatin1String("player") + , QLatin1String("number of players to be simulated.") + , QLatin1String("Default value") + , QLatin1String("5") + }); + + options.addOption({ QStringList() << QLatin1String("n") << QLatin1String("northing") + , QLatin1String("initial position UTM north.") + , QLatin1String("Default value") + , QLatin1String("77777") + }); + + options.addOption({ QStringList() << QLatin1String("e") << QLatin1String("easting") + , QLatin1String("initial position UTM east.") + , QLatin1String("Default value") + , QLatin1String("99999") + }); + + options.addOption({ QStringList() << QLatin1String("f") << QLatin1String("first-id") + , QLatin1String("first equipment ID to use.") + , QLatin1String("Default value") + , QLatin1String("1101") + }); + + options.addOption({ QStringList() << QLatin1String("r") << QLatin1String("pprow") + , QLatin1String("players per row.") + , QLatin1String("Default value") + , QLatin1String("25") + }); + + options.addOption({ QStringList() << QLatin1String("s") << QLatin1String("pspacing") + , QLatin1String("utm based spacing between the players.") + , QLatin1String("Default value") + , QLatin1String("100") + }); + + options.addOption({ QStringList() << QLatin1String("z") << QLatin1String("issi") + , QLatin1String("DestinationIssi / HostISSI") + , QLatin1String("Default value") + , QLatin1String("2") + }); + + options.addOption({ QStringList() << QLatin1String("m") << QLatin1String("movements") + , QLatin1String("how many movements per milliseconds to make.") + , QLatin1String("Default value") + , QLatin1String("2000") + }); + + options.addOption({ QStringList() << QLatin1String("d") << QLatin1String("death") + , QLatin1String("minimum times, after the movements timer is triggered, a dead player can revive.") + , QLatin1String("Default value") + , QLatin1String("100") + }); + + options.addOption({ QStringList() << QLatin1String("o") << QLatin1String("death-offset") + , QLatin1String("maximum times, after the movements timer is triggered, a dead player can revive.") + , QLatin1String("(0 -> identical to min)") + , QLatin1String("0") + }); + + options.addOption({ QStringList() << QLatin1String("t") << QLatin1String("pattern") + , QLatin1String("pattern the player has to walk [enter pattern by hand or pattern alias-name from settings file]\r\nfor more info, enter '--pattern-help'.") + , QLatin1String("Default value") + , QLatin1String("3,30,20#3,30,-20#3,-30,-20#3,-30,20") + }); + + options.addOption({ QStringList() << QLatin1String("demand-old-broadcast-telegrams") + , QLatin1String("player demand old broadcast telegrams starting at BCI ") + , QLatin1String("Default value") + , QLatin1String("0") + }); + + options.addOption({ QStringList() << QLatin1String("deactivate-single-mines") + , QLatin1String("the first player deactivates single mines with ids from minimum-mine-id to maximum-mine-id") + }); + + options.addOption({ QStringList() << QLatin1String("minimum-mine-id") + , QLatin1String("sets the value for minimum-mine-id used within deactivate-single-mines command") + , QLatin1String("Default value") + , QLatin1String("minimum-mine-id 2048") + }); + + options.addOption({ QStringList() << QLatin1String("maximum-mine-id") + , QLatin1String("sets the value for maximum-mine-Id used within deactivate-single-mines command") + , QLatin1String("Default value") + , QLatin1String("maximum-mine-id 2100") + }); + + options.addOption({ QStringList() << QLatin1String("pattern-help") + , QLatin1String("help for the pattern interpreter.") + }); + + + if (!options.init()) + { + options.showHelp(); + return -1; + } + QSettings serverSettings(app.applicationDirPath() + QLatin1String("/") + options.iniFile(), QSettings::IniFormat); + + TTSArgs ttsArgs; + + ttsArgs.destIssi = options.isSet(QLatin1String("issi")) ? options.value(QLatin1String("issi")).toInt() : 2; + ttsArgs.cntPlayer = options.isSet(QLatin1String("player")) ? options.value(QLatin1String("player")).toInt() : 0; + int northPos_arg = options.isSet(QLatin1String("northing")) ? options.value(QLatin1String("northing")).toInt() : 77777; + int eastPos_arg = options.isSet(QLatin1String("easting")) ? options.value(QLatin1String("easting")).toInt() : 90000; + ttsArgs.position = QPointF(eastPos_arg, northPos_arg); + ttsArgs.eqIdStart = options.isSet(QLatin1String("first-id")) ? options.value(QLatin1String("first-id")).toInt() : 1101; + ttsArgs.pprow = options.isSet(QLatin1String("pprow")) ? options.value(QLatin1String("pprow")).toInt() : 25; + ttsArgs.pspacing = options.isSet(QLatin1String("pspacing")) ? options.value(QLatin1String("pspacing")).toInt() : 100; + ttsArgs.movs_per_msec = options.isSet(QLatin1String("movements")) ? options.value(QLatin1String("movements")).toInt() : 2000; + ttsArgs.minimumDeathTicks = options.isSet(QLatin1String("death")) ? options.value(QLatin1String("death")).toInt() : 10; + ttsArgs.maximumDeathTicks = options.isSet(QLatin1String("death-offset")) ? options.value(QLatin1String("death-offset")).toInt() : 20; + ttsArgs.demandOldBraodcastTelegrams = options.isSet(QLatin1String("demand-old-broadcast-telegrams")) ? true : false; + if (ttsArgs.demandOldBraodcastTelegrams) + ttsArgs.demandOldBraodcastTelegramsCounter = options.value(QLatin1String("demand-old-broadcast-telegrams")).toInt(); + ttsArgs.deactivationSingleMines = options.isSet(QLatin1String("deactivate-single-mines")) ? true : false; + ttsArgs.minimumMineId = options.isSet(QLatin1String("minimum-mine-id")) ? options.value(QLatin1String("minimum-mine-id")).toInt() : 2048; + ttsArgs.maximumMineId = options.isSet(QLatin1String("maximum-mine-id")) ? options.value(QLatin1String("maximum-mine-id")).toInt() : 2100; + ttsArgs.pattern = options.isSet(QLatin1String("pattern")) ? options.value(QLatin1String("pattern")) : QLatin1String("3,30,20#3,30,-20#3,-30,-20#3,-30,20"); + + if (options.isSet(QLatin1String("pattern-help"))) + { + options.showHelp(); + return -1; + } + + + if (ttsArgs.maximumDeathTicks == 0) + ttsArgs.maximumDeathTicks = ttsArgs.minimumDeathTicks; + + WARNING_LOG(logger) << "Simulating " << ttsArgs.cntPlayer << " players"; + WARNING_LOG(logger) << " ... DestinationIssi/HostIssi: " << ttsArgs.destIssi; + WARNING_LOG(logger) << " ... on Position n/e: " << ttsArgs.position.y() << "/" << ttsArgs.position.x(); + WARNING_LOG(logger) << " ... first equipmentID is: " << ttsArgs.eqIdStart; + WARNING_LOG(logger) << " ... player is reborn randomly after minimum " << ttsArgs.minimumDeathTicks + << " ticks and maximum " << ttsArgs.maximumDeathTicks << " ticks"; + WARNING_LOG(logger) << " ... pattern = " << ttsArgs.pattern; + WARNING_LOG(logger) << " ... max. " << ttsArgs.pprow << " players per row"; + WARNING_LOG(logger) << " ... spacing of '" << ttsArgs.pspacing << " UTM east' between players"; + WARNING_LOG(logger) << " ... one player will be moved after " << ttsArgs.movs_per_msec << " msecs"; + + TTServer *s = new TTServer(ttsArgs); + + if (!s->listen(QHostAddress::Any, serverSettings.value(QLatin1String("Radio/Port"), 4200).toInt())) + { + ERROR_LOG(logger) << "Error listening on localhost:" << serverSettings.value(QLatin1String("Radio/Port"), 52010).toInt() << ": " + << s->errorString(); + delete s; + return -1; + } + + DEBUG_LOG(logger) << "Starting Server"; + + int ret = app.exec(); + + delete s; + + return ret; +} diff --git a/TetraIF/PrtCnv/TetraTestServer/server.cpp b/TetraIF/PrtCnv/TetraTestServer/server.cpp new file mode 100644 index 000000000..2acb4883b --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/server.cpp @@ -0,0 +1,38 @@ + + +#include "server.h" + +#include +#include + +#include "worker.h" + +TTServer::TTServer(const TTSArgs &ttsArgs) + : m_ttsArgs(ttsArgs) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TTServer")) +{ + connect(this, &TTServer::newConnection, + this, &TTServer::onNewConnection); +} + +void TTServer::onNewConnection() +{ + QTcpSocket *sock = nextPendingConnection(); + if (!sock) + return; + NOTICE_LOG(m_logger) << "New incoming connection from " + << sock->peerName() << ":" + << sock->peerPort(); + + TTWorker *ttw = new TTWorker(sock, m_ttsArgs); + if (!ttw->init()) + exit(5); + + connect(sock, &QTcpSocket::disconnected, + this, &TTServer::onDisconnect); +} + +void TTServer::onDisconnect() +{ + NOTICE_LOG(m_logger) << "Disconnected"; +} diff --git a/TetraIF/PrtCnv/TetraTestServer/server.h b/TetraIF/PrtCnv/TetraTestServer/server.h new file mode 100644 index 000000000..9ae8a3087 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/server.h @@ -0,0 +1,54 @@ + + + +#pragma once + +#include +#include +#include +#include +#include + + +struct runningPattern +{ + int steps = 0; + int ethering = 0; + int northering = 0; +}; + +struct TTSArgs +{ + QPointF position; + QString pattern; + QSettings *settings = nullptr; + int destIssi = 0; + unsigned int cntPlayer = 0; + unsigned int eqIdStart = 0; + unsigned int minimumDeathTicks = 0; + unsigned int maximumDeathTicks = 0; + unsigned int pprow = 0; + unsigned int pspacing = 0; + unsigned int movs_per_msec = ~0U; + unsigned int minimumMineId = 0; + unsigned int maximumMineId = 0; + bool demandOldBraodcastTelegrams = false; + int demandOldBraodcastTelegramsCounter = 0; + bool deactivationSingleMines = false; +}; + +class TTServer : public QTcpServer +{ + Q_OBJECT +public: + explicit TTServer(const TTSArgs &m_ttsArgs); + +protected Q_SLOTS: + void onNewConnection(); + void onDisconnect(); + +protected: + TTSArgs m_ttsArgs; + + NGL::INGLLogger &m_logger; +}; diff --git a/TetraIF/PrtCnv/TetraTestServer/tts.txt b/TetraIF/PrtCnv/TetraTestServer/tts.txt new file mode 100644 index 000000000..2c05b75d4 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/tts.txt @@ -0,0 +1,111 @@ +TTS Tetra Test Server: +Das Testprogramm tts wird als Ersatz des Tetra-Server gestartet. Es dient dazu, Lasttests im Gesamtsystem zu starten. +----------------------------------------------- +Teilnehmer anlegen: + +In der Opperator-App in die Übung einloggen +Vorplanung->Teilnehmer Truppe->Bearbeite Teilnehmer +Einen Zug selektieren und Erstellen +Eine Anfangs-Ausstattungsnummer wählen und mit Enter jede Menge Teilnehmer mit aufsteigender Ausstattungsnummererzeugen. +----------------------------------------------- +Verschlüsselung abschalten: +auf dem Server EXCTDS01 die Datei /etc/lts-cc.conf öffnen + +[TrainingAreaBase] +UseTetraScrambling=false + +----------------------------------------------- +Tabelle pdm.pdm_radio_group aendern: +Dazu vorher den Namen der Gruppe herausfinden: +Als Administrator in der Operator App Vorplanung->Übungen->Übungen den Namen der Tetra Gruppe von der aktuellen Übung nehmen. + +Die Einstellungen, die geändert werden vorher aufschreiben, um wieder zum Betrieb mit dem Gefechtsfeld zurückzukommen. +In der Tabelle pdm.pdm_radio_group den Namen "radiohost" auf localhost und issi auf 2 einstellen +In der Tabelle pdm.pdm_radio_group den radio_port auf 4200 einstellen +----------------------------------------------- +Servernamen in PrtCnv.dat ändern +Auf dem Server (EXCTDS01) ala user ctc_sv im Verzeichnis bin die Datei PrtCnv.dat öffnen +[Central] +HostName=localhost +----------------------------------------------- +Serversoftware neu starten +----------------------------------------------- +tts starten: +Auf dem Server (EXCTDS01) ala user ctc_sv im Verzeichnis bin +./tts -p 800 -f 1200 + + Bedeutung: + -p 800 Positionsmeldungen für 800 Teilnehmer erzeugen + -f 1200 Anfangsausstattungsnummer vom Teilnehmer anlegen hier eingeben. + + +----------------------------------------------- +----------------------------------------------- +Relevante Tabellen sind: + 1) tab_prtcnv_member + 2) ex_nn.prtcnv_to_radio + Hier werden die Telegramme (Rtg Gefechtsfeld) zwischengespeichert, bis sie quittiert sind. + +Bei Problemen hat es sich als sinnvoll erwiesen, diese Tabellen zu löschen +----------------------------------------------- +----------------------------------------------- + +----------------------------------------------- +Optionen mit tts --help anzeigen lassen: + +./tts --help +Could not find log4cxx configuration file tetra_log4cxx.props +Using default logging to stdout +2020-09-03 13:19:15.300 ERROR tts |#| Settings Directory: /shd/CTC/TOOLS/.config/RME/TTS.conf (TDS-source/TetraIF/PrtCnv/TetraTestServer/main.cpp:30) +Usage: ./tts [options] + +Options: + -i, --ini Default: /etc/lts-cc.conf + -h, --help Displays this help. + -v, --version Displays version + information. + -p, --player number of players to be + simulated. + -n, --northing initial position UTM north. + -e, --easting initial position UTM east. + -f, --first-id first equipment ID to use. + -r, --pprow players per row. + -s, --pspacing utm based spacing between + the players. + -m, --movements how many movements per + milliseconds to make. + -d, --death minimum times, after the + movements timer is + triggered, a dead player can + revive. + -o, --death-offset <(0 -> identical to min)> maximum times, after the + movements timer is + triggered, a dead player can + revive. + -t, --pattern pattern the player has to + walk [enter pattern by hand + or pattern alias-name from + settings file] + for more info, enter + '--pattern-help'. + --demand-old-broadcast-telegrams player demand old broadcast + telegrams starting at BCI + + --deactivate-single-mines the first player + deactivates single mines + with ids from + minimum-mine-id to + maximum-mine-id + --minimum-mine-id sets the value for + minimum-mine-id used within + deactivate-single-mines + command + --maximum-mine-id sets the value for + maximum-mine-Id used within + deactivate-single-mines + command + --pattern-help help for the pattern + interpreter. + + + diff --git a/TetraIF/PrtCnv/TetraTestServer/worker.cpp b/TetraIF/PrtCnv/TetraTestServer/worker.cpp new file mode 100644 index 000000000..d975df8d4 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/worker.cpp @@ -0,0 +1,645 @@ + + + +#include "worker.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +TTWorker::TTWorker(QTcpSocket *socket, const TTSArgs &ttsArgs) + : m_socket(socket) + , m_timer(new QTimer(this)) + , m_counter(0) + , m_toogle(true) + , m_ttsArgs(ttsArgs) + , m_patternList(interpretPattern(ttsArgs.pattern)) + , m_generalPosition(ttsArgs.position) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TTWorker")) +{ + qsrand(time(nullptr)); +} + +bool TTWorker::init() +{ + connect(m_socket, &QTcpSocket::disconnected, + this, &TTWorker::deleteLater); + connect(m_socket, QOverload::of(&QTcpSocket::error), + this, &TTWorker::onSocketError); + connect(m_socket, &QTcpSocket::readyRead, + this, &TTWorker::onReadyRead); + connect(m_timer, &QTimer::timeout, + this, &TTWorker::onSendPlayerPositions); + + if (m_ttsArgs.movs_per_msec < 200) + { + ERROR_LOG(m_logger) << "Invalid value for 'movements per milliseconds'! Please choose a number greater than 200 msecs or equal. Program stopped."; + return false; + } + return true; +} + +void TTWorker::startExecution() +{ + + m_timer->start(m_ttsArgs.movs_per_msec); + NOTICE_LOG(m_logger) << "Start Exe login all Player"; + + for (unsigned int i = 0; i < m_ttsArgs.cntPlayer; i++) + { + int eqId = m_ttsArgs.eqIdStart + i; + int issi = m_ttsArgs.eqIdStart + i + 2000; + QPointF posUTM((m_generalPosition.x() + (i / m_ttsArgs.pprow) * m_ttsArgs.pspacing), + (m_generalPosition.y() + (i % m_ttsArgs.pprow) * m_ttsArgs.pspacing)); + Player *p = new Player(eqId, issi, m_ttsArgs.minimumDeathTicks, m_ttsArgs.maximumDeathTicks, posUTM); + m_playerList.append(p); + + sendLogin(p->eqId, p->issi); + } + + if (m_ttsArgs.deactivationSingleMines) + QTimer::singleShot(1000, this, &TTWorker::onSendDeaktivierungEinzelminen); + + if (m_ttsArgs.demandOldBraodcastTelegrams) + QTimer::singleShot(1000, this, &TTWorker::onSendNachforderungBroadcastTelegramm); + + + + } + +QVector TTWorker::interpretPattern(QString pattern) const +{ + if (pattern.isEmpty()) + { + ERROR_LOG(m_logger) << "INVALID PATTERN - pattern-size < 1"; + exit(8); + } + + if (pattern.at(0) == QLatin1Char('%')) + { + pattern.remove(0, 1); + + QString patternAlias = pattern; + + pattern = m_ttsArgs.settings->value(QLatin1String("pattern/") + patternAlias).toString(); + + if (pattern.isEmpty()) + { + ERROR_LOG(m_logger) << "INVALID PATTERN - alias '" << patternAlias << "' is not available in settings file! Program halted."; + exit(9); + } + } + + + + if (pattern.at(pattern.count() - 1) == QLatin1Char('#')) + pattern.remove(pattern.count() - 1, 1); + + QVector newPatternList; + runningPattern rp; + QStringList strings = pattern.split(QLatin1Char('#')); + QStringList stringy; + int i; + + for (i = 0; i < strings.count(); i++) + { + stringy = strings.at(i).split(QLatin1Char(',')); + + if (stringy.count() != 3) + break; + + bool ok = true; + + rp.steps = stringy.at(0).toInt(&ok); if (!ok) break; + rp.ethering = stringy.at(1).toInt(&ok); if (!ok) break; + rp.northering = stringy.at(2).toInt(&ok); if (!ok) break; + + newPatternList.append(rp); + + if (i == strings.count() - 1) + return newPatternList; + } + + ERROR_LOG(m_logger) << "INVALID PATTERN: '" << strings.at(i) << "'. Cannot start without correct pattern!"; + + exit(5); + + return QVector(); +} + +void TTWorker::sendLogin(uint32_t eqId, uint32_t issi) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram *tele = new N_CoPrtCnv::CoPrtCnvRadioTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginRequest, eqId, issi); + + DEBUG_LOG(m_logger) << "SEND LOGIN FOR ISSI=" << issi << ", eqId=" << eqId; + sendTelegram(tele, issi); +} + +void TTWorker::onReadyRead() +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; + qint64 bytesRead = m_socket->peek((char *)&header, sizeof(header)); + if (sizeof(header) != bytesRead) + { + DEBUG_LOG(m_logger) << "To few bytes to read from socket"; + return; + } + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) + { + ERROR_LOG(m_logger) << "Disconnect because radio-Telegram does not begin with magic-number A5: I got " + << header.m_MagicNumber; + m_socket->disconnectFromHost(); + return; + } + + if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) + { + WARNING_LOG(m_logger) << "Radio-Telegram length to big: " << header.m_Length + << " - but I proceed with this telegram."; + } + + + uint16_t dataSize = header.m_Length + sizeof(header); + if (m_socket->bytesAvailable() < dataSize) + { + DEBUG_LOG(m_logger) << "not enough bytes available - waiting for more data"; + return; + } + QByteArray buf(dataSize, Qt::Uninitialized); + + bytesRead = 0; + while (bytesRead < dataSize) + { + qint64 br = m_socket->read(&buf.data()[bytesRead], dataSize - bytesRead); + bytesRead += br; + } + handleReceivedTelegram(buf); + + if (m_socket->bytesAvailable()) + QTimer::singleShot(0, this, &TTWorker::onReadyRead); +} + +void TTWorker::handleReceivedTelegram(const QByteArray &data) +{ + INFO_LOG(m_logger) << data.size(); + + switch (data.at(4)) + { + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: + handleRegisterInd(); + startExecution(); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: + handleDataIndReq(data); + + break; + default: + INFO_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << (int)data[4] + << " not implemented!"; + break; + } +} + +void TTWorker::sendTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram, uint32_t issi) +{ + radioTelegram->setZaehler(m_counter++); + radioTelegram->setDestISSI(m_ttsArgs.destIssi); + radioTelegram->setSrcISSI(issi); + + m_socket->write(radioTelegram->data()); + m_socket->flush(); + delete radioTelegram; +} + +void TTWorker::onSendNachforderungBroadcastTelegramm() +{ + Player *p = m_playerList.at(0); + + if (p->isLogin) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram tel(GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME, + 10, p->eqId); + tel.setZaehler(0); + tel.setBroadcastIndex(0); + tel.setDestISSI(m_ttsArgs.destIssi); + tel.setSrcISSI(p->issi); + tel.setPayload4Byte(0); + tel.setPayload1Byte(0); + tel.setPayload2Byte(m_ttsArgs.demandOldBraodcastTelegramsCounter); + m_socket->write(tel.data()); + } + else + QTimer::singleShot(1000, this, &TTWorker::onSendNachforderungBroadcastTelegramm); +} + +void TTWorker::onSendDeaktivierungEinzelminen() +{ + if (m_playerList.isEmpty()) + { + ERROR_LOG(m_logger) << "No player for onSendDeaktivierungEinzelminen..."; + return; + } + Player *p = m_playerList.at(0); + static unsigned int mineId = m_ttsArgs.minimumMineId; + + NOTICE_LOG(m_logger) << "onSendDeaktivierungEinzelminen " << p->isLogin; + if (p->isLogin) + { + TrainingAreaBase::TetraIcd::MineTriggered tele; + tele.header.equipmentNumber = p->eqId; + tele.header.timeStamp = time(nullptr) * 1000; + tele.mineIndex = mineId++; + tele.mineAreaId = 0; + + sendTelegram(tele, p->issi); + } + + if (mineId <= m_ttsArgs.maximumMineId) + QTimer::singleShot(1000, this, &TTWorker::onSendDeaktivierungEinzelminen); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void TTWorker::sendTaktischerStatus(uint32_t eqId, uint32_t issi, TrainingAreaBase::TetraIcd::VulnerabilityState vbg) +{ + TrainingAreaBase::TetraIcd::StateChange tele; + tele.header.equipmentNumber = eqId; + tele.header.timeStamp = time(nullptr) * 1000; + + tele.tasVitality = 90; + tele.tasVulnerabilityKindId = 459008; + tele.vulnerabilityBits = 0; + + for (Player *p : qAsConst(m_playerList)) + { + if (p->eqId == eqId) + { + p->vbg = vbg; + tele.vulnerabilityState = vbg; + DEBUG_LOG(m_logger) << "Player (" << p->eqId << ") - VBG: " << int(vbg); + break; + } + } + + sendTelegram(tele, issi); +} + +void TTWorker::sendSanitationReport(uint32_t eqId, uint32_t issi) +{ + m_toogle = false; + return; + TrainingAreaBase::TetraIcd::SanitaryMaterialStockReport tele; + tele.header.equipmentNumber = eqId; + tele.header.timeStamp = time(nullptr) * 1000; + int matCount = 14; + tele.sanitaryMaterialCount = matCount; + std::vector mat; + mat.reserve(matCount); + for (int i = 1; i <= matCount; i++) + mat.emplace_back(i); + tele.sanitaryMaterialStock = mat; + sendTelegram(tele, issi); + +} + + + + + + + + + + + + + + + + +void TTWorker::sendBITE(uint32_t eqId, uint32_t issi) +{ + TrainingAreaBase::TetraIcd::BiteReport tele; + tele.header.equipmentNumber = eqId; + tele.header.timeStamp = time(nullptr) * 1000; + tele.loginType = TrainingAreaBase::TetraIcd::BiteReport::LoginType::Relogin; + tele.configError = false; + sendTelegram(tele, issi); + sendTaktischerStatus(eqId, issi, TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady); +} + +void TTWorker::handleDataIndReq(const QByteArray &data) +{ + QScopedPointer radioTelegram(new N_CoPrtCnv::CoPrtCnvRadioTelegram(data)); + int telID = radioTelegram->getTelID(); + + switch (telID) + { +#if 0 + TODO + case GEF_AUSLOESUNG_DUS_TREFFER: + { + + + DEBUG_LOG(mLogger) << "handleAusloeserDUSTreffer: eqId=" << radioTelegram->getIdentity() << + " issi=" << radioTelegram->getDestISSI(); + + + XDR_Wrapper_it *wrapper = nullptr; + if (!N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(wrapper, radioTelegram.data())) + if (!wrapper) + return; + const ausloesung_dus_treffer_rt &rt_data = static_cast(wrapper)->get_rt(); + + if (rt_data.bek_wirkung > 90) + sendTaktischerStatus(radioTelegram->getIdentity(), radioTelegram->getDestISSI(), TOTALAUSFALL); + else + sendTaktischerStatus(radioTelegram->getIdentity(), radioTelegram->getDestISSI(), ANNAEHENDER_TREFFER); + delete wrapper; + return; + } +#endif + case GEF_TAKTISCHER_STATUS: + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(radioTelegram.data()); + TrainingAreaBase::TetraIcd::StateChange sc = TrainingAreaBase::TetraIcd::StateChange::fromJson(tele->jsonData()); + delete tele; + DEBUG_LOG(m_logger) << " Try to Resetnd State " << sc.header.equipmentNumber << " we got state: " << static_cast(sc.vulnerabilityState) << " and this bits here: " << sc.vulnerabilityBits; + + sc.header.timeStamp = time(nullptr) * 1000; + uint32_t issi = 0; + for (int i = 0; i < m_playerList.count(); i++) + { + if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) + { + issi = m_playerList.at(i)->issi; + break; + } + } + + ERROR_LOG(m_logger) << " Try to Resetnd S2tate " << sc.header.equipmentNumber << " we got state: " << static_cast(sc.vulnerabilityState) << " and this bits here: " << sc.vulnerabilityBits; + sendTelegram(sc, issi); + return; + } + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(radioTelegram.data()); + TrainingAreaBase::TetraIcd::Sanitation sc = TrainingAreaBase::TetraIcd::Sanitation::fromJson(tele->jsonData()); + delete tele; + + DEBUG_LOG(m_logger) << " Try to Resetnd State " << sc.header.equipmentNumber << " we got procedure: " << sc.proceduresTaken; + + sc.header.timeStamp = time(nullptr) * 1000; + uint32_t issi = 0; + for (int i = 0; i < m_playerList.count(); i++) + { + if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) + { + issi = m_playerList.at(i)->issi; + break; + } + } + + ERROR_LOG(m_logger) << " Try to Resetnd S2tate " << sc.header.equipmentNumber << " we got state: " << sc.proceduresTaken; + sendTelegram(sc, issi); + return; + } + case GEF_TREFFER_AUSLOESUNG: + case GEF_INIT: + { + TrainingAreaBase::TetraIcd::StateChange tele; + uint32_t issi = 0; + for (int i = 0; i < m_playerList.count(); i++) + { + if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) + { + issi = m_playerList.at(i)->issi; + break; + } + } + TrainingAreaBase::TetraIcd::VulnerabilityState state = (telID == GEF_TREFFER_AUSLOESUNG) + ? static_cast(radioTelegram->getPayloadDataUInt8(7)) + : TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady; + + tele.originatorType = TrainingAreaBase::TetraIcd::OriginatorType::Initialisation; + tele.header.equipmentNumber = radioTelegram->getIdentity(); + tele.header.timeStamp = time(nullptr) * 1000; + uint32_t vulcomplete = radioTelegram->getPayloadDataUInt32(8, 2); + uint32_t vitality = vulcomplete &= 0xF000; + vitality >>= 12; + + tele.tasVulnerabilityKindId = vulcomplete &= 0x0FFF; + + tele.tasVulnerabilityKindId <<= 16; + tele.tasVulnerabilityKindId |= 0xB1; + + tele.tasVitality = (vitality - 1) * 10; + if (tele.tasVitality < 0) + tele.tasVitality = 100; + + if (state == TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady && vitality > 0) + tele.vulnerabilityState = TrainingAreaBase::TetraIcd::VulnerabilityState::MediumDamage; + else + tele.vulnerabilityState = state; + + sendTelegram(tele, issi); + return; + } + + + + + + + + + + + + } + + + + if (radioTelegram->isLoginTelegram()) + { + + DEBUG_LOG(m_logger) << "player cont: " << m_playerList.count(); + for (int i = 0; i < m_playerList.count(); i++) + { + Player *p = m_playerList.at(i); + if (radioTelegram->getDestISSI() == p->issi) + { + if (p->isLogin) + return; + DEBUG_LOG(m_logger) << "Player #" << i << " with eqId=" << p->eqId << " and issi=" << p->issi << " is now logged in."; + p->isLogin = true; + sendBITE(p->eqId, p->issi); + return; + } + } + + ERROR_LOG(m_logger) << "Invalid player was logged in. issi: '" << radioTelegram->getDestISSI() << "'"; + return; + } + + + DEBUG_LOG(m_logger) << "Received unused or invalid telegram with Telegram-ID: " << telID; +} + +static void fillHeader(char *data, int len) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader *hdr + = (N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader *)data; + hdr->m_MagicNumber = N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER; + hdr->m_Counter = 0; + hdr->m_Length = len; +} + +void TTWorker::handleRegisterInd() +{ + m_counter = 1; + + QByteArray buf; + buf.resize(6); + fillHeader(buf.data(), 2); + buf[4] = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp; + buf[5] = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered; + + m_socket->write(buf); + + +} + +void TTWorker::movePlayer(Player *p) +{ + + + if (p->patternInList > m_patternList.count() - 1) + p->patternInList = 0; + else + { + if (p->stepInPattern > m_patternList.at(p->patternInList).steps) + { + p->stepInPattern = 1; + if (p->patternInList == m_patternList.count() - 1) + p->patternInList = 0; + else + p->patternInList++; + } + } + + p->posUTM.setX(p->posUTM.x() + + m_patternList.at(p->patternInList).northering); + p->posUTM.setY(p->posUTM.y() + + m_patternList.at(p->patternInList).ethering); + + p->stepInPattern++; +} + +void TTWorker::onSendPlayerPositions() +{ + + qint64 bytesSent = 0; + int playerCount = 0; + TrainingAreaBase::TetraIcd::PositionReport tele; + for (int i = 0; i < m_playerList.count(); i++) + { + Player *p = m_playerList.at(i); + + if (!p->isLogin) + { + INFO_LOG(m_logger) << "Player with eqId=" << p->eqId << " and issi=" << p->issi << " is not logged in."; + break; + } + playerCount++; + + + if (p->vbg != TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady && p->isEndOfTicks()) + sendTaktischerStatus(p->eqId, p->issi, TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady); + + tele.header.equipmentNumber = p->eqId; + if (m_toogle) + sendSanitationReport(p->eqId, p->issi); + + + movePlayer(p); + tele.relPosition.offsetY = p->posUTM.y(); + tele.relPosition.offsetX = p->posUTM.x(); + + tele.header.timeStamp = time(nullptr) * 1000; + + N_CoPrtCnv::CoPrtCnvCentralTelegram ct(tele); + N_CoPrtCnv::CoPrtCnvRadioTelegram *tel = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(&ct); + tel->setZaehler(m_counter++); + tel->setDestISSI(m_ttsArgs.destIssi); + tel->setSrcISSI(p->issi); + m_socket->write(tel->data()); + bytesSent += tel->getPayloadSize(); + delete tel; + } + bool bFlushed = m_socket->flush(); + INFO_LOG(m_logger) << "Sent " << bytesSent << "bytes (" << playerCount << " players), bFlushed=" << bFlushed; +} + +void TTWorker::onSocketError() +{ + if (m_socket) + m_socket->disconnectFromHost(); +} diff --git a/TetraIF/PrtCnv/TetraTestServer/worker.h b/TetraIF/PrtCnv/TetraTestServer/worker.h new file mode 100644 index 000000000..d59704648 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/worker.h @@ -0,0 +1,128 @@ + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "server.h" + + +class QTcpSocket; +class QTimer; + +class Player +{ +private: + void randomizeDeathTicks() + { + deathTicks = ((qrand() % (maximumDeathTicks - minimumDeathTicks + 1)) + minimumDeathTicks); + } + +public: + + uint32_t eqId; + uint32_t issi; + QPointF posUTM; + + + bool isLogin; + bool isValidBITE; + TrainingAreaBase::TetraIcd::VulnerabilityState vbg; + + + int patternInList; + int stepInPattern; + + + uint32_t deathTicks; + uint32_t minimumDeathTicks; + uint32_t maximumDeathTicks; + + Player(int eqId_, int issi_, uint32_t minimumDeathTicks_, uint32_t maximumDeathTicks_, const QPointF &posUTM_) + : eqId(eqId_) + , issi(issi_) + , posUTM(posUTM_) + , isLogin(false) + , isValidBITE(false) + , vbg(TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady) + , patternInList(0) + , stepInPattern(1) + , deathTicks(0) + , minimumDeathTicks(minimumDeathTicks_) + , maximumDeathTicks(maximumDeathTicks_) + { + randomizeDeathTicks(); + } + + bool isEndOfTicks() + { + deathTicks--; + if (deathTicks < 1) + { + randomizeDeathTicks(); + return true; + } + return false; + } +}; + +class TTWorker : public QObject +{ + Q_OBJECT + +public: + explicit TTWorker(QTcpSocket *socket, const TTSArgs &ttsArgs); + + bool init(); + +private Q_SLOTS: + void onReadyRead(); + void onSendPlayerPositions(); + + void onSocketError(); + void onSendNachforderungBroadcastTelegramm(); + void onSendDeaktivierungEinzelminen(); + +protected: + void startExecution(); + QVector interpretPattern(QString pattern) const; + void movePlayer(Player *p); + void handleReceivedTelegram(const QByteArray &data); + void handleRegisterInd(); + void handleDataIndReq(const QByteArray &data); + + void sendTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram, uint32_t issi); + template + void sendTelegram(const T &tele, uint32_t issi) + { + N_CoPrtCnv::CoPrtCnvCentralTelegram ct(tele); + sendTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(&ct), issi); + } + void sendLogin(uint32_t eqId, uint32_t issi); + void sendBITE(uint32_t eqId, uint32_t issi); + void sendTaktischerStatus(uint32_t eqId, uint32_t issi, TrainingAreaBase::TetraIcd::VulnerabilityState vbg); + void sendSanitationReport(uint32_t eqId, uint32_t issi); + +private: + QTcpSocket *m_socket; + QTimer *m_timer; + QByteArray m_buffer; + unsigned int m_counter; + bool m_toogle; + + TTSArgs m_ttsArgs; + + QVector m_playerList; + QVector m_patternList; + QPointF m_generalPosition; + NGL::INGLLogger &m_logger; +}; diff --git a/TetraIF/PrtCnv/log4cxx_prtcnv.props b/TetraIF/PrtCnv/log4cxx_prtcnv.props new file mode 100644 index 000000000..27f34bc00 --- /dev/null +++ b/TetraIF/PrtCnv/log4cxx_prtcnv.props @@ -0,0 +1,49 @@ +# +# Logger-Config für PrtCnv +# +# $Id$ +# $HeadURL$ +# $Author$ +# +# Aus: grep getNGLLogger * | cut -d \" -f 2 | sort -u +# +log4j.reset=true +#log4j.rootLogger=DEBUG, stdout +log4j.rootLogger=WARN, file + +#log4j.logger.CoPrtCnvCentralTelegram=WARN +#log4j.logger.CoPrtCnvRadioTelegram=WARN +#log4j.logger.CoPrtCnvTelegramConverter=WARN +#log4j.logger.PrtCnvApplication=WARN +#log4j.logger.PrtCnvBroadcastMgr=WARN +#log4j.logger.PrtCnvCentralThread=WARN +#log4j.logger.PrtCnvDbThread=WARN +#log4j.logger.PrtCnvInjectionSocket=WARN +#log4j.logger.PrtCnvInjectionThread=WARN +#log4j.logger.PrtCnvMain=WARN +#log4j.logger.PrtCnvMember=WARN +#log4j.logger.PrtCnvRadioThread=WARN +#log4j.logger.PrtCnvRadioThread.statistic=WARN +#log4j.logger.PrtCnvRadioTrafficThread=WARN +#log4j.logger.PrtCnvStoredCentralTelegram=WARN +#log4j.logger.PrtCnvStoredRadioTelegram=WARN +#log4j.logger.PrtCnvStoredRadioTelegram=WARN +#log4j.logger.PrtCnvTelegramLogThread=WARN +#log4j.logger.PrtCnvThreadStarter=WARN + +# Appender +############ +log4j.appender.file=Lts::RollingFileAppender +log4j.appender.file.MaxFileSize=10MB +log4j.appender.file.MaxBackupIndex=9 +#will be replace by ngllogger +#log4j.appender.file.file=${HOME}/log/PrtCnv.log +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n + +# Appnd_Console +########################################################### +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n + diff --git a/TetraIF/PrtCnv/logger.cpp b/TetraIF/PrtCnv/logger.cpp new file mode 100644 index 000000000..6bbb33031 --- /dev/null +++ b/TetraIF/PrtCnv/logger.cpp @@ -0,0 +1,30 @@ + + + +#include "logger.h" + +#include + +namespace PrtCnv +{ + +LOGGER_T getLogger(const char *name) +{ + static const char ns[] = "PRT."; + std::string loggerName; + const size_t len = strlen(name); + loggerName.reserve(sizeof(ns) + len); + loggerName.append(ns, sizeof(ns) - 1); + loggerName.append(name, len); + + try { + return NGL::NGLLoggerBootstrap::getNGLRootLogger(). + getNGLLogger( loggerName ); + } catch ( const std::exception &ex ) + { + fprintf(stderr, "Error retrieving logger: %s", ex.what()); + abort(); + } +} + +} diff --git a/TetraIF/PrtCnv/logger.h b/TetraIF/PrtCnv/logger.h new file mode 100644 index 000000000..198d77a70 --- /dev/null +++ b/TetraIF/PrtCnv/logger.h @@ -0,0 +1,18 @@ + + + +#pragma once + +#include + +namespace PrtCnv +{ + +typedef NGL::INGLLogger& LOGGER_T; + +LOGGER_T getLogger(const char *name); +inline LOGGER_T getLogger(const QString &loggerName) +{ + return getLogger(loggerName.toUtf8().constData()); +} +} diff --git a/Z/src/CMakeLists.txt b/Z/src/CMakeLists.txt new file mode 100755 index 000000000..2ff050a95 --- /dev/null +++ b/Z/src/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +ADD_SUBDIRECTORY(ngldb) +ADD_SUBDIRECTORY(tcpserver) +ADD_SUBDIRECTORY(QtSingleApplication) +ADD_SUBDIRECTORY(WMS_Interface) +ADD_SUBDIRECTORY(nglapplication) +ADD_SUBDIRECTORY(nglcompression) +ADD_SUBDIRECTORY(nglsettings) +ADD_SUBDIRECTORY(ngltranslator) +ADD_SUBDIRECTORY(ngltools) +ADD_SUBDIRECTORY(nglwidgets) +ADD_SUBDIRECTORY(NGLLogger) diff --git a/Z/src/NGLLogger/CMakeLists.txt b/Z/src/NGLLogger/CMakeLists.txt new file mode 100755 index 000000000..ea6074d6f --- /dev/null +++ b/Z/src/NGLLogger/CMakeLists.txt @@ -0,0 +1,50 @@ + +FIND_PACKAGE(Log4Qt REQUIRED) + +# Sourcen +SET(NGLLogger_SRCS + MurmurHash2.cpp + MurmurHash2.h + INGLLogger.h + + NGLLogger_export.h + NGLLoggerBootstrap.cpp + NGLLoggerBootstrap.h + NGLLogger.cpp + NGLLogger.h +) + +# Header +SET(NGLLogger_HDRS +) + +# Make sure NGLLogger.h compiles .. +ADD_DEFINITIONS(-DBUILDING_NGLLOGGER) +NGL_ADD_LIBRARY(ALL NGLLogger SHARED ${NGLLogger_SRCS} ${NGLLogger_HDRS}) +NGL_TARGET_INCLUDE_DIRECTORIES(NGLLogger + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(NGLLogger + PRIVATE + Log4Qt::log4qt + PUBLIC + Qt5::Core +) + +NGL_INSTALL_TARGET(NGLLogger) + +# +# test_ngllogger +# +IF(BUILD_TESTING AND TARGET NGLLogger) + ADD_EXECUTABLE(test_ngllogger test_ngllogger.cpp) + TARGET_LINK_LIBRARIES(test_ngllogger NGLLogger) + TARGET_LINK_LIBRARIES(test_ngllogger + Log4Qt::log4qt + ngltools + ) + ADD_TEST(NAME test_ngllogger COMMAND $) +ENDIF(BUILD_TESTING AND TARGET NGLLogger) + +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/log4cxx.props ${CMAKE_BINARY_DIR}/log4cxx.props COPYONLY) diff --git a/Z/src/NGLLogger/INGLLogger.h b/Z/src/NGLLogger/INGLLogger.h new file mode 100755 index 000000000..9bb50cc20 --- /dev/null +++ b/Z/src/NGLLogger/INGLLogger.h @@ -0,0 +1,306 @@ + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include "NGLLogger_export.h" + +namespace NGL +{ +class INGLLogger; + +enum class LogLevel +{ + Undefined = 0, + Trace = 64, + Debug = 96, + Info = 128, + Warning = 150, + Error = 182, + Fatal = 214, +}; + +class LogStreamHelper +{ +public: + inline LogStreamHelper(INGLLogger &logger, LogLevel level, const char *const file, int line, const char *const function) + : m_logger(logger) + , m_level(level) + , m_line(line) + , m_file(file) + , m_func(function) + {} + inline ~LogStreamHelper(); + + template + inline LogStreamHelper &operator<<(const T &val); + +private: + std::ostringstream m_buffer; + NGL::INGLLogger &m_logger; + const LogLevel m_level; + const int m_line; + const char *const m_file; + const char *const m_func; +}; + + + + + + + +class INGLLogger +{ +public: + INGLLogger(const INGLLogger &) = delete; + INGLLogger &operator=(const INGLLogger &) = delete; + INGLLogger() = default; + virtual ~INGLLogger() = default; + + using String = std::string; + + + + + + virtual INGLLogger &getNGLLogger(const char *fullqualifiedname) = 0; + virtual INGLLogger &getNGLLogger(const std::string &fullqualifiedname) = 0; + + + + virtual bool isTraceEnabled() const = 0; + virtual bool isDebugEnabled() const = 0; + virtual bool isInfoEnabled() const = 0; + virtual bool isWarningEnabled() const = 0; + virtual bool isErrorEnabled() const = 0; + virtual bool isFatalEnabled() const = 0; + virtual bool isLevelEnabled(LogLevel level) const = 0; + + + + virtual void log(LogLevel level, const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + + virtual void logTrace(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logDebug(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logInfo(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logWarning(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logError(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logFatal(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + + virtual void logStartup(const char *file, int line, const char *function = nullptr) = 0; + + virtual void logShutdown(const char *file, int line, const char *function = nullptr) = 0; + + + virtual std::string getLoggerName() const = 0; + + virtual void setNoSpace(bool bNoSpace) = 0; + virtual bool noSpace() const = 0; +}; + + + + +inline LogStreamHelper::~LogStreamHelper() +{ + m_logger.log(m_level, m_buffer.str(), m_file, m_line, m_func); +} + +template +inline LogStreamHelper &LogStreamHelper::operator<<(const T &val) +{ + m_buffer << val; + if (!m_logger.noSpace()) + m_buffer << " "; + return *this; +} + + +} + +inline std::ostream &operator<<(std::ostream &stream, const QByteArray &str) +{ + stream << std::string(str.data(), str.size()); + return stream; +} + + + + +inline std::ostream &operator<<(std::ostream &stream, + const QPointF &value) +{ + stream << "QPointF(" << QString::number(value.x(), 'f', 6).toStdString() << "#" << QString::number(value.y(), 'f', 6).toStdString() << ")"; + return stream; +} + + + +inline std::ostream &operator<< (std::ostream &stream, + const QPoint &value) +{ + stream << "QPoint(" << value.x() << "#" << value.y() << ")"; + return stream; +} + +inline std::ostream &operator<< (std::ostream &stream, + const QSize &value) +{ + stream << "QSize(w=" << value.width() << ";h=" << value.height() << ")"; + return stream; +} +inline std::ostream &operator<< (std::ostream &stream, + const QSizeF &value) +{ + stream << "QSize(w=" + << QString::number(value.width(), 'f', 6).toStdString() << ";h=" + << QString::number(value.height(), 'f', 6).toStdString() + << ")"; + return stream; +} + + +inline std::ostream &operator<< (std::ostream &stream, + const QRect &value) +{ + stream << "QRect(center=" << value.center() + << " w=" << value.width() + << ";h=" << value.height() + << " bottomLeft=" << value.bottomLeft() + << " topRight=" << value.topRight() + << ")"; + return stream; +} + +inline std::ostream &operator<< (std::ostream &stream, + const QRectF &value) +{ + stream << "QRectF(center=" << value.center() + << " w=" << QString::number(value.width(), 'f', 3).toStdString() + << ";h=" << QString::number(value.height(), 'f', 3).toStdString() + << " bottomLeft=" << value.bottomLeft() + << " topRight=" << value.topRight() + << ")"; + return stream; +} + + + +inline std::ostream &operator<< (std::ostream &stream, + const QList &value) +{ + stream << "QList(" << value.size() << "): "; + for (int i : value) + stream << i << ";"; + return stream; +} + + +inline std::ostream &operator<< (std::ostream &stream, + const QList &value) +{ + stream << "QList(" << value.size() << "): "; + for (const QPointF &item : value) + stream << item << ";"; + return stream; +} + + +inline std::ostream &operator<<(std::ostream &stream, const QString &str) +{ + return stream << str.toUtf8(); +} + +namespace NGL +{ + +namespace NGLLoggerHelper +{ +NGLLOGGER_EXPORT void hexDumpHelper(NGL::INGLLogger &logger, + NGL::LogLevel level, + const void *a_data, + const unsigned int a_size); +inline void hexDumpHelper(NGL::INGLLogger &logger, + NGL::LogLevel level, + const QByteArray &data) +{ + return hexDumpHelper(logger, level, data.data(), data.size()); +} +} + +NGLLOGGER_EXPORT NGL::INGLLogger& getMemoryLogger(); +NGLLOGGER_EXPORT std::string getMemoryData(); + +} + + + + + +#define LOGFUNCTION Q_FUNC_INFO + + +#define NOTICE_LOG(logger) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO) + +#ifdef LTS_DEBUG +#define TRACE_LOG(logger) \ + for (bool log_level_enabled = (logger).isTraceEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Trace, __FILE__,__LINE__, Q_FUNC_INFO) +#else +#define TRACE_LOG(logger) \ + for ( ; false; ) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Trace, __FILE__,__LINE__, Q_FUNC_INFO) +#endif + +#define DEBUG_LOG(logger) \ + for (bool log_level_enabled = (logger).isDebugEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Debug, __FILE__,__LINE__, Q_FUNC_INFO) + +#define INFO_LOG(logger) \ + for (bool log_level_enabled = (logger).isInfoEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO) + +#define WARNING_LOG(logger) \ + for (bool log_level_enabled = (logger).isWarningEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Warning, __FILE__,__LINE__, Q_FUNC_INFO) + +#define ERROR_LOG(logger) \ + for (bool log_level_enabled = (logger).isErrorEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Error, __FILE__,__LINE__, Q_FUNC_INFO) + +#define FATAL_LOG(logger) \ + for (bool log_level_enabled = (logger).isFatalEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Fatal, __FILE__,__LINE__, Q_FUNC_INFO) + +#define STARTUP_LOG(logger) { (logger).logStartup(__FILE__, __LINE__, Q_FUNC_INFO); } +#define SHUTDOWN_LOG(logger) { (logger).logShutdown(__FILE__, __LINE__, Q_FUNC_INFO); } + + + + + + + + +#define MEMORY_LOG() \ + for (bool log_level_enabled = (NGL::getMemoryLogger()).isInfoEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(NGL::getMemoryLogger(), NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO) << NGL::getMemoryData() + + diff --git a/Z/src/NGLLogger/MurmurHash2.cpp b/Z/src/NGLLogger/MurmurHash2.cpp new file mode 100755 index 000000000..8a5ecaeb1 --- /dev/null +++ b/Z/src/NGLLogger/MurmurHash2.cpp @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + +#include "MurmurHash2.h" +#include + +namespace NGL +{ +unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) +{ + + + + const unsigned int m = 0x5bd1e995; + const int r = 24; + + + + unsigned int h = seed ^ len; + + + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + unsigned int k = *(reinterpret_cast(data)); + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + + + switch(len) + { + case 3: h ^= data[2] << 16; + Q_FALLTHROUGH(); + case 2: h ^= data[1] << 8; + Q_FALLTHROUGH(); + case 1: h ^= data[0]; + h *= m; + }; + + + + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} +} diff --git a/Z/src/NGLLogger/MurmurHash2.h b/Z/src/NGLLogger/MurmurHash2.h new file mode 100755 index 000000000..7dc1b579d --- /dev/null +++ b/Z/src/NGLLogger/MurmurHash2.h @@ -0,0 +1,9 @@ + + + +#pragma once + +namespace NGL +{ +unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed = 0 ); +} diff --git a/Z/src/NGLLogger/NGLLogger.cpp b/Z/src/NGLLogger/NGLLogger.cpp new file mode 100755 index 000000000..6dab4f632 --- /dev/null +++ b/Z/src/NGLLogger/NGLLogger.cpp @@ -0,0 +1,446 @@ + + + +#include "NGLLogger.h" +#include "MurmurHash2.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace NGL +{ + +void LtsRollingFileAppender::setLtsLogfileName(const QString <sLogfileName) +{ + m_ltsLogfileName = ltsLogfileName; +} + +void LtsRollingFileAppender::activateOptions() +{ + if (!m_ltsLogfileName.isEmpty()) + setFile(m_ltsLogfileName); + Log4Qt::RollingFileAppender::activateOptions(); +} + +QString LtsRollingFileAppender::m_ltsLogfileName; +static Log4Qt::Appender *createLtsRollingFileAppender() +{ + auto ret = new LtsRollingFileAppender; + ret->setAppendFile(true); + return ret; +} + + + + + +class CleanupHelper final +{ +public: + CleanupHelper() = default; + ~CleanupHelper(); + std::mutex &getLoggerMapMutex(); + + std::unordered_map m_loggermap; +protected: + std::mutex m_loggermapmutex; +}; + + + + + +NGL::NGLLogger *NGL::NGLLogger::rootlogger_ptr = nullptr; + +NGL::CleanupHelper NGL::NGLLogger::s_cleanup; + + + + +CleanupHelper::~CleanupHelper() +{ + std::lock_guard lock(m_loggermapmutex); + + for (auto it : m_loggermap) + delete it.second; + m_loggermap.clear(); + + delete NGL::NGLLogger::rootlogger_ptr; + NGL::NGLLogger::rootlogger_ptr = nullptr; +} + +std::mutex &CleanupHelper::getLoggerMapMutex() +{ + return m_loggermapmutex; +} +} + + + + +NGL::NGLLogger::NGLLogger(const std::string &fullqualifiedname) + : name(fullqualifiedname) + , currentLevel(LogLevel::Undefined) + , m_bNoSpace(true) +{ + if (!fullqualifiedname.empty()) + { + logger_ptr = Log4Qt::LogManager::loggerRepository()->logger(QString::fromStdString(name)); + s_cleanup.m_loggermap[MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size())] = this; + } + else + { + logger_ptr = Log4Qt::LogManager::loggerRepository()->rootLogger(); + + } + + + configChanged(); +} + + + + + +NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const char *fullqualifiedname) +{ + std::lock_guard lock(s_cleanup.getLoggerMapMutex()); + auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname, strlen(fullqualifiedname))); + if (it != s_cleanup.m_loggermap.end()) + return *(*it).second; + + return *(new NGLLogger(fullqualifiedname)); +} + + + + + +NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const std::string &fullqualifiedname) +{ + std::lock_guard lock(s_cleanup.getLoggerMapMutex()); + auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size())); + if (it != s_cleanup.m_loggermap.end()) + return *(*it).second; + + return *(new NGLLogger(fullqualifiedname)); +} + + + + + +void NGL::NGLLogger::log(LogLevel level, const INGLLogger::String &message, const char *file, int line, const char *function) +{ + logger_ptr->logWithLocation(static_cast(level), file, line, function, QString::fromStdString(message)); +} + + + + + +void NGL::NGLLogger::logTrace(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Trace) + log(LogLevel::Trace, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logDebug(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Debug) + log(LogLevel::Debug, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logInfo(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Info) + log(LogLevel::Info, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logWarning(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Warning) + log(LogLevel::Warning, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logError(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Error) + log(LogLevel::Error, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logFatal(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + log(LogLevel::Fatal, message, file, line, function); +} + + + + +#ifndef LTS_VERSION_MAJOR +#define LTS_VERSION_MAJOR "undefined" +#endif +#ifndef LTS_VERSION_MINOR +#define LTS_VERSION_MINOR "undefined" +#endif +#ifndef LTS_VERSION_PATCH +#define LTS_VERSION_PATCH "undefined" +#endif +#ifndef LTS_VERSION_DATE +#define LTS_VERSION_DATE "undefined" +#endif +#ifndef JENKINS_BUILD_NUMBER +#define JENKINS_BUILD_NUMBER "unknown" +#endif +static const char ver_major[] = LTS_VERSION_MAJOR; +static const char ver_minor[] = LTS_VERSION_MINOR; +static const char ver_patch[] = LTS_VERSION_PATCH; +static const char ver_date[] = LTS_VERSION_DATE; +static const char ver_jenkins[] = JENKINS_BUILD_NUMBER; + +void NGL::NGLLogger::logStartup(const char *file, int line, const char *function) +{ + log(LogLevel::Info, QStringLiteral("Application is started (%1.%2-%3 rev%4 from %5)") + .arg(QString::fromLatin1(ver_major), + QString::fromLatin1(ver_minor), + QString::fromLatin1(ver_jenkins), + QString::fromLatin1(ver_patch), + QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function); +} + + + + +void NGL::NGLLogger::logShutdown(const char *file, int line, const char *function) +{ + log(LogLevel::Info, QStringLiteral("Application is shut down (%1.%2-%3 rev%4 from %5)") + .arg(QString::fromLatin1(ver_major), + QString::fromLatin1(ver_minor), + QString::fromLatin1(ver_jenkins), + QString::fromLatin1(ver_patch), + QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function); +} + + + + + +NGL::NGLLogger &NGL::NGLLogger::getNGLRootLogger() +{ + if (!rootlogger_ptr) throw NotCreatedError(); + return *rootlogger_ptr; +} + + + + +static QString findConfigFile(const QString &configfilename) +{ + if (configfilename.isEmpty()) + return QString(); + + + QFileInfo fi(configfilename); + if (fi.isFile() && fi.isReadable()) + return fi.absoluteFilePath(); + + + QString p = QCoreApplication::applicationDirPath() + QLatin1Char('/') + configfilename; + fi.setFile(p); + if (fi.isFile() && fi.isReadable()) + return fi.absoluteFilePath(); + + return QString(); +} + + + + +NGL::NGLLogger &NGL::NGLLogger::createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName, + bool quiet) +{ + if (rootlogger_ptr) + { + if (!ignorealreadycreated) throw AlreadyCreatedError(); + } + else + { + Log4Qt::Factory::registerAppender("Lts::RollingFileAppender", createLtsRollingFileAppender); + LtsRollingFileAppender::setLtsLogfileName(logOutputName); + + rootlogger_ptr = new NGLLogger(std::string()); + const QString filename = findConfigFile(configfilename); + if (!filename.isEmpty()) + { + Log4Qt::PropertyConfigurator::configureAndWatch(filename); + QObject::connect(Log4Qt::ConfiguratorHelper::instance(), &Log4Qt::ConfiguratorHelper::configurationFileChanged, + []() { configurationFileChanged(); }); + const auto l = Log4Qt::ConfiguratorHelper::instance()->configureError(); + for (const auto &t : l) + std::cerr << t.message().toUtf8().data() << std::endl; + if (!l.isEmpty()) + exit(-1); + } + else + { + if (!quiet) + std::cerr << "Could not find log4cxx configuration file " << configfilename << std::endl + << "Using default logging to stdout" << std::endl; + + + Log4Qt::Properties props; + props.setProperty(QLatin1String("log4j.rootLogger"), + QLatin1String("WARN, stdout")); + props.setProperty(QLatin1String("log4j.appender.stdout"), + QLatin1String("org.apache.log4j.ConsoleAppender")); + props.setProperty(QLatin1String("log4j.appender.stdout.layout"), + QLatin1String("org.apache.log4j.PatternLayout")); + props.setProperty(QLatin1String("log4j.appender.stdout.layout.ConversionPattern"), + QLatin1String("%d %-5p %c |#| %m (%.50F:%L) %n")); + Log4Qt::PropertyConfigurator::configure(props); + } + rootlogger_ptr->configChanged(); + } + return *rootlogger_ptr; +} + +void NGL::NGLLogger::configurationFileChanged() +{ + for (auto ptr : s_cleanup.m_loggermap) + ptr.second->configChanged(); +} + +void NGL::NGLLogger::configChanged() +{ + if (logger_ptr->isTraceEnabled()) + currentLevel = LogLevel::Trace; + else if (logger_ptr->isDebugEnabled()) + currentLevel = LogLevel::Debug; + else if (logger_ptr->isInfoEnabled()) + currentLevel = LogLevel::Info; + else if (logger_ptr->isWarnEnabled()) + currentLevel = LogLevel::Warning; + else if (logger_ptr->isErrorEnabled()) + currentLevel = LogLevel::Error; + else + currentLevel = LogLevel::Fatal; +} + +namespace NGL +{ +namespace NGLLoggerHelper +{ + +void hexDumpHelper(NGL::INGLLogger &logger, NGL::LogLevel level, + const void *a_data, const unsigned int a_size) +{ + if (!logger.isLevelEnabled(level) || !a_data) + return; + + unsigned char *data = (unsigned char *)a_data; + QByteArray baBuf; + for (unsigned int i = 0; i < a_size; i++) + { + if (0 == (i % 8)) + baBuf = QByteArray::number(i, 16).rightJustified(8, '0').toUpper(); + baBuf += " " + QByteArray::number(data[i], 16).rightJustified(2, '0').toUpper(); + if (7 == (i % 8)) + logger.log(level, baBuf.constData(), __FILE__, __LINE__); + } + if (a_size % 8) + logger.log(level, baBuf.constData(), __FILE__, __LINE__); +} + +} + + +NGL::INGLLogger& getMemoryLogger() +{ + try + { + return NGLLogger::getNGLRootLogger().getNGLLogger("memorystate"); + + } + catch (const std::exception &ex) + { + fprintf(stderr, "Error retrieving logger: %s", ex.what()); + abort(); + } +} + +int parseLine(char* line){ + + int i = strlen(line); + const char* p = line; + while (*p <'0' || *p > '9') p++; + line[i-3] = '\0'; + i = atoi(p); + return i; +} + +int getMemoryValue() +{ + + FILE* file = fopen("/proc/self/status", "r"); + int result = -1; + char line[128]; + + while (fgets(line, 128, file) != NULL){ + + if (strncmp(line, "VmRSS:", 6) == 0){ + result = parseLine(line); + break; + } + } + fclose(file); + return result; +} + +std::string getMemoryData() +{ + return QStringLiteral("VmRSS: %1 kB #").arg(QString::number(getMemoryValue())).toStdString(); +} + + +} + + + + diff --git a/Z/src/NGLLogger/NGLLogger.h b/Z/src/NGLLogger/NGLLogger.h new file mode 100755 index 000000000..3d23a46e4 --- /dev/null +++ b/Z/src/NGLLogger/NGLLogger.h @@ -0,0 +1,94 @@ + + + +#pragma once + +#ifndef BUILDING_NGLLOGGER +#error Do not include me outside NGLLogger library - only use INGLLogger.h! +#endif + +#include "INGLLogger.h" + +#include + +#include +#include + +namespace NGL +{ + +class CleanupHelper; + +class LtsRollingFileAppender final : public Log4Qt::RollingFileAppender +{ + Q_OBJECT +public: + using Log4Qt::RollingFileAppender::RollingFileAppender; + static void setLtsLogfileName(const QString <sLogfileName); + void activateOptions() override; +private: + static QString m_ltsLogfileName; +}; + +class NGLLogger final : public INGLLogger +{ + explicit NGLLogger(const std::string &fullqualifiedname); +public: + + class NotCreatedError {}; + class AlreadyCreatedError {}; + + INGLLogger &getNGLLogger(const char *fullqualifiedname) override; + INGLLogger &getNGLLogger(const std::string &fullqualifiedname) override; + + inline bool isTraceEnabled() const override { return currentLevel <= LogLevel::Trace; } + inline bool isDebugEnabled() const override { return currentLevel <= LogLevel::Debug; } + inline bool isInfoEnabled() const override { return currentLevel <= LogLevel::Info; } + inline bool isWarningEnabled() const override { return currentLevel <= LogLevel::Warning; } + inline bool isErrorEnabled() const override { return currentLevel <= LogLevel::Error; } + inline bool isFatalEnabled() const override { return currentLevel <= LogLevel::Fatal; } + inline bool isLevelEnabled(LogLevel level) const override { return currentLevel <= level; } + + void log(LogLevel level, const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logTrace(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logDebug(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logInfo(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logWarning(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logError(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logFatal(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + + void logStartup(const char *file, int line, const char *function = nullptr) override; + void logShutdown(const char *file, int line, const char *function = nullptr) override; + + inline void setNoSpace(bool bNoSpace) override { m_bNoSpace = bNoSpace; } + inline bool noSpace() const override { return m_bNoSpace; } + + inline std::string getLoggerName() const override { return name; } + + static NGLLogger &getNGLRootLogger(); + static NGLLogger &createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName = QString(), + bool quiet = false); + + Log4Qt::Logger *log4qtLogger() { return logger_ptr; } +protected: + static void configurationFileChanged(); + void configChanged(); + +private: + + Log4Qt::Logger *logger_ptr; + const std::string name; + LogLevel currentLevel; + bool m_bNoSpace; + + static NGLLogger *rootlogger_ptr; + + friend class CleanupHelper; + static CleanupHelper s_cleanup; + + friend class XMLWatchdog; +}; + +} diff --git a/Z/src/NGLLogger/NGLLoggerBootstrap.cpp b/Z/src/NGLLogger/NGLLoggerBootstrap.cpp new file mode 100755 index 000000000..84d8b382f --- /dev/null +++ b/Z/src/NGLLogger/NGLLoggerBootstrap.cpp @@ -0,0 +1,30 @@ + + + +#include "NGLLoggerBootstrap.h" +#include "NGLLogger.h" + + + + + +NGL::INGLLogger & NGL::NGLLoggerBootstrap::getNGLRootLogger() +{ + return NGL::NGLLogger::getNGLRootLogger(); +} + + + + + +NGL::INGLLogger & NGL::NGLLoggerBootstrap::createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName, + bool quiet) +{ + return NGL::NGLLogger::createNGLRootLogger(configfilename, ignorealreadycreated, logOutputName, quiet); +} + + + + diff --git a/Z/src/NGLLogger/NGLLoggerBootstrap.h b/Z/src/NGLLogger/NGLLoggerBootstrap.h new file mode 100755 index 000000000..2b767b522 --- /dev/null +++ b/Z/src/NGLLogger/NGLLoggerBootstrap.h @@ -0,0 +1,59 @@ + + + +#ifndef NGLLOGGERBOOTSTRAP_H +#define NGLLOGGERBOOTSTRAP_H + +#include "INGLLogger.h" +#include "NGLLogger_export.h" + +namespace NGL +{ + +namespace NGLLoggerBootstrap +{ +class AlreadyCreatedError final : public std::exception +{ + const char* what() const noexcept override + { + return "NGLLogger rootlogger already created!"; + } +}; + +class NotCreatedError final : public std::exception +{ + const char* what() const noexcept override + { + return "NGLLogger rootlogger not yet created!"; + } +}; + + + + +NGLLOGGER_EXPORT INGLLogger &getNGLRootLogger(); + + + + + + + + +NGLLOGGER_EXPORT INGLLogger &createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName = QString(), + bool quiet = false); +inline INGLLogger &createNGLRootLogger(const char *configfilename, + bool ignorealreadycreated, + const QString &logOutputName = QString()) +{ + return createNGLRootLogger(QString::fromUtf8(configfilename), ignorealreadycreated, logOutputName); +} + +} + +} + + +#endif diff --git a/Z/src/NGLLogger/NGLLogger_export.h b/Z/src/NGLLogger/NGLLogger_export.h new file mode 100755 index 000000000..a998ace10 --- /dev/null +++ b/Z/src/NGLLogger/NGLLogger_export.h @@ -0,0 +1,22 @@ + + +#ifndef NGLLOGGER_EXPORT_H +#define NGLLOGGER_EXPORT_H + +#ifndef NGLLOGGER_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLLOGGER_EXPORT +# else +# ifdef WIN32 +# ifdef MAKE_NGLLOGGER_LIB +# define NGLLOGGER_EXPORT __declspec(dllexport) +# else +# define NGLLOGGER_EXPORT __declspec(dllimport) +# endif +# else +# define NGLLOGGER_EXPORT __attribute__((visibility("default"))) +# endif +# endif +#endif + +#endif diff --git a/Z/src/NGLLogger/log4cxx.props b/Z/src/NGLLogger/log4cxx.props new file mode 100755 index 000000000..210d66b5c --- /dev/null +++ b/Z/src/NGLLogger/log4cxx.props @@ -0,0 +1,42 @@ +log4j.reset=true +log4j.rootLogger=ERROR, stdout + +log4j.logger.Gui=TRACE, console +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%p %d %t %c{1} - %F:%L %m%n + + +log4j.logger.ngs=FATAL, stdout +log4j.logger.ngs.Application_1=INFO, file +log4j.logger.ngs.Application_2=ERROR +log4j.logger.ngs.Application_3=ERROR + +log4j.logger.libsymbol.SymbolTable=WARN, stdout +log4j.logger.libsymbol.SymbolReader=WARN, stdout +log4j.logger.libngldb=INFO, stdout + +log4j.logger.NGL.main=INFO, stdout, file +log4j.logger.NGL.MainWindow=INFO, stdout, file +log4j.logger.NGL.zwmsqt=INFO, stdout, file + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=#ngs# %r %p %d %t %c %c{1} - %F:%L %m%n + +log4j.appender.file=org.apache.log4j.RollingFileAppender +log4j.appender.file.MaxFileSize=1MB +log4j.appender.file.MaxBackupIndex=9 +log4j.appender.file.file=log.out +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=#ngs# %r %p %d %t %c %c{1} - %F:%L %m%n + +log4j.appender.syslog=org.apache.log4j.SyslogAppender +log4j.appender.syslog.Threshold=WARN +log4j.appender.syslog.SysLogHost=localhost +log4j.appender.syslog.Facility=LOCAL7 +log4j.appender.syslog.layout=org.apache.log4j.PatternLayout +log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m +log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true +log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO +log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL diff --git a/Z/src/NGLLogger/test_ngllogger.cpp b/Z/src/NGLLogger/test_ngllogger.cpp new file mode 100755 index 000000000..96549d6ea --- /dev/null +++ b/Z/src/NGLLogger/test_ngllogger.cpp @@ -0,0 +1,34 @@ +#include "INGLLogger.h" +#include "NGLLoggerBootstrap.h" +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx.props", false); + + NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger(). getNGLLogger( "Gui" ); + + STARTUP_LOG(l); + SHUTDOWN_LOG(l); + NOTICE_LOG(l) << "Gui - NOTICE"; + TRACE_LOG(l) << "Gui - TRACE"; + DEBUG_LOG(l) << "Gui - DEBUG"; + INFO_LOG(l) << "Gui - INFO"; + WARNING_LOG(l) << "Gui - WARNING"; + ERROR_LOG(l) << "Gui - ERROR"; + FATAL_LOG(l) << "Gui - FATAL"; + + NGL::INGLLogger &l2 = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger( "Gui.AES" ); + NOTICE_LOG(l2) << "Gui.AES - NOTICE"; + TRACE_LOG(l2) << "Gui.AES - TRACE"; + DEBUG_LOG(l2) << "Gui.AES - DEBUG"; + INFO_LOG(l2) << "Gui.AES - INFO"; + WARNING_LOG(l2) << "Gui.AES - WARNING"; + ERROR_LOG(l2) << "Gui.AES - ERROR"; + FATAL_LOG(l2) << "Gui.AES - FATAL"; + SHUTDOWN_LOG(l2) + + return 0; +} diff --git a/Z/src/QtSingleApplication/CMakeLists.txt b/Z/src/QtSingleApplication/CMakeLists.txt new file mode 100755 index 000000000..0159d87b7 --- /dev/null +++ b/Z/src/QtSingleApplication/CMakeLists.txt @@ -0,0 +1,51 @@ +# QtSingleApplication solution from +# http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Utilities/qtsingleapplication +# LGPL + +SET(qtsapp_common_SRCS + qtlocalpeer.cpp + qtlocalpeer.h +) +QT5_WRAP_CPP(qtsapp_common_SRCS qtlockedfile.h) +NGL_ADD_LIBRARY(WS AAR SV qtsa_common STATIC ${qtsapp_common_SRCS}) +NGL_TARGET_LINK_LIBRARIES(qtsa_common + PUBLIC + Qt5::Network + Qt5::Core +) + +SET(qtsapp_SRCS + qtsingleapplication.cpp + qtsingleapplication.h + +) +NGL_ADD_LIBRARY(WS qtsingleapplication SHARED ${qtsapp_SRCS}) +NGL_INSTALL_TARGET(qtsingleapplication) +NGL_TARGET_INCLUDE_DIRECTORIES(qtsingleapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) +NGL_TARGET_LINK_LIBRARIES(qtsingleapplication + PRIVATE + qtsa_common + PUBLIC + Qt5::Core + Qt5::Widgets +) + +SET(qtscoreapp_SRCS + qtsinglecoreapplication.h + qtsinglecoreapplication.cpp +) +NGL_ADD_LIBRARY(AAR SV qtsinglecoreapplication SHARED ${qtscoreapp_SRCS}) +NGL_INSTALL_TARGET(qtsinglecoreapplication) +NGL_TARGET_INCLUDE_DIRECTORIES(qtsinglecoreapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) +NGL_TARGET_LINK_LIBRARIES(qtsinglecoreapplication + PRIVATE + qtsa_common + PUBLIC + Qt5::Core +) diff --git a/Z/src/QtSingleApplication/QtLockedFile b/Z/src/QtSingleApplication/QtLockedFile new file mode 100755 index 000000000..642afda07 --- /dev/null +++ b/Z/src/QtSingleApplication/QtLockedFile @@ -0,0 +1 @@ +#include "qtlockedfile.h" diff --git a/Z/src/QtSingleApplication/QtSingleApplication b/Z/src/QtSingleApplication/QtSingleApplication new file mode 100755 index 000000000..baa6ea94a --- /dev/null +++ b/Z/src/QtSingleApplication/QtSingleApplication @@ -0,0 +1 @@ +#include "qtsingleapplication.h" diff --git a/Z/src/QtSingleApplication/QtSingleCoreApplication b/Z/src/QtSingleApplication/QtSingleCoreApplication new file mode 100755 index 000000000..d247e7528 --- /dev/null +++ b/Z/src/QtSingleApplication/QtSingleCoreApplication @@ -0,0 +1 @@ +#include "qtsinglecoreapplication.h" diff --git a/Z/src/QtSingleApplication/qtlocalpeer.cpp b/Z/src/QtSingleApplication/qtlocalpeer.cpp new file mode 100755 index 000000000..641d5abee --- /dev/null +++ b/Z/src/QtSingleApplication/qtlocalpeer.cpp @@ -0,0 +1,167 @@ + + + + +#include "qtlocalpeer.h" +#include +#include +#include + +#if defined(Q_OS_WIN) +#include +#include +typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); +static PProcessIdToSessionId pProcessIdToSessionId = 0; +#endif +#if defined(Q_OS_UNIX) +#include +#include +#include +#endif + +namespace QtLP_Private { +#include "qtlockedfile.cpp" +#if defined(Q_OS_WIN) +#include "qtlockedfile_win.cpp" +#else +#include "qtlockedfile_unix.cpp" +#endif +} + +const char* QtLocalPeer::ack = "ack"; + +QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) + : QObject(parent), id(appId) +{ + QString prefix = id; + if (id.isEmpty()) { + id = QCoreApplication::applicationFilePath(); +#if defined(Q_OS_WIN) + id = id.toLower(); +#endif + prefix = id.section(QLatin1Char('/'), -1); + } + prefix.remove(QRegExp(QLatin1String("[^a-zA-Z]"))); + prefix.truncate(6); + + QByteArray idc = id.toUtf8(); + quint16 idNum = qChecksum(idc.constData(), idc.size()); + socketName = QLatin1String("qtsingleapp-") + prefix + + QLatin1Char('-') + QString::number(idNum, 16); + +#if defined(Q_OS_WIN) + if (!pProcessIdToSessionId) { + QLibrary lib(QLatin1String("kernel32")); + pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); + } + if (pProcessIdToSessionId) { + DWORD sessionId = 0; + pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); + socketName += QLatin1Char('-') + QString::number(sessionId, 16); + } +#else + socketName += QLatin1Char('-') + QString::number(::getuid(), 16); +#endif + + server = new QLocalServer(this); + QString lockName = QDir(QDir::tempPath()).absolutePath() + + QLatin1Char('/') + socketName + + QLatin1String("-lockfile"); + lockFile.setFileName(lockName); + lockFile.open(QIODevice::ReadWrite); +} + + + +bool QtLocalPeer::isClient() +{ + if (lockFile.isLocked()) + return false; + + if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) + return true; + + bool res = server->listen(socketName); +#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) + + if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { + QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName); + res = server->listen(socketName); + } +#endif + if (!res) + qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); + QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection); + return false; +} + + +bool QtLocalPeer::sendMessage(const QString &message, int timeout) +{ + if (!isClient()) + return false; + + QLocalSocket socket; + bool connOk = false; + for(int i = 0; i < 2; i++) { + + socket.connectToServer(socketName); + connOk = socket.waitForConnected(timeout/2); + if (connOk || i) + break; + int ms = 250; +#if defined(Q_OS_WIN) + Sleep(DWORD(ms)); +#else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, nullptr); +#endif + } + if (!connOk) + return false; + + QByteArray uMsg(message.toUtf8()); + QDataStream ds(&socket); + ds.writeBytes(uMsg.constData(), uMsg.size()); + bool res = socket.waitForBytesWritten(timeout); + if (res) { + res &= socket.waitForReadyRead(timeout); + if (res) + res &= (socket.read(qstrlen(ack)) == ack); + } + return res; +} + + +void QtLocalPeer::receiveConnection() +{ + QLocalSocket* socket = server->nextPendingConnection(); + if (!socket) + return; + + while (socket->bytesAvailable() < (int)sizeof(quint32)) + socket->waitForReadyRead(); + QDataStream ds(socket); + QByteArray uMsg; + quint32 remaining; + ds >> remaining; + uMsg.resize(remaining); + int got = 0; + char* uMsgBuf = uMsg.data(); + do { + got = ds.readRawData(uMsgBuf, remaining); + remaining -= got; + uMsgBuf += got; + } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); + if (got < 0) { + qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); + delete socket; + return; + } + QString message(QString::fromUtf8(uMsg)); + socket->write(ack, qstrlen(ack)); + socket->waitForBytesWritten(1000); + socket->waitForDisconnected(1000); + delete socket; + emit messageReceived(message); +} diff --git a/Z/src/QtSingleApplication/qtlocalpeer.h b/Z/src/QtSingleApplication/qtlocalpeer.h new file mode 100755 index 000000000..3b745167a --- /dev/null +++ b/Z/src/QtSingleApplication/qtlocalpeer.h @@ -0,0 +1,40 @@ + + + +#ifndef QTLOCALPEER_H +#define QTLOCALPEER_H + +#include +#include +#include + +#include "qtlockedfile.h" + +class QtLocalPeer : public QObject +{ + Q_OBJECT + +public: + QtLocalPeer(QObject *parent = nullptr, const QString &appId = QString()); + bool isClient(); + bool sendMessage(const QString &message, int timeout); + QString applicationId() const + { return id; } + +Q_SIGNALS: + void messageReceived(const QString &message); + +protected Q_SLOTS: + void receiveConnection(); + +protected: + QString id; + QString socketName; + QLocalServer* server; + QtLP_Private::QtLockedFile lockFile; + +private: + static const char* ack; +}; + +#endif diff --git a/Z/src/QtSingleApplication/qtlockedfile.cpp b/Z/src/QtSingleApplication/qtlockedfile.cpp new file mode 100755 index 000000000..2306c2833 --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile.cpp @@ -0,0 +1,68 @@ + + + +#include "qtlockedfile.h" + + + + + + + + + +QtLockedFile::QtLockedFile() + : QFile() +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + + + +QtLockedFile::QtLockedFile(const QString &name) + : QFile(name) +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + + + +bool QtLockedFile::open(OpenMode mode) +{ + if (mode & QIODevice::Truncate) { + qWarning("QtLockedFile::open(): Truncate mode not allowed."); + return false; + } + return QFile::open(mode); +} + + + +bool QtLockedFile::isLocked() const +{ + return m_lock_mode != NoLock; +} + + + +QtLockedFile::LockMode QtLockedFile::lockMode() const +{ + return m_lock_mode; +} + + + + + + + + + diff --git a/Z/src/QtSingleApplication/qtlockedfile.h b/Z/src/QtSingleApplication/qtlockedfile.h new file mode 100755 index 000000000..0b33d7a2a --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile.h @@ -0,0 +1,61 @@ + + + +#ifndef QTLOCKEDFILE_H +#define QTLOCKEDFILE_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#if defined(Q_OS_WIN) +# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) +# define QT_QTLOCKEDFILE_EXPORT +# elif defined(QT_QTLOCKEDFILE_IMPORT) +# if defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# endif +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) +# elif defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTLOCKEDFILE_EXPORT +#endif + +namespace QtLP_Private { + +class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile +{ + Q_OBJECT +public: + enum LockMode { NoLock = 0, ReadLock, WriteLock }; + + QtLockedFile(); + explicit QtLockedFile(const QString &name); + ~QtLockedFile(); + + bool open(OpenMode mode); + + bool lock(LockMode mode, bool block = true); + bool unlock(); + bool isLocked() const; + LockMode lockMode() const; + +private: +#ifdef Q_OS_WIN + Qt::HANDLE wmutex; + Qt::HANDLE rmutex; + QVector rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; +} +#endif diff --git a/Z/src/QtSingleApplication/qtlockedfile_unix.cpp b/Z/src/QtSingleApplication/qtlockedfile_unix.cpp new file mode 100755 index 000000000..67fcd0727 --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile_unix.cpp @@ -0,0 +1,78 @@ + + + +#include +#include +#include +#include + +#include "qtlockedfile.h" + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; + int cmd = block ? F_SETLKW : F_SETLK; + int ret = fcntl(handle(), cmd, &fl); + + if (ret == -1) { + if (errno != EINTR && errno != EAGAIN) + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + + m_lock_mode = mode; + return true; +} + + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_UNLCK; + int ret = fcntl(handle(), F_SETLKW, &fl); + + if (ret == -1) { + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + m_lock_mode = NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); +} + diff --git a/Z/src/QtSingleApplication/qtlockedfile_win.cpp b/Z/src/QtSingleApplication/qtlockedfile_win.cpp new file mode 100755 index 000000000..d4f97687e --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile_win.cpp @@ -0,0 +1,174 @@ + + + +#include "qtlockedfile.h" +#include +#include + +#define MUTEX_PREFIX "QtLockedFile mutex " + +#define MAX_READERS MAXIMUM_WAIT_OBJECTS + +#if QT_VERSION >= 0x050000 +#define QT_WA(unicode, ansi) unicode +#endif + +Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate) +{ + if (mutexname.isEmpty()) { + QFileInfo fi(*this); + mutexname = QString::fromLatin1(MUTEX_PREFIX) + + fi.absoluteFilePath().toLower(); + } + QString mname(mutexname); + if (idx >= 0) + mname += QString::number(idx); + + Qt::HANDLE mutex; + if (doCreate) { + QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); }, + { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } ); + if (!mutex) { + qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); + return 0; + } + } + else { + QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); }, + { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } ); + if (!mutex) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) + qErrnoWarning("QtLockedFile::lock(): OpenMutex failed"); + return 0; + } + } + return mutex; +} + +bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock) +{ + Q_ASSERT(mutex); + DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0); + switch (res) { + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + return true; + break; + case WAIT_TIMEOUT: + break; + default: + qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed"); + } + return false; +} + + + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + if (!wmutex && !(wmutex = getMutexHandle(-1, true))) + return false; + + if (!waitMutex(wmutex, block)) + return false; + + if (mode == ReadLock) { + int idx = 0; + for (; idx < MAX_READERS; idx++) { + rmutex = getMutexHandle(idx, false); + if (!rmutex || waitMutex(rmutex, false)) + break; + CloseHandle(rmutex); + } + bool ok = true; + if (idx >= MAX_READERS) { + qWarning("QtLockedFile::lock(): too many readers"); + rmutex = 0; + ok = false; + } + else if (!rmutex) { + rmutex = getMutexHandle(idx, true); + if (!rmutex || !waitMutex(rmutex, false)) + ok = false; + } + if (!ok && rmutex) { + CloseHandle(rmutex); + rmutex = 0; + } + ReleaseMutex(wmutex); + if (!ok) + return false; + } + else { + Q_ASSERT(rmutexes.isEmpty()); + for (int i = 0; i < MAX_READERS; i++) { + Qt::HANDLE mutex = getMutexHandle(i, false); + if (mutex) + rmutexes.append(mutex); + } + if (rmutexes.size()) { + DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(), + TRUE, block ? INFINITE : 0); + if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) { + if (res != WAIT_TIMEOUT) + qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed"); + m_lock_mode = WriteLock; + unlock(); + return false; + } + } + } + + m_lock_mode = mode; + return true; +} + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + if (m_lock_mode == ReadLock) { + ReleaseMutex(rmutex); + CloseHandle(rmutex); + rmutex = 0; + } + else { + for (Qt::HANDLE mutex : qAsConst(rmutexes)) { + ReleaseMutex(mutex); + CloseHandle(mutex); + } + rmutexes.clear(); + ReleaseMutex(wmutex); + } + + m_lock_mode = QtLockedFile::NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); + if (wmutex) + CloseHandle(wmutex); +} diff --git a/Z/src/QtSingleApplication/qtsingleapplication.cpp b/Z/src/QtSingleApplication/qtsingleapplication.cpp new file mode 100755 index 000000000..b3a70c2ca --- /dev/null +++ b/Z/src/QtSingleApplication/qtsingleapplication.cpp @@ -0,0 +1,104 @@ + + + + +#include "qtsingleapplication.h" +#include "qtlocalpeer.h" +#include + + + + + + +void QtSingleApplication::sysInit(const QString &appId) +{ + actWin = nullptr; + peer = new QtLocalPeer(this, appId); + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived); +} + + + + + +QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) + : QApplication(argc, argv, GUIenabled) +{ + sysInit(); +} + + + + + +QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) + : QApplication(argc, argv) +{ + sysInit(appId); +} + + + + +bool QtSingleApplication::isRunning() +{ + return peer->isClient(); +} + + + + +bool QtSingleApplication::sendMessage(const QString &message, int timeout) +{ + return peer->sendMessage(message, timeout); +} + + + + +QString QtSingleApplication::id() const +{ + return peer->applicationId(); +} + + + + + +void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) +{ + actWin = aw; + if (activateOnMessage) + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); + else + disconnect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); +} + + + + +QWidget* QtSingleApplication::activationWindow() const +{ + return actWin; +} + + + + +void QtSingleApplication::activateWindow() +{ + if (actWin) { + actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); + actWin->raise(); + actWin->activateWindow(); + } +} + + + + + + + + diff --git a/Z/src/QtSingleApplication/qtsingleapplication.h b/Z/src/QtSingleApplication/qtsingleapplication.h new file mode 100755 index 000000000..82f3507f7 --- /dev/null +++ b/Z/src/QtSingleApplication/qtsingleapplication.h @@ -0,0 +1,56 @@ + + + +#ifndef QTSINGLEAPPLICATION_H +#define QTSINGLEAPPLICATION_H + +#include + +class QtLocalPeer; + +#ifndef QTSINGLEAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define QTSINGLEAPPLICATION_EXPORT +# else +# if defined(MAKE_QTSINGLEAPPLICATION_LIB) +# define QTSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define QTSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +class QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication +{ + Q_OBJECT + +public: + QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); + QtSingleApplication(const QString &appId, int &argc, char **argv); + + bool isRunning(); + QString id() const; + + void setActivationWindow(QWidget* aw, bool activateOnMessage = true); + QWidget* activationWindow() const; + + + void initialize(bool dummy = true) + { isRunning(); Q_UNUSED(dummy) } + +public Q_SLOTS: + bool sendMessage(const QString &message, int timeout = 5000); + void activateWindow(); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + void sysInit(const QString &appId = QString()); + QtLocalPeer *peer; + QWidget *actWin; +}; + +#endif diff --git a/Z/src/QtSingleApplication/qtsinglecoreapplication.cpp b/Z/src/QtSingleApplication/qtsinglecoreapplication.cpp new file mode 100755 index 000000000..7c9cc883d --- /dev/null +++ b/Z/src/QtSingleApplication/qtsinglecoreapplication.cpp @@ -0,0 +1,60 @@ + + + + +#include "qtsinglecoreapplication.h" +#include "qtlocalpeer.h" + + + + + + + +QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv) + : QCoreApplication(argc, argv) +{ + peer = new QtLocalPeer(this); + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleCoreApplication::messageReceived); +} + + + + +QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv) + : QCoreApplication(argc, argv) +{ + peer = new QtLocalPeer(this, appId); + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleCoreApplication::messageReceived); +} + + + + + +bool QtSingleCoreApplication::isRunning() +{ + return peer->isClient(); +} + + + + + +bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) +{ + return peer->sendMessage(message, timeout); +} + + + + + +QString QtSingleCoreApplication::id() const +{ + return peer->applicationId(); +} + + + + diff --git a/Z/src/QtSingleApplication/qtsinglecoreapplication.h b/Z/src/QtSingleApplication/qtsinglecoreapplication.h new file mode 100755 index 000000000..8c23f3ab8 --- /dev/null +++ b/Z/src/QtSingleApplication/qtsinglecoreapplication.h @@ -0,0 +1,46 @@ + + + +#ifndef QTSINGLECOREAPPLICATION_H +#define QTSINGLECOREAPPLICATION_H + +#include + +class QtLocalPeer; + +#ifndef QTSINGLECOREAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define QTSINGLEAPPLICATION_EXPORT +# else +# if defined(MAKE_QTSINGLECOREAPPLICATION_LIB) +# define QTSINGLECOREAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define QTSINGLECOREAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +class QTSINGLECOREAPPLICATION_EXPORT QtSingleCoreApplication : public QCoreApplication +{ + Q_OBJECT + +public: + QtSingleCoreApplication(int &argc, char **argv); + QtSingleCoreApplication(const QString &appId, int &argc, char **argv); + + bool isRunning(); + QString id() const; + +public Q_SLOTS: + bool sendMessage(const QString &message, int timeout = 5000); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + QtLocalPeer* peer; +}; + +#endif diff --git a/Z/src/WMS_Interface/CMakeLists.txt b/Z/src/WMS_Interface/CMakeLists.txt new file mode 100755 index 000000000..3700fc0d8 --- /dev/null +++ b/Z/src/WMS_Interface/CMakeLists.txt @@ -0,0 +1,35 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + + +SET(wms_ds_SRCS + IECC2WMS.h + IWMS2ECC.h + wms_ecc_equipmenttypes.cpp + wms_ecc_equipmenttypes.h + wms_ecc_equipRequirements.cpp + wms_ecc_equipRequirements.h + wms_ecc_exercises.cpp + wms_ecc_exercises.h + wms_ecc_ibase.h + wms_ecc_playerInfo.cpp + wms_ecc_playerInfo.h + wms_ecc_registration.cpp + wms_ecc_registration.h + wms_ecc_unregister.cpp + wms_ecc_unregister.h + json_keys.h + ) + +NGL_ADD_LIBRARY2(AAR SV wms_json_ds SHARED ${wms_ds_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(wms_json_ds + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ) +NGL_TARGET_LINK_LIBRARIES(wms_json_ds + PUBLIC + Qt5::Core + ) diff --git a/Z/src/WMS_Interface/IECC2WMS.h b/Z/src/WMS_Interface/IECC2WMS.h new file mode 100755 index 000000000..4dd163a06 --- /dev/null +++ b/Z/src/WMS_Interface/IECC2WMS.h @@ -0,0 +1,20 @@ + + + +#pragma once + +namespace WmsJson +{ +class IECC2WMS +{ + +public: + IECC2WMS() = default; + virtual ~IECC2WMS() = default; + + + virtual void playerChanged(int playerId, int exerciseId) = 0; + virtual void exerciseDataChanged(int exerciseId, int betrZustand) = 0; + +}; +} diff --git a/Z/src/WMS_Interface/IWMS2ECC.h b/Z/src/WMS_Interface/IWMS2ECC.h new file mode 100755 index 000000000..c91fa42f3 --- /dev/null +++ b/Z/src/WMS_Interface/IWMS2ECC.h @@ -0,0 +1,137 @@ + + +#pragma once + +#include +#include +#include +#include + +class IWMS2ECC +{ + +public: + IWMS2ECC() = default; + virtual ~IWMS2ECC() = default; + + enum RegisterReturnValue + { + RegistrationOk = 0, + PlayerNotFound = 1, + PlayerDeleted = 2, + AssignmentIncorrect = 3, + EquipNoAlreadyAssigned = 4, + RegistrationFailed = 5 + }; + + enum UnregisterReturnValue + { + UnregisterOk = 0, + EquipNoNotFound = 1, + UnregisterFailed = 2 + }; + + enum PlayerState + { + NOT_FOUND = 0, + FOUND = 1, + DELETED = 2 + }; + + enum PlayerAssignState + { + UNDEFINED = -2, + NOT_ASSIGNED = -1, + ASSIGNED = 0, + HANDOUT_EXCON = 1, + HANDOUT_WMS = 2, + HANDOUT_EXCON_OVERRULED_WMS = 3 + }; + static inline PlayerAssignState int2PlayerAssignState(int s) + { + switch (s) + { + case UNDEFINED: + case NOT_ASSIGNED: + case ASSIGNED: + case HANDOUT_EXCON: + case HANDOUT_WMS: + case HANDOUT_EXCON_OVERRULED_WMS: + return static_cast(s); + } + Q_ASSERT(false); + return UNDEFINED; + } + + struct PlayerInfo + { + PlayerState playerState = NOT_FOUND; + int playerId = -1; + int parentPlayerId = -1; + int equipNo = -1; + PlayerAssignState assignState = UNDEFINED; + int exerciseId = -1; + int forceId = -1; + int typeId = -1; + int equipTypeId = -1; + int typeClassId = -1; + int symbolColor = -1; + bool isDeleted = false; + QByteArray symbolPNG; + QString hierarchy; + QString designator; + QString tactIdent; + QString info; + QString alias; + QString forceName; + }; + + struct Exercise + { + int id = -1; + int actExercise = 0; + time_t start = 0; + time_t end = 0; + QString name; + QString stateAsString; + }; + using exerciseMap = QMap; + + struct EquipmentType + { + QString name; + int id = 0; + int specialType = 0; + int minEquipNo = 0; + int maxEquipNo = 0; + int taVulnerabilityModelId = 0; + int taPlayerTypeId = 0; + bool deletedInWMS = false; + }; + using equipTypeMap = QMap; + + + virtual RegisterReturnValue registerPlayer(int playerId, int equipNo, const PlayerAssignState &zuordnung, const QString &alias, + const QString &info, int exerciseId) = 0; + + virtual UnregisterReturnValue unregister(int equipNo, int exerciseId) = 0; + virtual PlayerInfo getPlayerInfo(int playerId, int exerciseId) = 0; + + virtual exerciseMap getExercises() const = 0; + virtual Exercise getActualExercise() const = 0; + + + virtual QMap getEquipRequirements(int exerciseId) const = 0; + + virtual QMap getAllPlayers(int exerciseId) const = 0; + virtual QMap getAllVehicles(int exerciseId) const = 0; + + virtual int getPlayerId(int equipNo, int exerciseId) const = 0; + virtual int getEquipNo(int playerId, int exerciseId) const = 0; + + virtual int getTypeClassId(int equipTypeId) const = 0; +}; + +Q_DECLARE_METATYPE(IWMS2ECC::Exercise) +Q_DECLARE_METATYPE(IWMS2ECC::EquipmentType) +Q_DECLARE_METATYPE(IWMS2ECC::RegisterReturnValue) diff --git a/Z/src/WMS_Interface/json_keys.h b/Z/src/WMS_Interface/json_keys.h new file mode 100755 index 000000000..90d147efb --- /dev/null +++ b/Z/src/WMS_Interface/json_keys.h @@ -0,0 +1,52 @@ + + +#pragma once + +#include + +namespace WebSocketInterface +{ + + +namespace JsonKeys +{ + +inline QString EXERCISE_ID() { return QStringLiteral("exerciseId"); } +inline QString DATA_MODIFICATION() { return QStringLiteral("dataModification"); } +inline QString PARTICIPANT_ID() { return QStringLiteral("participantId"); } +inline QString REGISTRATION_RETURN_VALUE() { return QStringLiteral("registrationReturnValue"); } + + +inline QString EQUIPMENT_TYPES_REQUEST() { return QStringLiteral("equipmentTypesRequest"); } + + +inline QString EQUIPMENT_TYPES_REPLY() { return QStringLiteral("equipmentTypesReply"); } + + +inline QString EXERCISES_REQUEST() { return QStringLiteral("exercisesRequest"); } + + +inline QString EXERCISES_REPLY() { return QStringLiteral("exercisesReply"); } + + +inline QString EXERCISE_UPDATE() { return QStringLiteral("exercisesUpdate"); } + + +inline QString PARTICIPANTS_REQUEST() { return QStringLiteral("participantsRequest"); } + + +inline QString PARTICIPANTS_REPLY() { return QStringLiteral("participantsReply"); } + + +inline QString PARTICIPANTS_UPDATE() { return QStringLiteral("participantsUpdate"); } + + +inline QString PARTICIPANT_REGISTER_IN_EXCON_REQUEST() { return QStringLiteral("participantRegisterInEXCONRequest");} + + +inline QString PARTICIPANT_REGISTER_IN_EXCON_REPLY() { return QStringLiteral("participantRegisterInEXCONReply");} + + + +} +} diff --git a/Z/src/WMS_Interface/wms_ecc_equipRequirements.cpp b/Z/src/WMS_Interface/wms_ecc_equipRequirements.cpp new file mode 100755 index 000000000..1eb29d300 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipRequirements.cpp @@ -0,0 +1,71 @@ + + + +#include "wms_ecc_equipRequirements.h" +#include +#include + +QJsonObject EquipRequirements::toJson() const +{ + QJsonArray arr; + for (QMap::ConstIterator it = m_equipRequire.begin(); it != m_equipRequire.end(); ++it) + { + QJsonObject obj; + obj[QLatin1String("key")] = it.key(); + obj[QLatin1String("value")] = it.value(); + arr.append(obj); + } + + QJsonObject retMap; + retMap[QLatin1String("equipMap")] = arr; + retMap[QLatin1String("ok")] = m_ok; + + return retMap; +} + +EquipRequirements EquipRequirements::fromJson(const QJsonObject &map) +{ + EquipRequirements eq; + + const QJsonArray arr = map[QLatin1String("equipMap")].toArray(); + for (const auto &ele : arr) + { + const QJsonObject obj = ele.toObject(); + int equipmentTypeId = obj[QLatin1String("key")].toInt(); + int amount = obj[QLatin1String("value")].toInt(); + eq.m_equipRequire.insert(equipmentTypeId, amount); + } + + eq.m_ok = map[QLatin1String("ok")].toBool(); + + return eq; +} + +QVariantMap EquipRequirements::toVariantMap() const +{ + QVariantMap viMap; + for (QMap::ConstIterator it = m_equipRequire.begin(); it != m_equipRequire.end(); ++it) + viMap.insert(QString::number(it.key()), QVariant(it.value())); + + QVariantMap retMap; + retMap[QLatin1String("equipMap")] = QVariant(viMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +EquipRequirements EquipRequirements::fromVariantMap(const QVariantMap &map) +{ + EquipRequirements eq; + + const QVariantMap viMap = map[QLatin1String("equipMap")].toMap(); + for (QVariantMap::ConstIterator it = viMap.begin(); it != viMap.end(); ++it) + { + const int key = it.key().toInt(); + eq.m_equipRequire.insert(key, it.value().toInt()); + } + + eq.m_ok = map[QLatin1String("ok")].toBool(); + + return eq; +} diff --git a/Z/src/WMS_Interface/wms_ecc_equipRequirements.h b/Z/src/WMS_Interface/wms_ecc_equipRequirements.h new file mode 100755 index 000000000..9a9f25e4f --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipRequirements.h @@ -0,0 +1,30 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include + +class WMS_JSON_DS_EXPORT EquipRequirements : public IBase +{ +public: + QJsonObject toJson() const; + static EquipRequirements fromJson(const QJsonObject &map); + + QVariantMap toVariantMap() const; + static EquipRequirements fromVariantMap(const QVariantMap &map); + + + QMap getEquipRequirements() const { return m_equipRequire; } + bool getOk() const { return m_ok; } + + void setEquipRequirements(const QMap &equip) { m_equipRequire = equip; } + void setOk(bool ok) { m_ok = ok; } + +private: + QMap m_equipRequire; + bool m_ok = false; +}; diff --git a/Z/src/WMS_Interface/wms_ecc_equipmenttypes.cpp b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.cpp new file mode 100755 index 000000000..f66025f9d --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.cpp @@ -0,0 +1,132 @@ + + + +#include "wms_ecc_equipmenttypes.h" +#include + +QJsonObject EquipmentTypes::toJson(const IWMS2ECC::EquipmentType &et) +{ + QJsonObject obj; + + obj[QLatin1String("id")] = et.id; + obj[QLatin1String("name")] = et.name; + obj[QLatin1String("minEquipNo")] = et.minEquipNo; + obj[QLatin1String("maxEquipNo")] = et.maxEquipNo; + obj[QLatin1String("specialType")] = et.specialType; + obj[QLatin1String("taVulnerabilityModelId")] = et.taVulnerabilityModelId; + obj[QLatin1String("taPlayerTypeId")] = et.taPlayerTypeId; + obj[QLatin1String("deletedInWMS")] = et.deletedInWMS; + + return obj; +} + +IWMS2ECC::EquipmentType EquipmentTypes::fromJson(const QJsonObject &obj) +{ + IWMS2ECC::EquipmentType et; + + et.id = obj[QLatin1String("id")].toInt(); + et.name = obj[QLatin1String("name")].toString(); + et.minEquipNo = obj[QLatin1String("minEquipNo")].toInt(); + et.maxEquipNo = obj[QLatin1String("maxEquipNo")].toInt(); + et.specialType = obj[QLatin1String("specialType")].toInt(); + et.taVulnerabilityModelId = obj[QLatin1String("taVulnerabilityModelId")].toInt(); + et.taPlayerTypeId = obj[QLatin1String("taPlayerTypeId")].toInt(); + et.deletedInWMS = obj[QLatin1String("deletedInWMS")].toBool(); + + return et; +} + +QJsonObject EquipmentTypes::toJsonAll() const +{ + QJsonArray arr; + for (const IWMS2ECC::EquipmentType &et : m_equipmentTypes) + arr.append(toJson(et)); + + QJsonObject retMap; + retMap[QLatin1String("etMap")] = arr; + retMap[QLatin1String("ok")] = m_ok; + + return retMap; +} + +EquipmentTypes EquipmentTypes::fromJsonAll(const QJsonObject &map) +{ + EquipmentTypes ets; + + const QJsonArray arr = map[QLatin1String("etMap")].toArray(); + for (const auto &ele : arr) + { + const IWMS2ECC::EquipmentType val = fromJson(ele.toObject()); + ets.m_equipmentTypes.insert(val.id, val); + } + + ets.m_ok = map[QLatin1String("ok")].toBool(); + + return ets; +} + + +QVariantMap EquipmentTypes::toVariantMap() const +{ + QVariantMap vMap; + + vMap[QLatin1String("id")] = QVariant(m_equipmentType.id); + vMap[QLatin1String("name")] = m_equipmentType.name; + vMap[QLatin1String("minEquipNo")] = QVariant((int)m_equipmentType.minEquipNo); + vMap[QLatin1String("maxEquipNo")] = QVariant((int)m_equipmentType.maxEquipNo); + vMap[QLatin1String("specialType")] = QVariant(m_equipmentType.specialType); + vMap[QLatin1String("deletedInWMS")] = QVariant(m_equipmentType.deletedInWMS); + + vMap[QLatin1String("ok")] = QVariant(m_ok); + + return vMap; +} + +EquipmentTypes EquipmentTypes::fromVariantMap(const QVariantMap &map) +{ + EquipmentTypes ets; + + ets.m_equipmentType.id = map[QLatin1String("id")].toInt(); + ets.m_equipmentType.name = map[QLatin1String("name")].toString(); + ets.m_equipmentType.minEquipNo = map[QLatin1String("minEquipNo")].toInt(); + ets.m_equipmentType.maxEquipNo = map[QLatin1String("maxEquipNo")].toInt(); + ets.m_equipmentType.specialType = map[QLatin1String("specialType")].toInt(); + ets.m_equipmentType.deletedInWMS = map[QLatin1String("deletedInWMS")].toBool(); + + ets.m_ok = map[QLatin1String("ok")].toBool(); + + return ets; +} + +QVariantMap EquipmentTypes::toVariantMapAll() const +{ + QVariantMap vMap; + for (IWMS2ECC::equipTypeMap::ConstIterator it = m_equipmentTypes.begin(); it != m_equipmentTypes.end(); ++it) + { + m_equipmentType = it.value(); + vMap.insert(QString::number(it.key()), QVariant(toVariantMap())); + } + + QVariantMap retMap; + retMap[QLatin1String("etMap")] = QVariant(vMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +EquipmentTypes EquipmentTypes::fromVariantMapAll(const QVariantMap &map) +{ + EquipmentTypes ets; + + const QVariantMap vMap = map[QLatin1String("etMap")].toMap(); + for (QVariantMap::ConstIterator it = vMap.begin(); it != vMap.end(); ++it) + { + int key = it.key().toInt(); + IWMS2ECC::EquipmentType et = EquipmentTypes::fromVariantMap(it.value().toMap()).m_equipmentType; + ets.m_equipmentTypes.insert(key, et); + } + + ets.m_ok = map[QLatin1String("ok")].toBool(); + + return ets; +} diff --git a/Z/src/WMS_Interface/wms_ecc_equipmenttypes.h b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.h new file mode 100755 index 000000000..67cde3778 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.h @@ -0,0 +1,37 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include +#include + +class WMS_JSON_DS_EXPORT EquipmentTypes : public IBase +{ +public: + QJsonObject toJsonAll() const; + static EquipmentTypes fromJsonAll(const QJsonObject &map); + static QJsonObject toJson(const IWMS2ECC::EquipmentType &et); + static IWMS2ECC::EquipmentType fromJson(const QJsonObject &obj); + + QVariantMap toVariantMapAll() const; + static EquipmentTypes fromVariantMapAll(const QVariantMap &map); + QVariantMap toVariantMap() const; + static EquipmentTypes fromVariantMap(const QVariantMap &map); + + IWMS2ECC::EquipmentType getEquipmentType() const { return m_equipmentType; } + IWMS2ECC::equipTypeMap getEquipmentTypes() const { return m_equipmentTypes; } + bool getOk() const { return m_ok; } + + void setEquipmentType(const IWMS2ECC::EquipmentType &et) { m_equipmentType = et; } + void setEquipmentTypes(const IWMS2ECC::equipTypeMap &map) { m_equipmentTypes = map; } + void setOk(bool ok) { m_ok = ok; } + +private: + IWMS2ECC::equipTypeMap m_equipmentTypes; + mutable IWMS2ECC::EquipmentType m_equipmentType; + bool m_ok = false; +}; diff --git a/Z/src/WMS_Interface/wms_ecc_exercises.cpp b/Z/src/WMS_Interface/wms_ecc_exercises.cpp new file mode 100755 index 000000000..31c89d9c8 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_exercises.cpp @@ -0,0 +1,135 @@ + + + +#include "wms_ecc_exercises.h" +#include +#include + +namespace EXCON +{ + +QJsonObject Exercises::toJson(const IWMS2ECC::Exercise &ex) const +{ + QJsonObject obj; + + obj[QLatin1String("id")] = ex.id; + obj[QLatin1String("actExercise")] = ex.actExercise; + obj[QLatin1String("start")] = static_cast(ex.start); + obj[QLatin1String("end")] = static_cast(ex.end); + obj[QLatin1String("name")] = ex.name; + obj[QLatin1String("state")] = ex.stateAsString; + + obj[QLatin1String("ok")] = m_ok; + + return obj; +} + +IWMS2ECC::Exercise Exercises::fromJson(const QJsonObject &obj) +{ + IWMS2ECC::Exercise ex; + + ex.id = obj[QLatin1String("id")].toInt(); + ex.actExercise = obj[QLatin1String("actExercise")].toInt(); + ex.start = static_cast(obj[QLatin1String("start")].toInt()); + ex.end = static_cast(obj[QLatin1String("end")].toInt()); + ex.name = obj[QLatin1String("name")].toString(); + ex.stateAsString = obj[QLatin1String("state")].toString(); + + return ex; +} + +QJsonObject Exercises::toJsonAll() const +{ + QJsonArray arr; + for (const IWMS2ECC::Exercise &ex : m_exercises) + arr.append(toJson(ex)); + + QJsonObject obj; + obj[QLatin1String("exMap")] = arr; + obj[QLatin1String("ok")] = m_ok; + + return obj; +} + +Exercises Exercises::fromJsonAll(const QJsonObject &map) +{ + Exercises ex; + + const QJsonArray arr = map[QLatin1String("exMap")].toArray(); + for (const QJsonValue &val : arr) + { + const IWMS2ECC::Exercise exinfo = fromJson(val.toObject()); + ex.m_exercises.insert(exinfo.id, exinfo); + } + + ex.m_ok = map[QLatin1String("ok")].toBool(); + + return ex; +} + + +QVariantMap Exercises::toVariantMap() const +{ + QVariantMap vMap; + + vMap[QLatin1String("id")] = QVariant(m_exercise.id); + vMap[QLatin1String("name")] = m_exercise.name; + vMap[QLatin1String("start")] = QVariant(static_cast(m_exercise.start)); + vMap[QLatin1String("end")] = QVariant(static_cast(m_exercise.end)); + vMap[QLatin1String("state")] = m_exercise.stateAsString; + + vMap[QLatin1String("ok")] = QVariant(m_ok); + + return vMap; +} + +Exercises Exercises::fromVariantMap(const QVariantMap &map) +{ + Exercises ex; + + ex.m_exercise.id = map[QLatin1String("id")].toInt(); + ex.m_exercise.name = map[QLatin1String("name")].toString(); + ex.m_exercise.start = map[QLatin1String("start")].toLongLong(); + ex.m_exercise.end = map[QLatin1String("end")].toLongLong(); + ex.m_exercise.stateAsString = map[QLatin1String("state")].toString(); + + ex.m_ok = map[QLatin1String("ok")].toBool(); + + return ex; +} + +QVariantMap Exercises::toVariantMapAll() const +{ + QVariantMap vMap; + for (IWMS2ECC::exerciseMap::ConstIterator it = m_exercises.begin(); it != m_exercises.end(); ++it) + { + m_exercise = it.value(); + vMap.insert(QString::number(it.key()), QVariant(toVariantMap())); + } + + QVariantMap retMap; + retMap[QLatin1String("exeMap")] = QVariant(vMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +Exercises Exercises::fromVariantMapAll(const QVariantMap &map) +{ + Exercises ex; + + const QVariantMap vMap = map[QLatin1String("exeMap")].toMap(); + for (QVariantMap::ConstIterator it = vMap.begin(); it != vMap.end(); ++it) + { + + int key = it.key().toInt(); + IWMS2ECC::Exercise e = Exercises::fromVariantMap(it.value().toMap()).m_exercise; + ex.m_exercises.insert(key, e); + } + + ex.m_ok = map[QLatin1String("ok")].toBool(); + + return ex; +} + +} diff --git a/Z/src/WMS_Interface/wms_ecc_exercises.h b/Z/src/WMS_Interface/wms_ecc_exercises.h new file mode 100755 index 000000000..ce982a868 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_exercises.h @@ -0,0 +1,41 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include + +namespace EXCON +{ + +class WMS_JSON_DS_EXPORT Exercises : public IBase +{ +public: + QJsonObject toJsonAll() const; + static Exercises fromJsonAll(const QJsonObject &map); + QJsonObject toJson(const IWMS2ECC::Exercise &ex) const; + static IWMS2ECC::Exercise fromJson(const QJsonObject &obj); + + QVariantMap toVariantMapAll() const; + static Exercises fromVariantMapAll(const QVariantMap &map); + QVariantMap toVariantMap() const; + static Exercises fromVariantMap(const QVariantMap &map); + + IWMS2ECC::Exercise getExercise() const { return m_exercise; } + IWMS2ECC::exerciseMap getExercises() const { return m_exercises; } + bool getOk() const { return m_ok; } + + void setExercise(const IWMS2ECC::Exercise &exe) { m_exercise = exe; } + void setExercises(const IWMS2ECC::exerciseMap &exe) { m_exercises = exe; } + void setOk(bool ok) { m_ok = ok; } + +private: + IWMS2ECC::exerciseMap m_exercises; + mutable IWMS2ECC::Exercise m_exercise; + bool m_ok = false; +}; + +} diff --git a/Z/src/WMS_Interface/wms_ecc_ibase.h b/Z/src/WMS_Interface/wms_ecc_ibase.h new file mode 100755 index 000000000..e6d44597a --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_ibase.h @@ -0,0 +1,15 @@ + + + +#pragma once + +#include + +class WMS_JSON_DS_EXPORT IBase +{ +public: + IBase() = default; + virtual ~IBase() = default; + +}; + diff --git a/Z/src/WMS_Interface/wms_ecc_playerInfo.cpp b/Z/src/WMS_Interface/wms_ecc_playerInfo.cpp new file mode 100755 index 000000000..545cbf422 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_playerInfo.cpp @@ -0,0 +1,176 @@ + + + +#include "wms_ecc_playerInfo.h" +#include +#include +#include + +QJsonObject PlayerInfo::toJson(const IWMS2ECC::PlayerInfo &pi) +{ + QJsonObject obj; + obj[QLatin1String("playerState")] = pi.playerState; + obj[QLatin1String("playerId")] = pi.playerId; + obj[QLatin1String("parentPlayerId")] = pi.parentPlayerId; + obj[QLatin1String("equipNo")] = pi.equipNo; + obj[QLatin1String("assignState")] = pi.assignState; + obj[QLatin1String("exerciseId")] = pi.exerciseId; + obj[QLatin1String("forceId")] = pi.forceId; + obj[QLatin1String("typeId")] = pi.typeId; + obj[QLatin1String("isDeleted")] = pi.isDeleted; + obj[QLatin1String("equipTypeId")] = pi.equipTypeId; + obj[QLatin1String("typeClassId")] = pi.typeClassId; + obj[QLatin1String("symbolColor")] = pi.symbolColor; + obj[QLatin1String("symbolPNG")] = QString::fromLatin1(pi.symbolPNG.toBase64()); + obj[QLatin1String("hierarchy")] = pi.hierarchy; + obj[QLatin1String("designator")] = pi.designator; + obj[QLatin1String("tactIdent")] = pi.tactIdent; + obj[QLatin1String("info")] = pi.info; + obj[QLatin1String("alias")] = pi.alias; + obj[QLatin1String("forceName")] = pi.forceName; + + return obj; +} + +IWMS2ECC::PlayerInfo PlayerInfo::fromJson(const QJsonObject &obj) +{ + IWMS2ECC::PlayerInfo pi; + + pi.playerState = static_cast(obj[QLatin1String("playerState")].toInt()); + pi.playerId = obj[QLatin1String("playerId")].toInt(); + pi.parentPlayerId = obj[QLatin1String("parentPlayerId")].toInt(); + pi.equipNo = obj[QLatin1String("equipNo")].toInt(); + pi.assignState = static_cast(obj[QLatin1String("assignState")].toInt()); + pi.exerciseId = obj[QLatin1String("exerciseId")].toInt(); + pi.forceId = obj[QLatin1String("forceId")].toInt(); + pi.typeId = obj[QLatin1String("typeId")].toInt(); + pi.isDeleted = obj[QLatin1String("isDeleted")].toBool(); + pi.equipTypeId = obj[QLatin1String("equipTypeId")].toInt(); + pi.typeClassId = obj[QLatin1String("typeClassId")].toInt(); + pi.symbolColor = obj[QLatin1String("symbolColor")].toInt(); + pi.symbolPNG = QByteArray::fromBase64(obj[QLatin1String("symbolPNG")].toString().toLatin1()); + pi.hierarchy = obj[QLatin1String("hierarchy")].toString(); + pi.designator = obj[QLatin1String("designator")].toString(); + pi.tactIdent = obj[QLatin1String("tactIdent")].toString(); + pi.info = obj[QLatin1String("info")].toString(); + pi.alias = obj[QLatin1String("alias")].toString(); + pi.forceName = obj[QLatin1String("forceName")].toString(); + + return pi; +} + +QJsonObject PlayerInfo::toJsonAll() const +{ + QJsonArray arr; + for (const IWMS2ECC::PlayerInfo &pi : m_allPlayerInfo) + arr.append(toJson(pi)); + + QJsonObject retMap; + retMap[QLatin1String("piMap")] = arr; + retMap[QLatin1String("ok")] = m_ok; + + return retMap; +} + +PlayerInfo PlayerInfo::fromJsonAll(const QJsonObject &map) +{ + PlayerInfo pi; + + const QJsonArray arr = map[QLatin1String("piMap")].toArray(); + for (const QJsonValue &val : arr) + { + const IWMS2ECC::PlayerInfo player = fromJson(val.toObject()); + + pi.m_allPlayerInfo.insert(player.playerId, player); + } + + pi.m_ok = map[QLatin1String("ok")].toBool(); + + return pi; +} + +QVariantMap PlayerInfo::toVariantMap() const +{ + QVariantMap retMap; + retMap[QLatin1String("playerId")] = QVariant(m_playerInfo.playerId); + retMap[QLatin1String("parentPlayerId")] = QVariant(m_playerInfo.parentPlayerId); + retMap[QLatin1String("equipNo")] = QVariant(m_playerInfo.equipNo); + retMap[QLatin1String("equipTypeId")] = QVariant(m_playerInfo.equipTypeId); + retMap[QLatin1String("typeClassId")] = QVariant(m_playerInfo.typeClassId); + retMap[QLatin1String("forceId")] = QVariant(m_playerInfo.forceId); + retMap[QLatin1String("designator")] = m_playerInfo.designator; + retMap[QLatin1String("tactIdent")] = m_playerInfo.tactIdent; + retMap[QLatin1String("hierarchy")] = m_playerInfo.hierarchy; + retMap[QLatin1String("forceName")] = m_playerInfo.forceName; + retMap[QLatin1String("info")] = m_playerInfo.info; + retMap[QLatin1String("alias")] = m_playerInfo.alias; + retMap[QLatin1String("symbolPNG")] = QVariant(m_playerInfo.symbolPNG); + retMap[QLatin1String("symbolColor")] = QVariant(m_playerInfo.symbolColor); + + retMap[QLatin1String("assignState")] = QVariant(m_playerInfo.assignState); + retMap[QLatin1String("playerState")] = QVariant(m_playerInfo.playerState); + + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +PlayerInfo PlayerInfo::fromVariantMap(const QVariantMap &map) +{ + PlayerInfo pi; + + pi.m_playerInfo.playerId = map[QLatin1String("playerId")].toInt(); + pi.m_playerInfo.parentPlayerId = map[QLatin1String("parentPlayerId")].toInt(); + pi.m_playerInfo.equipNo = map[QLatin1String("equipNo")].toInt(); + pi.m_playerInfo.forceId = map[QLatin1String("forceId")].toInt(); + pi.m_playerInfo.equipTypeId = map[QLatin1String("equipTypeId")].toInt(); + pi.m_playerInfo.typeClassId = map[QLatin1String("typeClassId")].toInt(); + pi.m_playerInfo.designator = map[QLatin1String("designator")].toString(); + pi.m_playerInfo.tactIdent = map[QLatin1String("tactIdent")].toString(); + pi.m_playerInfo.hierarchy = map[QLatin1String("hierarchy")].toString(); + pi.m_playerInfo.forceName = map[QLatin1String("forceName")].toString(); + pi.m_playerInfo.info = map[QLatin1String("info")].toString(); + pi.m_playerInfo.alias = map[QLatin1String("alias")].toString(); + pi.m_playerInfo.symbolPNG = map[QLatin1String("symbolPNG")].toByteArray(); + pi.m_playerInfo.symbolColor = map[QLatin1String("symbolColor")].toInt(); + pi.m_playerInfo.assignState = (IWMS2ECC::PlayerAssignState) map[QLatin1String("assignState")].toInt(); + pi.m_playerInfo.playerState = (IWMS2ECC::PlayerState) map[QLatin1String("playerState")].toInt(); + + pi.m_ok = map[QLatin1String("ok")].toBool(); + + return pi; +} + +QVariantMap PlayerInfo::toVariantMapAll() const +{ + QVariantMap vMap; + for (const IWMS2ECC::PlayerInfo &pi : m_allPlayerInfo) + { + m_playerInfo = pi; + vMap.insert(QString::number(pi.playerId), QVariant(toVariantMap())); + } + + QVariantMap retMap; + retMap[QLatin1String("plMap")] = QVariant(vMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +PlayerInfo PlayerInfo::fromVariantMapAll(const QVariantMap &map) +{ + PlayerInfo players; + + const QVariantMap vMap = map[QLatin1String("plMap")].toMap(); + for (const QVariant &data : vMap) + { + PlayerInfo player = PlayerInfo::fromVariantMap(data.toMap()); + IWMS2ECC::PlayerInfo pi = player.getPlayerInfo(); + players.m_allPlayerInfo.insert(pi.playerId, pi); + } + + players.m_ok = vMap[QLatin1String("ok")].toBool(); + return players; +} + + diff --git a/Z/src/WMS_Interface/wms_ecc_playerInfo.h b/Z/src/WMS_Interface/wms_ecc_playerInfo.h new file mode 100755 index 000000000..898a96cb7 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_playerInfo.h @@ -0,0 +1,40 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include + + +class WMS_JSON_DS_EXPORT PlayerInfo : public IBase +{ +public: + static QJsonObject toJson(const IWMS2ECC::PlayerInfo &pi); + static IWMS2ECC::PlayerInfo fromJson(const QJsonObject &obj); + + QJsonObject toJsonAll() const; + static PlayerInfo fromJsonAll(const QJsonObject &map); + + QVariantMap toVariantMap() const; + static PlayerInfo fromVariantMap(const QVariantMap &map); + + QVariantMap toVariantMapAll() const; + static PlayerInfo fromVariantMapAll(const QVariantMap &map); + + IWMS2ECC::PlayerInfo getPlayerInfo() const { return m_playerInfo; } + QMap getAllPlayerInfo() const { return m_allPlayerInfo; } + bool getOk() const { return m_ok; } + + void setPlayerInfo(const IWMS2ECC::PlayerInfo &info) { m_playerInfo = info; } + void setAllPlayerInfo(const QMap &pi) { m_allPlayerInfo = pi; } + void setOk(bool ok) { m_ok = ok; } + +private: + QMap m_allPlayerInfo; + mutable IWMS2ECC::PlayerInfo m_playerInfo; + bool m_ok = false; +}; + diff --git a/Z/src/WMS_Interface/wms_ecc_registration.cpp b/Z/src/WMS_Interface/wms_ecc_registration.cpp new file mode 100755 index 000000000..3aee57a61 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_registration.cpp @@ -0,0 +1,89 @@ + + + +#include "wms_ecc_registration.h" +#include + +QJsonObject Registration::toJson() const +{ + QJsonObject obj; + + obj[QLatin1String("playerId")] = m_playerId; + obj[QLatin1String("assignment")] = m_assignment; + obj[QLatin1String("exerciseId")] = m_exerciseId; + obj[QLatin1String("ok")] = m_ok; + + if (m_bEquipNoIsSet) + obj[QLatin1String("equipNo")] = m_equipNo; + if (m_bAliasIsSet) + obj[QLatin1String("alias")] = m_alias; + if (m_bInfoIsSet) + obj[QLatin1String("info")] = m_info; + + return obj; +} + +Registration Registration::fromJson(const QJsonObject &obj) +{ + Registration rg; + + rg.m_playerId = obj[QLatin1String("playerId")].toInt(); + rg.m_assignment = IWMS2ECC::int2PlayerAssignState(obj[QLatin1String("assignment")].toInt()); + rg.m_exerciseId = obj[QLatin1String("exerciseId")].toInt(); + + rg.m_bEquipNoIsSet = obj.contains(QLatin1String("equipNo")); + if (rg.m_bEquipNoIsSet) + rg.m_equipNo = obj[QLatin1String("equipNo")].toInt(); + rg.m_bAliasIsSet = obj.contains(QLatin1String("alias")); + if (rg.m_bAliasIsSet) + rg.m_alias = obj[QLatin1String("alias")].toString(); + rg.m_bInfoIsSet = obj.contains(QLatin1String("info")); + if (rg.m_bInfoIsSet) + rg.m_info = obj[QLatin1String("info")].toString(); + rg.m_ok = obj[QLatin1String("ok")].toBool(); + + return rg; +} + + +QVariantMap Registration::toVariantMap() const +{ + QVariantMap retMap; + + retMap[QLatin1String("playerId")] = QVariant(m_playerId); + retMap[QLatin1String("assignment")] = QVariant(m_assignment); + retMap[QLatin1String("exerciseId")] = QVariant(m_exerciseId); + + if (m_bEquipNoIsSet) + retMap[QLatin1String("equipNo")] = QVariant(m_equipNo); + if (m_bAliasIsSet) + retMap[QLatin1String("alias")] = m_alias; + if (m_bInfoIsSet) + retMap[QLatin1String("info")] = m_info; + + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +Registration Registration::fromVariantMap(const QVariantMap &map) +{ + Registration rg; + + rg.m_playerId = map[QLatin1String("playerId")].toInt(); + rg.m_assignment = IWMS2ECC::int2PlayerAssignState(map[QLatin1String("assignment")].toInt()); + rg.m_exerciseId = map[QLatin1String("exerciseId")].toInt(); + rg.m_ok = map[QLatin1String("ok")].toBool(); + + rg.m_bEquipNoIsSet = map.contains(QLatin1String("equipNo")); + if (rg.m_bEquipNoIsSet) + rg.m_equipNo = map[QLatin1String("equipNo")].toInt(); + rg.m_bAliasIsSet = map.contains(QLatin1String("alias")); + if (rg.m_bAliasIsSet) + rg.m_alias = map[QLatin1String("alias")].toString(); + rg.m_bInfoIsSet = map.contains(QLatin1String("info")); + if (rg.m_bInfoIsSet) + rg.m_info = map[QLatin1String("info")].toString(); + + return rg; +} diff --git a/Z/src/WMS_Interface/wms_ecc_registration.h b/Z/src/WMS_Interface/wms_ecc_registration.h new file mode 100755 index 000000000..8c0fc6348 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_registration.h @@ -0,0 +1,55 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include +#include + + +class WMS_JSON_DS_EXPORT Registration : public IBase +{ +public: + QJsonObject toJson() const; + static Registration fromJson(const QJsonObject &obj); + + QVariantMap toVariantMap() const; + static Registration fromVariantMap(const QVariantMap &map); + + int getPlayerId() const { return m_playerId; } + int getEquipNo() const { return m_equipNo; } + int getExerciseId() const { return m_exerciseId; } + QString getAlias() const { return m_alias; } + QString getInfo() const { return m_info; } + bool isEquipNoSet() const { return m_bEquipNoIsSet; } + bool isAliasSet() const { return m_bAliasIsSet; } + bool isInfoSet() const { return m_bInfoIsSet; } + + IWMS2ECC::PlayerAssignState getAssignment() const { return m_assignment; } + + bool getOk() const { return m_ok; } + + void setPlayerId(int playerId) { m_playerId = playerId; } + void setEquipNo(int equipNo) { m_equipNo = equipNo; m_bEquipNoIsSet = true; } + void setAssignment(IWMS2ECC::PlayerAssignState assignment) { m_assignment = assignment; } + void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; } + void setAlias(const QString &alias) { m_alias = alias; m_bAliasIsSet = true; } + void setInfo(const QString &info) { m_info = info; m_bInfoIsSet = true; } + void setOk(bool ok) { m_ok = ok; } + +private: + QString m_alias; + QString m_info; + IWMS2ECC::PlayerAssignState m_assignment = IWMS2ECC::UNDEFINED; + int m_playerId = 0; + int m_equipNo = 0; + int m_exerciseId = -1; + bool m_bEquipNoIsSet = false; + bool m_bAliasIsSet = false; + bool m_bInfoIsSet = false; + bool m_ok = false; +}; + diff --git a/Z/src/WMS_Interface/wms_ecc_unregister.cpp b/Z/src/WMS_Interface/wms_ecc_unregister.cpp new file mode 100755 index 000000000..5f1974f24 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_unregister.cpp @@ -0,0 +1,50 @@ + + + +#include "wms_ecc_unregister.h" +#include + +QJsonObject Unregister::toJson() const +{ + QJsonObject obj; + + obj[QLatin1String("equipNo")] = m_equipNo; + obj[QLatin1String("exerciseId")] = m_exerciseId; + obj[QLatin1String("ok")] = m_ok; + + return obj; +} + +Unregister Unregister::fromJson(const QJsonObject &obj) +{ + Unregister ur; + + ur.m_equipNo = obj[QLatin1String("equipNo")].toInt(); + ur.m_exerciseId = obj[QLatin1String("exerciseId")].toInt(); + ur.m_ok = obj[QLatin1String("ok")].toBool(); + + return ur; +} + +QVariantMap Unregister::toVariantMap() const +{ + QVariantMap retMap; + + retMap[QLatin1String("equipNo")] = QVariant(m_equipNo); + retMap[QLatin1String("exerciseId")] = QVariant(m_exerciseId); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +Unregister Unregister::fromVariantMap(const QVariantMap &map) +{ + Unregister ur; + + ur.m_equipNo = map[QLatin1String("equipNo")].toInt(); + ur.m_exerciseId = map[QLatin1String("exerciseId")].toInt(); + ur.m_ok = map[QLatin1String("ok")].toBool(); + + return ur; +} + diff --git a/Z/src/WMS_Interface/wms_ecc_unregister.h b/Z/src/WMS_Interface/wms_ecc_unregister.h new file mode 100755 index 000000000..d3731020c --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_unregister.h @@ -0,0 +1,32 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" + +#include +#include + +class WMS_JSON_DS_EXPORT Unregister : public IBase +{ +public: + QJsonObject toJson() const; + static Unregister fromJson(const QJsonObject &obj); + + QVariantMap toVariantMap() const; + static Unregister fromVariantMap(const QVariantMap &map); + + int getEquipNo() const { return m_equipNo; } + int getExerciseId() const { return m_exerciseId; } + bool getOk() const { return m_ok; } + + void setEquipNo(int equipNo) { m_equipNo = equipNo; } + void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; } + void setOk(bool ok) { m_ok = ok; } + +private: + int m_equipNo = 0; + int m_exerciseId = -1; + bool m_ok = false; +}; diff --git a/Z/src/nglapplication/CMakeLists.txt b/Z/src/nglapplication/CMakeLists.txt new file mode 100755 index 000000000..05e5541b2 --- /dev/null +++ b/Z/src/nglapplication/CMakeLists.txt @@ -0,0 +1,134 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +# +# nglapplication +# +SET(nglapplication_SRCS + nglapplication.cpp + nglapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) +NGL_ADD_LIBRARY(WS AAR SV HLA nglapplication SHARED ${nglapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + Qt5::Core + Qt5::Widgets +) +NGL_INSTALL_TARGET(nglapplication) + +# +# nglsingleapplication +# +SET(nglsingleapplication_SRCS + nglsingleapplication.cpp + nglsingleapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) +NGL_ADD_LIBRARY(WS nglsingleapplication SHARED ${nglsingleapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglsingleapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglsingleapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + qtsingleapplication +) +NGL_INSTALL_TARGET(nglsingleapplication) + +# +# nglcoreapplication +# +SET(nglcoreapplication_SRCS + nglcoreapplication.cpp + nglcoreapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) + +NGL_ADD_LIBRARY(ALL nglcoreapplication SHARED ${nglcoreapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglcoreapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglcoreapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + Qt5::Core +) +NGL_INSTALL_TARGET(nglcoreapplication) + +# +# nglsinglecoreapplication +# +SET(nglsinglecoreapplication_SRCS + nglsinglecoreapplication.cpp + nglsinglecoreapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) + +NGL_ADD_LIBRARY(AAR SV nglsinglecoreapplication SHARED ${nglsinglecoreapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglsinglecoreapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglsinglecoreapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + qtsinglecoreapplication +) +NGL_INSTALL_TARGET(nglsinglecoreapplication) + +# +# nglguiapplication +# +SET(nglguiapplication_SRCS + nglguiapplication.cpp + nglguiapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) + +NGL_ADD_LIBRARY(ALL nglguiapplication SHARED ${nglguiapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglguiapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglguiapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + Qt5::Gui +) +NGL_INSTALL_TARGET(nglguiapplication) diff --git a/Z/src/nglapplication/ngl_qt_msg_handler.inc b/Z/src/nglapplication/ngl_qt_msg_handler.inc new file mode 100755 index 000000000..c9da57f53 --- /dev/null +++ b/Z/src/nglapplication/ngl_qt_msg_handler.inc @@ -0,0 +1,64 @@ +/** + * @RDE_HEADER@ + * callback to catch qt log messages + * $Id$ + * $HeadURL$ + * $Author$ + */ + +#include +#include + +static void qtMsgHandler(QtMsgType type, const QMessageLogContext &, const QString &msg) +{ + // pulse audio connect errors are important but can be very annoying - so only print it ONE time only and also as an error + static bool pulseAudioMessageSent = false; + static QString pulseAudioMessage = QStringLiteral("PulseAudioService: pa_context_connect() failed"); + if (msg.startsWith(pulseAudioMessage)) + { + if (pulseAudioMessageSent) + { + return; + } + + type = QtCriticalMsg; + pulseAudioMessageSent = true; + } + + + try + { + NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger( "NGL.Qt" ); + switch (type) { + case QtDebugMsg: + DEBUG_LOG(l) << msg ; + break; + case QtInfoMsg: + INFO_LOG(l) << msg ; + break; + case QtWarningMsg: + WARNING_LOG(l) << msg ; + break; + case QtCriticalMsg: + ERROR_LOG(l) << msg ; + break; + case QtFatalMsg: + FATAL_LOG(l) << msg ; + break; + } + } catch (...) { + switch (type) + { + case QtDebugMsg: + case QtInfoMsg: + fputs(qPrintable(msg), stdout); + break; + case QtWarningMsg: + case QtCriticalMsg: + case QtFatalMsg: + fputs(qPrintable(msg), stderr); + break; + } + } +} + diff --git a/Z/src/nglapplication/ngl_signal_handler.inc b/Z/src/nglapplication/ngl_signal_handler.inc new file mode 100755 index 000000000..cf1d5f976 --- /dev/null +++ b/Z/src/nglapplication/ngl_signal_handler.inc @@ -0,0 +1,41 @@ +/** + * @RDE_HEADER@ + * small stub to catch SIGTERM for proper shutdown + * $Id$ + * $HeadURL$ + * $Author$ + */ + +#include +#include + +#ifdef Q_OS_WIN +#include +#include + + +class MyEventFilter final : public QAbstractNativeEventFilter +{ + public: + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override + { + Q_UNUSED(eventType); + Q_UNUSED(result); + const MSG *msg = reinterpret_cast(message); + if (msg->message == WM_CLOSE && msg->hwnd == nullptr) + QCoreApplication::quit(); + return false; + } +}; +#endif + +#ifndef SIGTERM +# define SIGTERM 15 +#endif +static void signalHandler(int signal_number) +{ + if(signal_number != SIGTERM) + return; + QCoreApplication::quit(); +} + diff --git a/Z/src/nglapplication/nglapplication.cpp b/Z/src/nglapplication/nglapplication.cpp new file mode 100755 index 000000000..ff96bd7c2 --- /dev/null +++ b/Z/src/nglapplication/nglapplication.cpp @@ -0,0 +1,31 @@ + + + +#include "nglapplication.h" +#include "ngl_signal_handler.inc" + + +NGLApplication::NGLApplication(int &argc, char **argv) + : QApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} + + +bool NGLApplication::notify(QObject *o, QEvent *e) +{ + bool bRet = false; + try + { + bRet = QApplication::notify(o, e); + } + catch (const std::exception &e) + { + fprintf(stderr, "exception %s\n", e.what()); + } + return bRet; +} diff --git a/Z/src/nglapplication/nglapplication.h b/Z/src/nglapplication/nglapplication.h new file mode 100755 index 000000000..a1fe052f6 --- /dev/null +++ b/Z/src/nglapplication/nglapplication.h @@ -0,0 +1,36 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLAPPLICATION_LIB +# define NGLAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLAPPLICATION_EXPORT NGLApplication : public QApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLApplication(int &argc, char **argv); + +protected: + bool notify(QObject *o, QEvent *e) override; +}; + +#define nglApp static_cast(NGLApplication::instance()) diff --git a/Z/src/nglapplication/nglcoreapplication.cpp b/Z/src/nglapplication/nglcoreapplication.cpp new file mode 100755 index 000000000..40f536612 --- /dev/null +++ b/Z/src/nglapplication/nglcoreapplication.cpp @@ -0,0 +1,17 @@ + + + +#include "nglcoreapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLCoreApplication::NGLCoreApplication(int &argc, char **argv) + : QCoreApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} diff --git a/Z/src/nglapplication/nglcoreapplication.h b/Z/src/nglapplication/nglcoreapplication.h new file mode 100755 index 000000000..ab6eebe95 --- /dev/null +++ b/Z/src/nglapplication/nglcoreapplication.h @@ -0,0 +1,31 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLCOREAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLCOREAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLCOREAPPLICATION_LIB +# define NGLCOREAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLCOREAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLCOREAPPLICATION_EXPORT NGLCoreApplication : public QCoreApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLCoreApplication(int &argc, char **argv); +}; diff --git a/Z/src/nglapplication/nglguiapplication.cpp b/Z/src/nglapplication/nglguiapplication.cpp new file mode 100755 index 000000000..a4f066ffe --- /dev/null +++ b/Z/src/nglapplication/nglguiapplication.cpp @@ -0,0 +1,17 @@ + + + +#include "nglguiapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLGuiApplication::NGLGuiApplication(int &argc, char **argv) + : QGuiApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} diff --git a/Z/src/nglapplication/nglguiapplication.h b/Z/src/nglapplication/nglguiapplication.h new file mode 100755 index 000000000..9f9eaaaf0 --- /dev/null +++ b/Z/src/nglapplication/nglguiapplication.h @@ -0,0 +1,33 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLGUIAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLGUIAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLGUIAPPLICATION_LIB +# define NGLGUIAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLGUIAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLGUIAPPLICATION_EXPORT NGLGuiApplication : public QGuiApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLGuiApplication(int &argc, char **argv); +}; + +#define nglGuiApp static_cast(NGLGuiApplication::instance()) diff --git a/Z/src/nglapplication/nglloggerhandler.cpp b/Z/src/nglapplication/nglloggerhandler.cpp new file mode 100755 index 000000000..6c3e9e7d1 --- /dev/null +++ b/Z/src/nglapplication/nglloggerhandler.cpp @@ -0,0 +1,91 @@ + + + +#include "nglloggerhandler.h" +#include "ngl_qt_msg_handler.inc" + +#include +#include +#include + +namespace NGL +{ + +static QByteArray username() +{ +#ifdef Q_OS_WIN + return qgetenv("USERNAME"); +#else + return qgetenv("USER"); +#endif +} + +static void setEnvVars() +{ + + const QString logPath = NGL::Settings::logPath(); + qputenv("LOG4QT_LOGDIR", logPath.toLocal8Bit()); + qputenv("LOG4QT_USER", username()); +} + + +void LoggerHandler::createLogger(const QByteArray &baseName, const char *configFileName, bool quiet) +{ + setEnvVars(); + m_baseLoggerName = baseName; + + const QString bnStr(QString::fromLatin1(baseName.toLower())); + const QString logPath = NGL::Settings::logPath(); + m_loggerFilenamePostfix = logPath + QLatin1Char('/') + QString::fromLocal8Bit(username()) + QLatin1Char('_') + bnStr; + m_loggerFilenamePrefix = QLatin1String(".log"); + + const QString logOutputName = m_loggerFilenamePostfix + m_loggerFilenamePrefix; + NGL::NGLLoggerBootstrap::createNGLRootLogger(QString::fromLatin1(configFileName), false, logOutputName, quiet); + + + qInstallMessageHandler(&qtMsgHandler); +} + + +void LoggerHandler::createLogger(const QByteArray &baseName, int exerciseId, int additionalId, bool quiet) +{ + setEnvVars(); + + const QString bnStr(QString::fromLatin1(baseName.toLower())); + const QString configFileName = QLatin1String("log4cxx_") + bnStr + QLatin1String(".props"); + const QString logPath = NGL::Settings::logPath(); + m_loggerFilenamePostfix = logPath + QLatin1Char('/') + QString::fromLocal8Bit(username()) + QLatin1Char('_') + bnStr; + if (exerciseId > 0) + m_loggerFilenamePostfix += QLatin1Char('_') + QString::number(exerciseId); + if (additionalId > 0) + m_loggerFilenamePostfix += QLatin1Char('_') + QString::number(additionalId); + + m_loggerFilenamePrefix = QLatin1String(".log"); + m_baseLoggerName = baseName + QByteArray(".main"); + + const QString logOutputName = m_loggerFilenamePostfix + m_loggerFilenamePrefix; + NGL::NGLLoggerBootstrap::createNGLRootLogger(configFileName, false, logOutputName, quiet); + + + qInstallMessageHandler(&qtMsgHandler); +} + + +NGL::INGLLogger &LoggerHandler::baseLogger() const +{ + return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(m_baseLoggerName.data()); +} + + +NGL::INGLLogger &LoggerHandler::logger(const char *loggerName) const +{ + return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName); +} + + +LoggerHandler *LoggerHandler::getLoggerHandler() +{ + return dynamic_cast(QCoreApplication::instance()); +} + +} diff --git a/Z/src/nglapplication/nglloggerhandler.h b/Z/src/nglapplication/nglloggerhandler.h new file mode 100755 index 000000000..826dd754d --- /dev/null +++ b/Z/src/nglapplication/nglloggerhandler.h @@ -0,0 +1,67 @@ + + +#pragma once + +#include +#include + +#ifndef LOGGERHANDLER_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define LOGGERHANDLER_EXPORT +# else +# if defined(MAKE_NGLCOREAPPLICATION_LIB) || defined(MAKE_NGLGUIAPPLICATION_LIB) || defined(MAKE_NGLAPPLICATION_LIB) || defined(MAKE_NGLSINGLECOREAPPLICATION_LIB) || defined(MAKE_NGLSINGLEAPPLICATION_LIB) +# define LOGGERHANDLER_EXPORT Q_DECL_EXPORT +# else +# define LOGGERHANDLER_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; + +class LOGGERHANDLER_EXPORT LoggerHandler +{ +public: + LoggerHandler() = default; + ~LoggerHandler() = default; + + + + void createLogger(const QByteArray &baseName, + const char *configFileName, + bool quiet = false); + + + + void createLogger(const QByteArray &baseName, + int exerciseId = 0, + int additionalId = 0, + bool quiet = false); + + + + NGL::INGLLogger &baseLogger() const; + + + + NGL::INGLLogger &logger(const char *loggerName) const; + + + + QString loggerNamePostfix() const { return m_loggerFilenamePostfix; } + + + + QString loggerNamePrefix() const { return m_loggerFilenamePrefix; } + + + + static LoggerHandler *getLoggerHandler(); +private: + QByteArray m_baseLoggerName; + QString m_loggerFilenamePostfix; + QString m_loggerFilenamePrefix; +}; +} diff --git a/Z/src/nglapplication/nglsingleapplication.cpp b/Z/src/nglapplication/nglsingleapplication.cpp new file mode 100755 index 000000000..48dbdd4ff --- /dev/null +++ b/Z/src/nglapplication/nglsingleapplication.cpp @@ -0,0 +1,32 @@ + + + +#include "nglsingleapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLSingleApplication::NGLSingleApplication(int &argc, char **argv) + : QtSingleApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} + + +bool NGLSingleApplication::notify(QObject *o, QEvent *e) +{ + bool bRet = false; + try + { + bRet = QtSingleApplication::notify(o, e); + } + catch (const std::exception &e) + { + fprintf(stderr, "exception %s\n", e.what()); + } + return bRet; +} diff --git a/Z/src/nglapplication/nglsingleapplication.h b/Z/src/nglapplication/nglsingleapplication.h new file mode 100755 index 000000000..d34e47125 --- /dev/null +++ b/Z/src/nglapplication/nglsingleapplication.h @@ -0,0 +1,36 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLSINGLEAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLSINGLEAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLSINGLEAPPLICATION_LIB +# define NGLSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLSINGLEAPPLICATION_EXPORT NGLSingleApplication : public QtSingleApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLSingleApplication(int &argc, char **argv); + +protected: + bool notify(QObject *o, QEvent *e) override; +}; + +#define nglApp static_cast(NGLSingleApplication::instance()) diff --git a/Z/src/nglapplication/nglsinglecoreapplication.cpp b/Z/src/nglapplication/nglsinglecoreapplication.cpp new file mode 100755 index 000000000..be75bbb28 --- /dev/null +++ b/Z/src/nglapplication/nglsinglecoreapplication.cpp @@ -0,0 +1,17 @@ + + + +#include "nglsinglecoreapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLSingleCoreApplication::NGLSingleCoreApplication(int &argc, char **argv) + : QtSingleCoreApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} diff --git a/Z/src/nglapplication/nglsinglecoreapplication.h b/Z/src/nglapplication/nglsinglecoreapplication.h new file mode 100755 index 000000000..c64eba419 --- /dev/null +++ b/Z/src/nglapplication/nglsinglecoreapplication.h @@ -0,0 +1,31 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLSINGLECOREAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLSINGLECOREAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLSINGLECOREAPPLICATION_LIB +# define NGLSINGLECOREAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLSINGLECOREAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLSINGLECOREAPPLICATION_EXPORT NGLSingleCoreApplication : public QtSingleCoreApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLSingleCoreApplication(int &argc, char **argv); +}; diff --git a/Z/src/nglcompression/CMakeLists.txt b/Z/src/nglcompression/CMakeLists.txt new file mode 100755 index 000000000..0b867347d --- /dev/null +++ b/Z/src/nglcompression/CMakeLists.txt @@ -0,0 +1,47 @@ +# +# CMake Script +# $Id$ +# $HeadURL$ +# $Author$ +# + +FIND_PACKAGE(BZip2 REQUIRED) +SET(nglcomp_SRCS + nglcomp_bzip2iodevice.cpp + nglcomp_bzip2iodevice.h + nglcomp_compress.cpp + nglcomp_compress.h + nglcomp_export.h + nglcomp_tarfilter.cpp + nglcomp_tarfilter.h +) +NGL_ADD_LIBRARY(WS nglcompression SHARED ${nglcomp_SRCS}) +NGL_TARGET_LINK_LIBRARIES(nglcompression + PUBLIC + Qt5::Core + PRIVATE + Qt5::Concurrent + NGLLogger + ${BZIP2_LIBRARIES} +# BZip2::BZip2 # not available with cmake 3.5 +) +NGL_TARGET_INCLUDE_DIRECTORIES(nglcompression + PRIVATE + ${BZIP2_INCLUDE_DIR} +) +NGL_INSTALL_TARGET(nglcompression) + +IF(BUILD_WS AND BUILD_TESTING) + REMOVE_DEFINITIONS(-DQT_GUI_LIB) + ADD_EXECUTABLE(nglcomp_test nglcomp_test.cpp nglcomp_test.h) + + TARGET_LINK_LIBRARIES(nglcomp_test + NGLLogger + nglcoreapplication + ngltools + nglcompression + Qt5::Test + ) + + ADD_TEST(NAME nglcomp_test COMMAND $) +ENDIF() diff --git a/Z/src/nglcompression/nglcomp_bzip2iodevice.cpp b/Z/src/nglcompression/nglcomp_bzip2iodevice.cpp new file mode 100755 index 000000000..e8bbf0258 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_bzip2iodevice.cpp @@ -0,0 +1,360 @@ + + + + + +#include "nglcomp_bzip2iodevice.h" + +#include +#include + +#include + + + + +class BZip2IODevice::Private +{ +public: + Private(BZip2IODevice *parent_, QIODevice *dev, int bs) + : parent(parent_) + , device(dev) + , iCurPos(0) + , iMaxBufSize(1024 * 1024) + , blocksize(bs) + , initialized(false) + , decomressStreamEnd(false) + { + buffer.resize(iMaxBufSize); + } + + bool initializeCompress(); + qint64 doCompress(const char *in, qint64 iMaxLen); + bool finishCompress(); + bool initializeDecompress(); + qint64 doDecompress(char *out, qint64 iMaxLen); + bool finishDecompress(); + static QString bzipError2String(int errCode); + + QAtomicInt aborted { 0 }; + BZip2IODevice *parent; + QIODevice *device; + unsigned int iCurPos; + unsigned int iMaxBufSize; + unsigned int blocksize; + bool initialized; + bool decomressStreamEnd; + QByteArray buffer; + bz_stream stream; +}; + +bool BZip2IODevice::Private::initializeCompress() +{ + if (initialized) + return true; + memset(&stream, 0, sizeof(stream)); + int blockSize = (blocksize > 0 && blocksize < 10) ? blocksize : 10; + int ret = BZ2_bzCompressInit(&stream, blockSize, 0, 0); + if (ret != BZ_OK) + { + parent->setErrorString(QStringLiteral("Error initializing bzip2 %1").arg(bzipError2String(ret))); + initialized = false; + } + else + initialized = true; + + return initialized; +} + +qint64 BZip2IODevice::Private::doCompress(const char *in, qint64 iMaxLen) +{ + if (!initialized) + { + if (parent->errorString().isEmpty()) + parent->setErrorString(QLatin1String("Internal Error - bzip not initialized")); + finishCompress(); + return -1; + } + if (iMaxLen > 2 * 1024 * 1024 * 1024LL) + { + finishCompress(); + parent->setErrorString(QLatin1String("Currently can't handle more than 2GB!")); + return -1; + } + + stream.next_in = const_cast(in); + stream.avail_in = iMaxLen; + + do + { + if (aborted) return 0; + + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); + + const int ret = BZ2_bzCompress(&stream, BZ_RUN); + if (ret != BZ_RUN_OK) + { + finishCompress(); + parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret))); + return -1; + } + int iBytesToWrite = buffer.size() - stream.avail_out; + if (iBytesToWrite) + { + if (device->write(buffer.constData(), iBytesToWrite) != iBytesToWrite) + { + finishCompress(); + parent->setErrorString(QLatin1String("Error writing to QIODevice")); + return -1; + } + } + } + while (stream.avail_in != 0); + + return stream.next_in - in; +} + +bool BZip2IODevice::Private::finishCompress() +{ + if (!initialized || aborted) + return true; + + int ret = -1; + + do + { + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); + ret = BZ2_bzCompress(&stream, BZ_FINISH); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { + finishCompress(); + parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret))); + return false; + } + int iBytesToWrite = buffer.size() - stream.avail_out; + if (device->write(buffer.constData(), iBytesToWrite) != iBytesToWrite) + { + finishCompress(); + parent->setErrorString(QLatin1String("Error writing to QIODevice")); + return false; + } + } + while (ret != BZ_STREAM_END); + BZ2_bzCompressEnd(&stream); + + initialized = false; + return true; +} + +bool BZip2IODevice::Private::initializeDecompress() +{ + if (initialized) + return true; + memset(&stream, 0, sizeof(stream)); + int ret = BZ2_bzDecompressInit(&stream, 0, 0); + if (ret != BZ_OK) + { + parent->setErrorString(QStringLiteral("Error initializing bzip2: %1").arg(bzipError2String(ret))); + initialized = false; + } + else + initialized = true; + decomressStreamEnd = false; + return initialized; +} + +qint64 BZip2IODevice::Private::doDecompress(char *out, qint64 iMaxLen) +{ + int ret = -1; + if (!initialized) + { + if (parent->errorString().isEmpty()) + parent->setErrorString(QLatin1String("Internal Error - bzip not initialized")); + finishDecompress(); + return -1; + } + if (decomressStreamEnd) + return 0; + + if (iMaxLen > 2 * 1024 * 1024 * 1024LL) + { + finishCompress(); + parent->setErrorString(QLatin1String("Currently can't handle more than 2GB!")); + return -1; + } + + stream.next_out = out; + stream.avail_out = iMaxLen; + + do + { + if (ret != BZ_STREAM_END && stream.avail_in == 0) + { + qint64 iReadCnt = device->read(buffer.data(), buffer.size()); + if (iReadCnt <= 0) + return -1; + stream.next_in = buffer.data(); + stream.avail_in = iReadCnt; + } + + ret = BZ2_bzDecompress(&stream); + if (ret != BZ_OK && ret != BZ_STREAM_END) + { + parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret))); + finishDecompress(); + return -1; + } + } + while (stream.avail_out != 0 && ret != BZ_STREAM_END); + decomressStreamEnd = (ret == BZ_STREAM_END); + return stream.next_out - out; +} + +bool BZip2IODevice::Private::finishDecompress() +{ + if (!initialized) + return true; + BZ2_bzDecompressEnd(&stream); + + initialized = false; + return true; +} + +QString BZip2IODevice::Private::bzipError2String(int errCode) +{ + switch (errCode) + { + case BZ_SEQUENCE_ERROR: + return QLatin1String("Sequence error"); + case BZ_PARAM_ERROR: + return QLatin1String("Parameter not correct"); + case BZ_MEM_ERROR: + return QLatin1String("Memory allocation error"); + case BZ_DATA_ERROR: + return QLatin1String("Invalid input data"); + case BZ_DATA_ERROR_MAGIC: + return QLatin1String("Not a bzip2 file"); + case BZ_IO_ERROR: + return QLatin1String("I/O error"); + case BZ_UNEXPECTED_EOF: + return QLatin1String("Unexpected end of file"); + case BZ_OUTBUFF_FULL: + return QLatin1String("Output buffer full"); + case BZ_CONFIG_ERROR: + return QLatin1String("Wrong config parameter"); + }; + return QString::number(errCode); +} + + + + +BZip2IODevice::BZip2IODevice(QIODevice *dev, int blocksize) + : d(new Private(this, dev, blocksize)) +{} + +BZip2IODevice::~BZip2IODevice() +{ + close(); + delete d; +} + +void BZip2IODevice::setBufferSize(unsigned int size) +{ + d->iMaxBufSize = size > 1024 ? size : 1024; + d->buffer.resize(d->iMaxBufSize); +} + +void BZip2IODevice::setBlockSize(unsigned int size) +{ + if (isOpen()) + return; + d->blocksize = size; +} + +bool BZip2IODevice::isSequential() const +{ + return true; +} + +bool BZip2IODevice::open(OpenMode mode) +{ + if ((mode & QIODevice::ReadWrite) == 0) + { + setErrorString(QStringLiteral("Unsupported OpenMode %1").arg(mode)); + return false; + } + if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) + { + setErrorString(QLatin1String("Can't read and write simultaniously")); + return false; + } + if ((mode & QIODevice::ReadOnly) == QIODevice::ReadOnly) + { + if (!d->device) + { + setErrorString(QLatin1String("No QIODevice for reading available")); + return false; + } + if ((d->device->openMode() & QIODevice::ReadOnly) == 0) + { + setErrorString(QLatin1String("QIODevice not opened for reading")); + return false; + } + if (!d->initializeDecompress()) + return false; + } + else + { + if (!d->device) + { + setErrorString(QLatin1String("No QIODevice for writing available")); + return false; + } + if ((d->device->openMode() & QIODevice::WriteOnly) == 0) + { + setErrorString(QLatin1String("QIODevice not opened for writing")); + return false; + } + if (!d->initializeCompress()) + return false; + } + setErrorString(QString()); + setOpenMode(mode); + return QIODevice::open(mode); +} + +void BZip2IODevice::abort() +{ + d->aborted = 1; +} + +void BZip2IODevice::close() +{ + if (!isOpen()) + return; + if ((openMode() & QIODevice::ReadOnly) == QIODevice::ReadOnly) + d->finishDecompress(); + else + d->finishCompress(); + QIODevice::close(); +} + +bool BZip2IODevice::atEnd() const +{ + if (!d->device) + return true; + return d->device->atEnd() && d->decomressStreamEnd && QIODevice::atEnd(); +} + +qint64 BZip2IODevice::readData(char *data, qint64 maxSize) +{ + return d->doDecompress(data, maxSize); +} + +qint64 BZip2IODevice::writeData(const char *data, qint64 maxSize) +{ + return d->doCompress(data, maxSize); +} diff --git a/Z/src/nglcompression/nglcomp_bzip2iodevice.h b/Z/src/nglcompression/nglcomp_bzip2iodevice.h new file mode 100755 index 000000000..79310fbdc --- /dev/null +++ b/Z/src/nglcompression/nglcomp_bzip2iodevice.h @@ -0,0 +1,42 @@ + + + + + +#ifndef BZIP2IODEVICE_H +#define BZIP2IODEVICE_H + +#include +#include + + + +class BZip2IODevice : public QIODevice +{ +public: + + + + BZip2IODevice(QIODevice *dev, int blocksize = 5); + virtual ~BZip2IODevice(); + + void abort(); + void setBufferSize(unsigned int size); + void setBlockSize(unsigned int size); + + + virtual bool isSequential() const; + virtual bool open(OpenMode mode); + virtual void close(); + virtual bool atEnd() const; +protected: + virtual qint64 readData(char *data, qint64 maxSize); + virtual qint64 writeData(const char *data, qint64 maxSize); +private: + + class Private; + friend class Private; + Private *const d; +}; + +#endif diff --git a/Z/src/nglcompression/nglcomp_compress.cpp b/Z/src/nglcompression/nglcomp_compress.cpp new file mode 100755 index 000000000..aeed7079c --- /dev/null +++ b/Z/src/nglcompression/nglcomp_compress.cpp @@ -0,0 +1,566 @@ + + +#include "nglcomp_compress.h" +#include "nglcomp_bzip2iodevice.h" +#include "nglcomp_tarfilter.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + + + + + + + + +#include + + + + + + + + + + + + +namespace NGL +{ + +Compress::Compress(QObject *parent) + : QObject(parent) + , m_u2_memFiles() + , m_aborted(0) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("nglcompress")) +{ + DEBUG_LOG(m_logger) << "c_tor"; + + + + + + + + + + QTimer *t = new QTimer(this); + t->setInterval(1000); + connect(t, &QTimer::timeout, this, [](){qWarning() << "still alive ...";}); + t->start(); +} + +Compress::~Compress() +{ + qWarning() << "## COMPRESS DTOR!!!!"; + + + DEBUG_LOG(m_logger) << "~"; + + abort(); + m_future.waitForFinished(); + DEBUG_LOG(m_logger) << "~ finished"; +} + +void Compress::abort() +{ + DEBUG_LOG(m_logger) << "ABORT"; + + m_aborted = 1; + m_lastError = tr("Aborted"); + + if (m_currentTarFilter != nullptr) + { + DEBUG_LOG(m_logger) << "aborting tar"; + m_currentTarFilter->abort(); + } + + if (m_currentBzipDevice != nullptr) + { + DEBUG_LOG(m_logger) << "aborting bzip"; + m_currentBzipDevice->abort(); + } +} + +void Compress::compress(QIODevice *out, + const QString &filesRootDir, + const QVector &files, + const QVector &memFiles, + const QString &destRootDir) +{ + DEBUG_LOG(m_logger) << "compress #2"; + reset(); + setupFutureWatcher(QtConcurrent::run(this, &Compress::_compress, out, filesRootDir, files, memFiles, destRootDir)); +} + +void Compress::compress(QIODevice *out, const QString &sourceDir, const QString &destRootDir) +{ + DEBUG_LOG(m_logger) << "compress #1 source dir: " << sourceDir << ", destRootDir: " << destRootDir; + reset(); + + QVector inFiles = directoryFileList(sourceDir, true); + + + int len = sourceDir.length(); + if (!sourceDir.endsWith(QLatin1Char('/'))) + len += 1; + for (auto &fi : inFiles) + { + fi.inputFileName = fi.inputFileName.mid(len); + fi.bAbsInputPath = false; + DEBUG_LOG(m_logger) << "fi: ifm = " << fi.inputFileName << ", abs = " << fi.bAbsInputPath; + } + + DEBUG_LOG(m_logger) << "FI list size: " << inFiles.count(); + + compress(out, sourceDir, inFiles, {}, destRootDir); +} + +bool Compress::_compress(QIODevice *output, + const QString &filesRootDir, + const QVector &files, + const QVector &memFiles, + const QString &_destRootDir) +{ + std::shared_ptr invalidatePointersOnScopeLeave(nullptr, [this](int *) + { + DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #1"; + m_currentTarFilter = nullptr; + m_currentBzipDevice = nullptr; + }); + (void)invalidatePointersOnScopeLeave; + + + if (!output || !output->isWritable()) + { + m_lastError = tr("Device is not writeable"); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError;; + + return false; + } + + const QString destRootDir = _destRootDir.endsWith(QLatin1Char('/')) ? + _destRootDir : _destRootDir + QLatin1Char('/'); + + const qint64 maxCount = files.count() + memFiles.count(); + qint64 count = 0; + + DEBUG_LOG(m_logger) << "destRootDir = " << destRootDir << ", maxCount = " << maxCount << ", count = " << count; + + BZip2IODevice bzip2(output, 9); + m_currentBzipDevice = &bzip2; + + if (!bzip2.open(QIODevice::WriteOnly)) + { + m_lastError = bzip2.errorString(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + + + qint64 bytesTotal = 0; + for (const FileInformations &file : qAsConst(files)) + { + if (m_aborted) return false; + + const QString in = file.bAbsInputPath ? file.inputFileName : filesRootDir + QLatin1Char('/') + file.inputFileName; + const QFileInfo fi(in); + + bytesTotal += fi.size(); + } + + + qint64 currentFileSize = 0; + QString currentFileName; + auto readCallback = [this, &maxCount, &count, ¤tFileSize, ¤tFileName, &bytesTotal](const qint64 iSize) + { + DEBUG_LOG(m_logger) << "readCallback: maxCount = " << maxCount << ", count = " << count + << ", currentFileSize = " << currentFileSize << ", currentFileName = " << currentFileName << ", iSize = " << iSize; + emit compressInfoEx(maxCount, count, currentFileSize, (currentFileSize - iSize), currentFileName, bytesTotal); + }; + + + TarFilter tf(&bzip2, nullptr, readCallback); + m_currentTarFilter = &tf; + const QVector paths = destRootDir.splitRef(QLatin1Char('/'), QString::SkipEmptyParts); + QString curPath; + + + DEBUG_LOG(m_logger) << "prepairing tar filter"; + for (const QStringRef &path : paths) + { + DEBUG_LOG(m_logger) << "path = " << path.toString(); + if (m_aborted) return false; + + if (curPath.isEmpty()) + curPath = path + QLatin1Char('/'); + else + curPath += path + QLatin1Char('/'); + + DEBUG_LOG(m_logger) << "curPath = " << curPath << ", filesRootDir.isEmpty() = " << filesRootDir.isEmpty(); + + if (filesRootDir.isEmpty()) + { + if (!tf.addData(curPath, QByteArray(), true)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + else + { + if (!tf.addFile(filesRootDir, curPath)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + } + + m_c_sizeInfo.realSize = 0; + for (const FileInformations &file : qAsConst(files)) + { + DEBUG_LOG(m_logger) << "file = " << file.inputFileName; + emit compressInfo(maxCount, ++count, file.inputFileName); + + if (m_aborted) return false; + + QString in = file.bAbsInputPath ? file.inputFileName : filesRootDir + QLatin1Char('/') + file.inputFileName; + QString out = destRootDir + (file.outputFileName.isEmpty() ? file.inputFileName : file.outputFileName); + + DEBUG_LOG(m_logger) << "in = " << in << ", out = " << out; + + QFileInfo fi(in); + + currentFileName = fi.fileName(); + currentFileSize = fi.size(); + m_c_sizeInfo.realSize += currentFileSize; + + DEBUG_LOG(m_logger) << "currentFileName = " << currentFileName << ", currentFileSize = " << currentFileSize << "m_c_sizeInfo.realSize" << m_c_sizeInfo.realSize; + + if (!tf.addFile(in, out)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + + for (const FileInformations &file : qAsConst(memFiles)) + { + DEBUG_LOG(m_logger) << "(mem) file = " << file.inputFileName; + emit compressInfo(maxCount, ++count, file.inputFileName); + + if (m_aborted) return false; + + currentFileName = file.inputFileName; + currentFileSize = file.fileData.size(); + m_c_sizeInfo.compressedSize += currentFileSize; + + DEBUG_LOG(m_logger) << "(mem) currentFileName = " << currentFileName << ", currentFileSize = " << currentFileSize << "m_c_sizeInfo.realSize" << m_c_sizeInfo.realSize; + + if (!tf.addData(file.inputFileName, file.fileData)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + + + DEBUG_LOG(m_logger) << "writing eos"; + tf.writeEOS(); + + DEBUG_LOG(m_logger) << "closing bzip"; + bzip2.close(); + + m_c_sizeInfo.compressedSize = output->size(); + DEBUG_LOG(m_logger) << "m_c_sizeInfo.compressedSize = " << m_c_sizeInfo.compressedSize; + + m_success = true; + + DEBUG_LOG(m_logger) << "DONE!"; + + return true; +} + +void Compress::uncompress(QIODevice *in, const QString &outDir) +{ + DEBUG_LOG(m_logger) << "uncompress #1"; + reset(); + setupFutureWatcher(QtConcurrent::run(this, &Compress::_uncompressDirectory, in, outDir)); +} + +bool Compress::_uncompressDirectory(QIODevice *input, const QString &outDir) +{ + DEBUG_LOG(m_logger) << "_uncompressDirectory"; + + std::shared_ptr invalidatePointersOnScopeLeave(nullptr, [this](int *) + { + DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #2"; + m_currentTarFilter = nullptr; + m_currentBzipDevice = nullptr; + }); + (void)invalidatePointersOnScopeLeave; + + + if (!input || !input->isReadable()) + { + m_lastError = tr("Device is not readable"); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + BZip2IODevice bzip2(input, 9); + m_currentBzipDevice = &bzip2; + if (!bzip2.open(QIODevice::ReadOnly)) + { + m_lastError = bzip2.errorString(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + TarFilter tf(&bzip2); + m_currentTarFilter = &tf; + TarFilter::FileInformations tfi; + QDir dir(outDir); + + DEBUG_LOG(m_logger) << "dir = " << dir.path(); + + while (tf.getData(tfi)) + { + DEBUG_LOG(m_logger) << "tfi.fileName = " << tfi.fileName; + emit uncompressInfo(input->size(), input->pos(), tfi.fileName); + if (m_aborted) return false; + + QString path = outDir + QLatin1Char('/') + tfi.fileName; + DEBUG_LOG(m_logger) << "path = " << path; + if (tfi.fileType == TarFilter::directory) + { + DEBUG_LOG(m_logger) << "tfi.fileType == TarFilter::directory"; + if (!dir.exists(path) && !dir.mkpath(path)) + { + m_lastError = tr("Error creating directory %1").arg(outDir); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + else + { + + QString pathName = QFileInfo(path).absolutePath(); + if (!dir.exists(pathName) && !dir.mkpath(pathName)) + { + m_lastError = tr("Error creating directory %1").arg(pathName); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + QFile f(path); + if (!f.open(QIODevice::WriteOnly)) + { + m_lastError = tr("Error opening %1 for writing (%2)").arg(path, f.errorString()); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + if (!tf.getData(&f)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + } + + DEBUG_LOG(m_logger) << "uncompress done!"; + m_success = true; + return true; +} + +void Compress::uncompress(QIODevice *in) +{ + DEBUG_LOG(m_logger) << "uncompress #2!"; + reset(); + setupFutureWatcher(QtConcurrent::run(this, &Compress::_uncompressBuffer, in)); +} + +bool Compress::_uncompressBuffer(QIODevice *input) +{ + DEBUG_LOG(m_logger) << "uncompressBuffer"; + + std::shared_ptr invalidatePointersOnScopeLeave(nullptr, [this](int *) + { + DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #2"; + m_currentTarFilter = nullptr; + m_currentBzipDevice = nullptr; + }); + (void)invalidatePointersOnScopeLeave; + + + if (!input->isReadable()) + { + m_lastError = tr("Device is not readable"); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + BZip2IODevice bzip2(input, 9); + m_currentBzipDevice = &bzip2; + if (!bzip2.open(QIODevice::ReadOnly)) + { + m_lastError = bzip2.errorString(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + TarFilter tf(&bzip2); + m_currentTarFilter = &tf; + TarFilter::FileInformations tfi; + while (tf.getData(tfi)) + { + DEBUG_LOG(m_logger) << "tfi.fileName = " << tfi.fileName; + emit uncompressInfo(input->size(), input->pos(), tfi.fileName); + if (m_aborted) return false; + + FileInformations fi; + fi.outputFileName = tfi.fileName; + + DEBUG_LOG(m_logger) << "fi.outputFileName = " << fi.outputFileName; + + if (tfi.fileType == TarFilter::directory) + { + fi.outputFileName += QLatin1Char('/'); + DEBUG_LOG(m_logger) << "> fi.outputFileName = " << fi.outputFileName; + } + else + { + DEBUG_LOG(m_logger) << "stuff"; + + QBuffer buf(&fi.fileData); + if (!buf.open(QIODevice::WriteOnly)) + { + m_lastError = tr("Error opening buffer for writing (%1)").arg(buf.errorString()); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + if (!tf.getData(&buf)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + + fi.bAbsInputPath = fi.outputFileName.startsWith(QLatin1Char('/')); + DEBUG_LOG(m_logger) << "added fi.bAbsInputPath = " << fi.bAbsInputPath; + m_u2_memFiles += fi; + } + + return true; +} + +bool Compress::success() const +{ + + ERROR_LOG(m_logger) << "success? " << (m_future.isFinished() && !m_future.isCanceled() && m_success); + ERROR_LOG(m_logger) << "success details: " + << "success m_future.isFinished() = " << (m_future.isFinished()) + << " !m_future.isCanceled() = " << !m_future.isCanceled() + << " m_success = " << m_success; + return (m_future.isFinished() && !m_future.isCanceled() && m_success); +} + +bool Compress::waitForFinished() +{ + DEBUG_LOG(m_logger) << "waitForFinished..."; + m_future.waitForFinished(); + DEBUG_LOG(m_logger) << "waitForFinished... done!"; + return success(); +} + +QVector Compress::directoryFileList(const QString &dir, bool recursive) +{ + DEBUG_LOG(m_logger) << "directoryFileList"; + + QVector sl_absolute; + QDir d(dir); + + if (d.exists()) + { + DEBUG_LOG(m_logger) << "exists"; + const auto entries = d.entryList(QDir::Files); + sl_absolute.reserve(sl_absolute.size() + entries.size()); + for (const QString &entry : entries) + sl_absolute << FileInformations(QFileInfo(d, entry).absoluteFilePath(), true); + } + + if (recursive) + { + DEBUG_LOG(m_logger) << "recursive"; + const auto entries = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + sl_absolute.reserve(sl_absolute.size() + entries.size()); + for (const QString &s : entries) + sl_absolute << directoryFileList(dir + QLatin1Char('/') + s, true); + } + + DEBUG_LOG(m_logger) << "done"; + return sl_absolute; +} + +void Compress::reset() +{ + DEBUG_LOG(m_logger) << "reset"; + m_u2_memFiles.clear(); + + m_lastError.clear(); + + m_c_sizeInfo.realSize = 0; + m_c_sizeInfo.compressedSize = 0; + + m_success = false; +} + +void Compress::setupFutureWatcher(const QFuture &future) +{ + DEBUG_LOG(m_logger) << "setupFutureWatcher"; + m_future = future; + QFutureWatcher *fw = new QFutureWatcher(this); + QObject::connect(fw, &QObject::destroyed, this, [this]() { DEBUG_LOG(m_logger) << "Future Watcher destroyed"; }); + QObject::connect(fw, &QFutureWatcher::finished, this, &Compress::finished); + QObject::connect(fw, &QFutureWatcher::finished, fw, &QObject::deleteLater); + QObject::connect(fw, &QFutureWatcher::finished, fw, [this]() { DEBUG_LOG(m_logger) << "Future Watcher about to be deleted"; }); + fw->setFuture(m_future); +} + +} diff --git a/Z/src/nglcompression/nglcomp_compress.h b/Z/src/nglcompression/nglcomp_compress.h new file mode 100755 index 000000000..07c6ee0d0 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_compress.h @@ -0,0 +1,140 @@ + + +#pragma once + +#include "nglcomp_export.h" + +#include + +#include +#include +#include +#include +#include + +class QIODevice; +class TarFilter; +class BZip2IODevice; + + +namespace NGL +{ +class NGLCOMPRESSION_EXPORT Compress : public QObject +{ + Q_OBJECT +public: + struct FileInformations + { + QString inputFileName; + QString outputFileName; + QByteArray fileData; + bool bAbsInputPath = true; + FileInformations() = default; + + FileInformations(const QString &name, bool isAbsolute) + : inputFileName(name) + , bAbsInputPath(isAbsolute) + {} + }; + + + struct FileSizeInfo + { + qint64 realSize = 0; + qint64 compressedSize = 0; + }; + + + + explicit Compress(QObject *parent = nullptr); + + ~Compress(); + + + + QVector getMemFiles() const { return m_u2_memFiles; } + + + FileSizeInfo getFileSizeInfo() const { return m_c_sizeInfo; } + + + bool success() const; + + + + void compress(QIODevice *out, + const QString &sourceRootDir, + const QVector &files, + const QVector &memFiles, + const QString &destRootDir); + + + + void compress(QIODevice *out, + const QString &sourceDir, + const QString &destRootDir); + + + void uncompress(QIODevice *in, + const QString &outDir); + + + void uncompress(QIODevice *in); + + + QString lastError() const { return m_lastError; } + + + + bool waitForFinished(); + +public Q_SLOTS: + void abort(); + +Q_SIGNALS: + + + void uncompressInfo(qint64 totalSize, qint64 curPos, const QString &curName); + + + void compressInfo(qint64 totalFiles, qint64 curFile, const QString &curName); + void compressInfoEx(qint64 totalFiles, qint64 curFile, qint64 totalSize, qint64 curPos, const QString &curName, const qint64 bytesTotal); + + + + void error(const QString &errorString); + + + + void finished(); +private: + + bool _compress(QIODevice *output, + const QString &filesRootDir, + const QVector &files, + const QVector &memFiles, + const QString &_destRootDir); + bool _uncompressDirectory(QIODevice *input, const QString &outDir); + bool _uncompressBuffer(QIODevice *input); + + void reset(); + void setupFutureWatcher(const QFuture &future); + + QVector directoryFileList(const QString &dir, bool recursive = false); + + FileSizeInfo m_c_sizeInfo; + QVector m_u2_memFiles; + + QString m_lastError; + QAtomicInt m_aborted; + + TarFilter *m_currentTarFilter { nullptr }; + BZip2IODevice *m_currentBzipDevice { nullptr }; + + QFuture m_future; + bool m_success { false }; + NGL::INGLLogger &m_logger; +}; +} +Q_DECLARE_TYPEINFO(NGL::Compress::FileInformations, Q_MOVABLE_TYPE); + diff --git a/Z/src/nglcompression/nglcomp_export.h b/Z/src/nglcompression/nglcomp_export.h new file mode 100755 index 000000000..a1fcc74d8 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLCOMPRESSION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLCOMPRESSION_EXPORT +# else +# if defined(MAKE_NGLCOMPRESSION_LIB) +# define NGLCOMPRESSION_EXPORT Q_DECL_EXPORT +# else +# define NGLCOMPRESSION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/nglcompression/nglcomp_tarfilter.cpp b/Z/src/nglcompression/nglcomp_tarfilter.cpp new file mode 100755 index 000000000..37c290324 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_tarfilter.cpp @@ -0,0 +1,525 @@ + + + + + +#include +#include +#include +#include +#include +#include + +#include + +#include "nglcomp_tarfilter.h" + +#ifndef Q_OS_WIN +#include +#include +#include +#endif + + + + + + + + +class TarFilter::Private +{ +public: + Private(QIODevice *dev, QTextCodec *c) + : device(dev) + , codec(c ? c : QTextCodec::codecForLocale()) + , iBufSize(1024 * 1024) + , nextChunkSize(-1) + {} + + struct tar_posix_header + { + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; + char unused[12]; + }; + bool fi2tph(const FileInformations &infos); + bool addHeader(const FileInformations &infos); + + bool tph2fi(FileInformations &infos); + bool getHeader(FileInformations &infos); + bool checkDevice(QIODevice *in, QIODevice *out); + bool copyData(QIODevice *in, QIODevice *out, qint64 iSize); + + QIODevice *device; + QTextCodec *codec; + QString lastError; + unsigned int iBufSize; + qint64 nextChunkSize; + QAtomicInt aborted { 0 }; + std::function readCallback; +}; + +bool TarFilter::Private::fi2tph(const FileInformations &infos) +{ + QByteArray fn = codec->fromUnicode(infos.fileName); +#ifdef Q_OS_WIN + if (fn.size() > 3 && fn[1] == ':' && (fn[2] == '\\' || fn[2] == '/')) + fn = fn.mid(3); +#endif + if (fn.startsWith('/')) + fn = fn.mid(1); + + long unsigned int fileSize = infos.fileType == directory ? 0 : infos.fileSize; + long unsigned int mtime = infos.mtime != -1 ? infos.mtime : time(nullptr); + tar_posix_header hdr; + memset(&hdr, 0, sizeof(hdr)); + QByteArray fn_part1 = fn.left(sizeof(hdr.name)); + memcpy(hdr.name, fn_part1.constData(), fn_part1.size()); + sprintf(hdr.mode, "%07x", 0x0fff & infos.mode); + sprintf(hdr.uid, "%07o", infos.uid); + sprintf(hdr.gid, "%07o", infos.gid); + sprintf(hdr.size, "%011lo", fileSize); + sprintf(hdr.mtime, "%011lo", mtime); + memset(hdr.chksum, ' ', sizeof(hdr.chksum)); + hdr.typeflag = infos.fileType; + + memcpy(hdr.magic, "ustar ",sizeof(hdr.magic) + sizeof(hdr.version)); +#ifdef Q_OS_WIN + + +#else + qstrncpy(hdr.uname, codec->fromUnicode(infos.uname).constData(), sizeof(hdr.uname)); + qstrncpy(hdr.gname, codec->fromUnicode(infos.gname).constData(), sizeof(hdr.gname)); +#endif + + + + + unsigned int checksum = 0; + const unsigned char *ptr = reinterpret_cast(&hdr); + for (unsigned i = 0; i < sizeof(hdr); i++) + checksum += ptr[i]; + constexpr int octalMax = 01000000; + while (checksum > octalMax) + checksum -= octalMax; + sprintf(hdr.chksum, "%06o", checksum); + + if (!device->write((const char *)&hdr, sizeof(hdr))) + { + lastError = QLatin1String("Error writing to QIODevice"); + return false; + } + return true; +} + +bool TarFilter::Private::addHeader(const FileInformations &infos) +{ + + + QByteArray fn = codec->fromUnicode(infos.fileName); +#ifdef Q_OS_WIN + if (fn.size() > 3 && fn[1] == ':' && (fn[2] == '\\' || fn[2] == '/')) + fn = fn.mid(3); +#endif + if (fn.startsWith('/')) + fn = fn.mid(1); + if (fn.size() > 512) + { + lastError = QLatin1String("Can't handle filenames with more then 512 bytes"); + return false; + } + if (fn.size() > 100) + { + FileInformations longlink; + longlink.fileName = QLatin1String("././@LongLink"); + longlink.fileType = gnu_longname; + longlink.fileSize = strlen(fn.constData()) + 1; + longlink.mtime = 0; + longlink.uid = 0; + longlink.gid = 0; +#ifndef Q_OS_WIN + struct passwd *p = getpwuid(longlink.uid); + if (p) + longlink.uname = codec->toUnicode(p->pw_name); + struct group *g = getgrgid(longlink.gid); + if (g) + longlink.gname = codec->toUnicode(g->gr_name); +#endif + fi2tph(longlink); + QByteArray ba(512, '\0'); + qstrncpy(ba.data(), fn.constData(), ba.size()); + if (!device->write(ba.constData(), ba.size())) + { + lastError = QLatin1String("Error writing to QIODevice"); + return false; + } + } + if (!fi2tph(infos)) + return false; + + return true; +} + +bool TarFilter::Private::tph2fi(FileInformations &infos) +{ + Private::tar_posix_header hdr; + do + { + int iBytesRead = device->read((char *)&hdr, sizeof(hdr)); + if (iBytesRead != sizeof(hdr)) + { + if (iBytesRead == 0 && device->atEnd()) + { + lastError = QString(); + return false; + } + lastError = QStringLiteral("Error reading from QIODevice! needed: %1, got: %2").arg(sizeof(hdr)).arg(iBytesRead); + return false; + } + } + while (memcmp(hdr.magic, "\0\0\0\0\0\0", sizeof(hdr.magic)) == 0); + if (memcmp(hdr.magic, "ustar ", sizeof(hdr.magic))) + { + lastError = QLatin1String("The archive is not supported"); + return false; + } + int checksum = QByteArray(hdr.chksum, sizeof(hdr.chksum)).toUInt(nullptr, 8); + memset(hdr.chksum, ' ', sizeof(hdr.chksum)); + int realChecksum = 0; + const unsigned char *ptr = reinterpret_cast(&hdr); + for (unsigned i = 0; i < sizeof(hdr); i++) + realChecksum += ptr[i]; + if (checksum != realChecksum) + { + lastError = QStringLiteral("Checksum does not match! needed: %1, got: %2").arg(checksum).arg(realChecksum); + return false; + } + + QByteArray ba(hdr.name, sizeof(hdr.name)); + ba.resize(qstrlen(ba.constData())); + infos.fileName = codec->toUnicode(ba); + infos.fileSize = QByteArray(hdr.size, sizeof(hdr.size)).toUInt(nullptr, 8); + infos.mode = static_cast(QByteArray(hdr.mode, sizeof(hdr.mode)).toUInt(nullptr, 16)); + infos.uid = QByteArray(hdr.uid, sizeof(hdr.uid)).toUInt(nullptr, 8); + infos.gid = QByteArray(hdr.gid, sizeof(hdr.gid)).toUInt(nullptr, 8); + infos.mtime = QByteArray(hdr.mtime, sizeof(hdr.mtime)).toUInt(nullptr, 8); + infos.fileType = (FileType)hdr.typeflag; + infos.uname = codec->toUnicode(hdr.uname, sizeof(hdr.uname)); + infos.gname = codec->toUnicode(hdr.gname, sizeof(hdr.gname)); + + return true; +} + +bool TarFilter::Private::getHeader(FileInformations &infos) +{ + if (!tph2fi(infos)) + return false; + switch (infos.fileType) + { + case regular: + case regular2: + case directory: + case gnu_longname: + break; + default: + lastError = QStringLiteral("Unsupported fileType %1").arg(infos.fileType); + return false; + } + if (infos.fileType == gnu_longname) + { + const QByteArray fn = device->read(512); + if (fn.size() != 512) + { + lastError = QLatin1String("Unexpected end of inputstream"); + return false; + } + if (!tph2fi(infos)) + return false; + const int len = qstrlen(fn.constData()); + infos.fileName = codec->toUnicode(fn.constData(), len); + } + + return true; +} + +bool TarFilter::Private::checkDevice(QIODevice *in, QIODevice *out) +{ + if (!in) + { + lastError = QLatin1String("No QIODevice for reading available"); + return false; + } + if ((in->openMode() & QIODevice::ReadOnly) == 0) + { + lastError = QLatin1String("QIODevice not opened for reading"); + return false; + } + + if (!out) + { + lastError = QLatin1String("No QIODevice for writing available"); + return false; + } + if ((out->openMode() & QIODevice::WriteOnly) == 0) + { + lastError = QLatin1String("QIODevice not opened for writing"); + return false; + } + return true; +} + +bool TarFilter::Private::copyData(QIODevice *in, QIODevice *out, qint64 iSize) +{ + if (iSize <= 0) + return true; + + while (iSize > 0) + { + if (aborted) return false; + + const qint64 iBytesToRead = iSize > iBufSize ? iBufSize : iSize; + const QByteArray ba = in->read(iBytesToRead); + + if (aborted) return false; + + if (ba.size() == 0) + { + lastError = QStringLiteral("Could not read %1 bytes from QIODevice").arg(iBytesToRead); + return false; + } + + if (out->write(ba) != ba.size()) + { + lastError = QStringLiteral("Could not write %1 bytes to QIODevice").arg(ba.size()); + return false; + } + iSize -= ba.size(); + + if (readCallback) + readCallback(iSize); + } + return true; +} + + + + +TarFilter::TarFilter(QIODevice *dev, QTextCodec *codec, const std::function &readCallback) + : d(new Private(dev, codec)) +{ + d->readCallback = readCallback; +} + +TarFilter::~TarFilter() +{ + delete d; +} + +void TarFilter::abort() +{ + d->aborted = 1; +} + +void TarFilter::setLocaleCodec(QTextCodec *codec) +{ + d->codec = codec ? codec : QTextCodec::codecForLocale(); +} + +void TarFilter::setBufferSize(unsigned int size) +{ + d->iBufSize = size > 1024 ? size : 1024; +} + +bool TarFilter::error() const +{ + return !d->lastError.isEmpty(); +} + +QString TarFilter::lastError() const +{ + return d->lastError; +} + +bool TarFilter::addFile(const QString &filename, const QString &filenameInArchive) +{ + QFileInfo fi(filename); + if (!fi.exists()) + { + d->lastError = QStringLiteral("File %1 does not exist").arg(filename); + return false; + } + if (!(fi.isDir() || fi.isFile())) + { + d->lastError = QStringLiteral("%1 isn't a directory or a regular file").arg(filename); + return false; + } + + FileInformations fInfos; + fInfos.fileName = (filenameInArchive.isEmpty() ? filename : filenameInArchive); + fInfos.fileSize = fi.isDir() ? 0 : fi.size(); + fInfos.mode = fi.permissions() & 0x0fff; +#ifdef Q_OS_WIN + fInfos.uid = 1000; + fInfos.gid = 100; +#else + fInfos.uid = fi.ownerId(); + fInfos.gid = fi.groupId(); + fInfos.uname = fi.owner(); + fInfos.gname = fi.group(); +#endif + fInfos.mtime = fi.lastModified().toSecsSinceEpoch(); + fInfos.fileType = fi.isDir() ? directory : regular; + + if (fi.isDir()) + { + QBuffer buf; + buf.open(QIODevice::ReadOnly); + return addData(fInfos, &buf); + } + QFile f(filename); + if (!f.open(QIODevice::ReadOnly)) + { + d->lastError = QStringLiteral("Error opening %1 for reading").arg(filename); + return false; + } + + if (d->aborted) return false; + + return addData(fInfos, &f); +} + +bool TarFilter::addData(const QString &filename, const QByteArray &data, bool bIsDir) +{ + if (d->aborted) return false; + + FileInformations fi; + fi.fileName = filename; + fi.fileSize = bIsDir ? 0 : data.size(); + fi.mode = static_cast(bIsDir ? 0x0755 : 0x0644); + fi.fileType = bIsDir ? directory : regular; +#ifndef Q_OS_WIN + fi.uid = getuid(); + fi.gid = getgid(); + char name[256]; + struct passwd *p_ptr = nullptr; + struct passwd p; + getpwuid_r(fi.uid, &p, name, sizeof(name) - 1, &p_ptr); + if (p_ptr) + fi.uname = d->codec->toUnicode(p_ptr->pw_name); + struct group *g_ptr; + struct group g; + getgrgid_r(fi.gid, &g, name, sizeof(name) - 1, &g_ptr); + if (g_ptr) + fi.gname = d->codec->toUnicode(g_ptr->gr_name); +#endif + + QBuffer buf(const_cast(&data)); + if (!buf.open(QIODevice::ReadOnly)) + { + d->lastError = QLatin1String("Internal Error - can't open QBuffer for reading!"); + return false; + } + return addData(fi, &buf); +} + +bool TarFilter::addData(const FileInformations &fi, QIODevice *in) +{ + if (d->aborted) return false; + + if (!d->checkDevice(in, d->device)) + return false; + + if (!d->addHeader(fi)) + return false; + + if (fi.fileSize) + { + if (!d->copyData(in, d->device, fi.fileSize)) + return false; + + int align = fi.fileSize % 512; + if (align) + { + align = 512 - align; + QByteArray ba2(align, '\0'); + d->device->write(ba2.constData(), align); + } + } + return true; +} + +bool TarFilter::writeEOS() +{ + + const int size = sizeof(TarFilter::Private::tar_posix_header) * 2; + QByteArray ba(size, '\0'); + return (d->device->write(ba) == size); +} + +bool TarFilter::getData(FileInformations &fi) +{ + if (d->aborted) return false; + + d->nextChunkSize = -1; + if (!d->getHeader(fi)) + return false; + d->nextChunkSize = fi.fileSize; + return true; +} + +bool TarFilter::getData(QIODevice *out) +{ + if (d->aborted) return false; + + if (!d->checkDevice(d->device, out)) + return false; + + if (d->nextChunkSize < 0) + { + d->lastError = QLatin1String("No informations about next chunk size. Did you call getData(FileInformations &fi) before?"); + return false; + } + + if (!d->copyData(d->device, out, d->nextChunkSize)) + return false; + + int align = d->nextChunkSize % 512; + if (align) + d->device->read(512 - align); + + d->nextChunkSize = -1; + return true; +} + +bool TarFilter::getData(FileInformations &fi, QByteArray &data) +{ + if (!getData(fi)) + return false; + + QBuffer buf(&data); + buf.open(QIODevice::WriteOnly); + return getData(&buf); +} + +bool TarFilter::getData(FileInformations &fi, QIODevice *out) +{ + if (!getData(fi)) + return false; + + return getData(out); +} diff --git a/Z/src/nglcompression/nglcomp_tarfilter.h b/Z/src/nglcompression/nglcomp_tarfilter.h new file mode 100755 index 000000000..f4144dd26 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_tarfilter.h @@ -0,0 +1,82 @@ + + + + + +#ifndef TARFILTER_H +#define TARFILTER_H + +#include +#include +#include + +class QIODevice; +class QTextCodec; +class QByteArray; + + + +class TarFilter +{ +public: + Q_DISABLE_COPY(TarFilter) + + enum FileType + { + regular = '0', + regular2 = '\0', + link = '1', + reserved = '2', + charType = '3', + block = '4', + directory = '5', + fifo = '6', + reserved2 = '7', + gnu_longLink = 'K', + gnu_longname = 'L', + }; + struct FileInformations + { + QString fileName; + qint64 fileSize = 0; + int uid = 1000; + int gid = 100; + QString uname; + QString gname; + time_t mtime = -1; + FileType fileType = regular; + QFile::Permissions mode = QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther; + }; + + + + TarFilter(QIODevice *dev, QTextCodec *codec = nullptr, const std::function &readCallback = nullptr); + ~TarFilter(); + + void abort(); + void setLocaleCodec(QTextCodec *codec); + void setBufferSize(unsigned int size); + bool error() const; + QString lastError() const; + + + bool addData(const FileInformations &fi, QIODevice *in); + + bool addFile(const QString &filename, const QString &filenameInArchive = QString()); + bool addData(const QString &filename, const QByteArray &data = QByteArray(), bool bIsDir = false); + + bool writeEOS(); + + + bool getData(FileInformations &fi, QIODevice *out); + + bool getData(FileInformations &fi); + bool getData(QIODevice *out); + bool getData(FileInformations &fi, QByteArray &data); + +private: + class Private; + Private *const d; +}; + +#endif diff --git a/Z/src/nglcompression/nglcomp_test.cpp b/Z/src/nglcompression/nglcomp_test.cpp new file mode 100755 index 000000000..89e49736a --- /dev/null +++ b/Z/src/nglcompression/nglcomp_test.cpp @@ -0,0 +1,175 @@ + + +#include "nglcomp_test.h" + +#include "nglcomp_compress.h" + +#include + +#include +#include + +#include + + + +void nglcomp_test::initTestCase() +{ + m_tempDirIn.setAutoRemove(true); + m_tempDirOut.setAutoRemove(true); + QVERIFY(m_tempDirIn.isValid()); + QVERIFY(m_tempDirOut.isValid()); + QVERIFY(m_tf.open()); + m_tf.setAutoRemove(true); + + m_fileContent[QLatin1String("1.txt")] = "111111111111111111111111"; + m_fileContent[QLatin1String("sub1/s1.txt")] = "222222222222222222222222"; + m_fileContent[QLatin1String("sub1/sub11/s11.txt")] = "333333333333333333333333"; + m_fileContent[QLatin1String("sub1/sub12/s12.txt")] = "444444444444444444444444"; + m_fileContent[QLatin1String("sub2/2.txt")] = "555555555555555555555555"; +} + + +void nglcomp_test::testCompressFile() +{ + QDir dir; + const auto directories = { + QLatin1String("sub1"), + QLatin1String("sub1/sub11"), + QLatin1String("sub1/sub12"), + QLatin1String("sub2") + }; + for (const QLatin1String &directory : directories) + QVERIFY(dir.mkdir(subPathIn(directory))); + + for (auto it = m_fileContent.cbegin(); it != m_fileContent.cend(); ++it) + writeTestFile(it.key(), it.value()); + + NGL::Compress c; + c.compress(&m_tf, subPathIn(QString()), QLatin1String("out")); + QVERIFY(c.waitForFinished()); +} + + +void nglcomp_test::testCompressMemory() +{ + QBuffer f(&m_ba); + QVERIFY(f.open(QIODevice::WriteOnly)); + QVector fi1; + QVector fi2; + NGL::Compress::FileInformations fi; + + fi.inputFileName = QLatin1String("chris.txt"); + fi.fileData = QByteArray("dumdidum\n"); + fi2 += fi; + + fi.inputFileName = QLatin1String("blub/chris.txt"); + fi.fileData = QByteArray("dumdidum im Verzeichnis blub\n"); + fi2 += fi; + + fi.inputFileName = QLatin1String("blub/blub/chris2.txt"); + fi.fileData = QByteArray("dumdidum im Verzeichnis blub/blub\n"); + fi2 += fi; + + NGL::Compress c; + c.compress(&f, QString(), fi1, fi2, QLatin1String("blub")); + QVERIFY(c.waitForFinished()); + f.close(); +} + +void nglcomp_test::testUncompressMemory() +{ + QBuffer f(&m_ba); + QVERIFY(f.open(QIODevice::ReadOnly)); + NGL::Compress c; + c.uncompress(&f, subPathIn(QString())); + QVERIFY(c.waitForFinished()); + f.close(); + + QVERIFY(f.open(QIODevice::ReadOnly)); + c.uncompress(&f); + QVERIFY(c.waitForFinished()); + QVector fi1 = c.getMemFiles(); + QVERIFY(fi1.count() == 4); + f.close(); +} + +void nglcomp_test::testUncompressFile() +{ + NGL::Compress c; + m_tf.seek(0); + c.uncompress(&m_tf, subPathOut(QString())); + QVERIFY(c.waitForFinished()); + + for (auto it = m_fileContent.cbegin(); it != m_fileContent.cend(); ++it) + checkContent(it.key(), it.value()); +} + +void nglcomp_test::cleanupTestCase() +{ + m_tf.close(); + m_tempDirIn.remove(); + m_tempDirOut.remove(); +} + + + +void nglcomp_test::writeTestFile(const QString &fn, const QByteArray &content) const +{ + QFile f(subPathIn(fn)); + QVERIFY(f.open(QIODevice::WriteOnly)); + QVERIFY(f.write(content) == content.size()); + f.close(); +} + +void nglcomp_test::checkContent(const QString &fn, const QByteArray &content) const +{ + QFile f(subPathOut(QLatin1String("out/") + fn)); + QVERIFY(f.open(QIODevice::ReadOnly)); + QCOMPARE(f.readAll(), content); +} + +QString nglcomp_test::subPathIn(const QString &p) const +{ + return m_tempDirIn.path() + QLatin1Char('/') + p; +} + +QString nglcomp_test::subPathOut(const QString &p) const +{ + return m_tempDirOut.path() + QLatin1Char('/') + p; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + +int main(int argc, char *argv[]) +{ + NGLCoreApplication app(argc, argv); + + app.createLogger("nglcomp_test", "log4cxx_nglcomp_test.props"); + nglcomp_test tc; + return QTest::qExec(&tc, argc, argv); +} diff --git a/Z/src/nglcompression/nglcomp_test.h b/Z/src/nglcompression/nglcomp_test.h new file mode 100755 index 000000000..9272e0926 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_test.h @@ -0,0 +1,36 @@ + + +#pragma once + +#include +#include +#include +#include +#include + +class nglcomp_test : public QObject +{ + Q_OBJECT + +public: + nglcomp_test() = default; + +private Q_SLOTS: + void initTestCase(); + void testCompressFile(); + void testCompressMemory(); + void testUncompressFile(); + void testUncompressMemory(); + void cleanupTestCase(); +private: + void writeTestFile(const QString &fn, const QByteArray &content) const; + void checkContent(const QString &fn, const QByteArray &content) const; + QString subPathIn(const QString &p) const; + QString subPathOut(const QString &p) const; +private: + QHash m_fileContent; + QByteArray m_ba; + QTemporaryFile m_tf; + QTemporaryDir m_tempDirIn; + QTemporaryDir m_tempDirOut; +}; diff --git a/Z/src/ngldb/CMakeLists.txt b/Z/src/ngldb/CMakeLists.txt new file mode 100755 index 000000000..a6ae5d6c7 --- /dev/null +++ b/Z/src/ngldb/CMakeLists.txt @@ -0,0 +1,45 @@ +# NGLDB +FIND_PACKAGE(PostgreSQL REQUIRED) + +OPTION(ENABLE_DB_TRACING "Enable trace output for NGLDB library" OFF) +IF(ENABLE_DB_TRACING) + add_compile_definitions(NGLDB_ENABLE_TRACE) +ENDIF(ENABLE_DB_TRACING) + +# +# NGL Database Library +# +SET(ngldb_SRCS + dbcommon.h + dbconnection.cpp + dbconnection.h + db_service_handler.h + dbtransaction.cpp + dbtransaction.h + ngldb_export.h + ngldb_logger.cpp + ngldb_logger.h + nsqlquery.cpp + nsqlquery.h + sql_query_janitor.cpp + sql_query_janitor.h +) + +NGL_ADD_LIBRARY(AAR SV HLA WS ngldb SHARED ${ngldb_SRCS}) +NGL_TARGET_LINK_LIBRARIES(ngldb + PRIVATE + NGLLogger + nglsettings + ${PostgreSQL_LIBRARIES} + PUBLIC + Qt5::Core + Qt5::Sql +) +NGL_TARGET_INCLUDE_DIRECTORIES(ngldb + PRIVATE + ${PostgreSQL_INCLUDE_DIR} + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +NGL_INSTALL_TARGET(ngldb) diff --git a/Z/src/ngldb/db_service_handler.h b/Z/src/ngldb/db_service_handler.h new file mode 100755 index 000000000..c4d64b774 --- /dev/null +++ b/Z/src/ngldb/db_service_handler.h @@ -0,0 +1,58 @@ + + +#pragma once + +#include +#include + +class QSqlDatabase; +namespace NGLDB +{ +template +class DbServiceHandler +{ +public: + DbServiceHandler() = default; + ~DbServiceHandler() = default; + + + bool init(int exerciseId, NGL::Settings *settings) + { + if (m_dbInterface) + return true; + + m_dbInterface = DB::create(exerciseId); + + if (!m_dbInterface->init(m_dbInterface->dbUser(), + settings->databasePassword(m_dbInterface->dbUser()), + settings->databaseDriver(), + settings->databaseHostname(), + settings->databaseName())) + { + m_dbInterface = nullptr; + return false; + } + return true; + } + + bool init(int exerciseId, const QSqlDatabase &db) + { + if (m_dbInterface) + return true; + + m_dbInterface = DB::create(exerciseId); + + if (!m_dbInterface->init(db)) + { + m_dbInterface = nullptr; + return false; + } + return true; + } + + std::shared_ptr db() const { return m_dbInterface; } + +private: + std::shared_ptr m_dbInterface; +}; +} diff --git a/Z/src/ngldb/dbcommon.h b/Z/src/ngldb/dbcommon.h new file mode 100755 index 000000000..b4804145d --- /dev/null +++ b/Z/src/ngldb/dbcommon.h @@ -0,0 +1,41 @@ + + + +#pragma once + +#include "ngldb_export.h" +#include + + + +namespace DBCommon +{ + +enum class eDatabaseSchema +{ + Exercise +}; + + + +inline QString getExerciseSchemaName(int exerciseId) +{ + return QLatin1String("ex_") + QString::number(exerciseId); +} + + + +inline QString getTableName(const QString &tableName, const QString &schemaName) +{ + if (schemaName.isEmpty()) + return tableName; + return schemaName + QLatin1Char('.') + tableName; +} + + + +inline QString getExerciseTableName(const QString &tableName, int exerciseId) +{ + return getTableName(tableName, getExerciseSchemaName(exerciseId)); +} +} diff --git a/Z/src/ngldb/dbconnection.cpp b/Z/src/ngldb/dbconnection.cpp new file mode 100755 index 000000000..843628e54 --- /dev/null +++ b/Z/src/ngldb/dbconnection.cpp @@ -0,0 +1,68 @@ + + +#include "dbconnection.h" + +#include +#include +#include + +#include "nsqlquery.h" + +namespace DBConnection +{ + +QSqlDatabase open(NGL::INGLLogger &logger, + const QString &dbUser, + const QString &dbPasswd, + const QString &dbDriver, + const QString &dbHost, + const QString &dbName, + const QString &schemaName, + const QString &connectionName) +{ + + + + DEBUG_LOG(logger) << "host: " << dbHost << " database: " << dbName; + QString realConnectionName(connectionName); + if (connectionName.isEmpty()) + { + realConnectionName = dbHost + QLatin1Char('_') + dbName; + if (!schemaName.isEmpty()) + realConnectionName += QLatin1Char('_') + schemaName; + } + + auto dbConnection = QSqlDatabase::addDatabase(dbDriver, realConnectionName); + dbConnection.setHostName(dbHost); + dbConnection.setDatabaseName(dbName); + dbConnection.setUserName(dbUser); + dbConnection.setPassword(dbPasswd); + + if (!dbConnection.open()) + { + const QString err = dbConnection.lastError().nativeErrorCode(); + FATAL_LOG(logger) << "Error opening database " << dbHost + << ":" << dbName << " as user " << dbUser; + FATAL_LOG(logger) << dbConnection.lastError().driverText() << " " + << dbConnection.lastError().databaseText() << " " << err; + return dbConnection; + } + + DEBUG_LOG(logger) << "Database Initialisation successful -> DB: " << dbName << ", con: " << realConnectionName; + + if (!schemaName.isEmpty()) + { + const QString stmt = QLatin1String("SET SEARCH_PATH TO ") + schemaName + QLatin1String(", PUBLIC"); + + NSqlQuery q(dbConnection); + if (!q.exec(stmt)) + { + ERROR_LOG(logger) << "Set SEARCH_PATH to " << schemaName << " failed!"; + dbConnection.close(); + } + } + + return dbConnection; +} + +} diff --git a/Z/src/ngldb/dbconnection.h b/Z/src/ngldb/dbconnection.h new file mode 100755 index 000000000..612caf361 --- /dev/null +++ b/Z/src/ngldb/dbconnection.h @@ -0,0 +1,24 @@ + + +#pragma once + +#include + +#include "ngldb_export.h" + +namespace NGL +{ +class INGLLogger; +} + +namespace DBConnection +{ +NGLDB_EXPORT QSqlDatabase open(NGL::INGLLogger &logger, + const QString &dbUser, + const QString &dbPasswd, + const QString &dbDriver, + const QString &dbHost, + const QString &dbName, + const QString &schemaName = QString(), + const QString &connectionName = QString()); +} diff --git a/Z/src/ngldb/dbtransaction.cpp b/Z/src/ngldb/dbtransaction.cpp new file mode 100755 index 000000000..a7cfe825d --- /dev/null +++ b/Z/src/ngldb/dbtransaction.cpp @@ -0,0 +1,82 @@ + + + +#include "dbtransaction.h" +#include "ngldb_logger.h" +#include + +thread_local int s_refCounter = 0; + +DBTransaction::DBTransaction(const QSqlDatabase &db) + : m_db(db) + , m_bCommitted(true) + , mLogger(NGLDB::getLogger("DBTransaction")) +{ + ++s_refCounter; + if (s_refCounter == 1) + begin(); +} + +DBTransaction::~DBTransaction() +{ + if (s_refCounter == 1) + { + if (!m_bCommitted) + rollback(); + } + --s_refCounter; +} + +bool DBTransaction::begin() +{ + if (!m_bCommitted) + return setState(false); + if (!m_db.transaction()) + { + ERROR_LOG(mLogger) << "Error starting a transaction: " << m_db.lastError().driverText(); + return setState(false); + } + m_bCommitted = false; + return setState(true); +} + +bool DBTransaction::commit() +{ + if (s_refCounter == 1) + { + if (!m_db.commit()) + { + ERROR_LOG(mLogger) << "Error committing a transaction: " << m_db.lastError().driverText(); + return setState(false); + } + m_bCommitted = true; + return setState(true); + } + return true; +} + +bool DBTransaction::rollback() +{ + if (s_refCounter == 1) + { + if (!m_db.rollback()) + { + ERROR_LOG(mLogger) << "Error rolling back a transaction" << m_db.lastError().driverText(); + return setState(false); + } + m_bCommitted = true; + return setState(true); + } + return true; +} + +bool DBTransaction::state() const +{ + return m_lastState; +} + +bool DBTransaction::setState(bool bState) +{ + m_lastState = bState; + return m_lastState; +} diff --git a/Z/src/ngldb/dbtransaction.h b/Z/src/ngldb/dbtransaction.h new file mode 100755 index 000000000..2803a06a5 --- /dev/null +++ b/Z/src/ngldb/dbtransaction.h @@ -0,0 +1,48 @@ + + +#pragma once + +#include + +#include "ngldb_export.h" + +namespace NGL +{ +class INGLLogger; +} + + +class NGLDB_EXPORT DBTransaction +{ +public: + + + explicit DBTransaction(const QSqlDatabase &db); + + + + ~DBTransaction(); + + + + bool begin(); + + + bool commit(); + + + bool rollback(); + + + bool state() const; + +private: + bool setState(bool bState); + + QSqlDatabase m_db; + bool m_bCommitted; + bool m_lastState; + NGL::INGLLogger &mLogger; +}; + + diff --git a/Z/src/ngldb/ngldb_export.h b/Z/src/ngldb/ngldb_export.h new file mode 100755 index 000000000..eecef03c2 --- /dev/null +++ b/Z/src/ngldb/ngldb_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLDB_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLDB_EXPORT +# else +# if defined(MAKE_NGLDB_LIB) +# define NGLDB_EXPORT Q_DECL_EXPORT +# else +# define NGLDB_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/ngldb/ngldb_logger.cpp b/Z/src/ngldb/ngldb_logger.cpp new file mode 100755 index 000000000..d7f1342ea --- /dev/null +++ b/Z/src/ngldb/ngldb_logger.cpp @@ -0,0 +1,24 @@ + + + +#include "ngldb_logger.h" +#include + +NGLDB::LOGGER_T NGLDB::getLogger(const char *name) +{ + static const char ns[] = "NGLDB."; + std::string loggerName; + const size_t len = strlen(name); + loggerName.reserve(sizeof(ns) + len); + loggerName.append(ns, sizeof(ns) - 1); + loggerName.append(name, len); + + try { + return NGL::NGLLoggerBootstrap::getNGLRootLogger(). + getNGLLogger( loggerName ); + } catch ( const std::exception &ex ) + { + fprintf(stderr, "Error retrieving logger: %s", ex.what()); + abort(); + } +} diff --git a/Z/src/ngldb/ngldb_logger.h b/Z/src/ngldb/ngldb_logger.h new file mode 100755 index 000000000..7326f9a16 --- /dev/null +++ b/Z/src/ngldb/ngldb_logger.h @@ -0,0 +1,31 @@ + + + +#pragma once + +#include + +#ifdef Q_CC_GNU +#define DB_TRACE_FUNCTION __PRETTY_FUNCTION__ +#else +#define DB_TRACE_FUNCTION __FUNCTION__ +#endif + +#ifdef NGLDB_ENABLE_TRACE +#define DB_TRACE { TRACE_LOG(mLogger) << DB_TRACE_FUNCTION } +#define DB_TRACE2(x) { TRACE_LOG(mLogger) << DB_TRACE_FUNCTION << x } +#else +#define DB_TRACE +#define DB_TRACE2(x) +#endif + +namespace NGLDB +{ +typedef NGL::INGLLogger &LOGGER_T; + +LOGGER_T getLogger(const char *name); +inline LOGGER_T getLogger(const QString &loggerName) +{ + return getLogger(loggerName.toUtf8().constData()); +} +} diff --git a/Z/src/ngldb/nsqlquery.cpp b/Z/src/ngldb/nsqlquery.cpp new file mode 100755 index 000000000..261401068 --- /dev/null +++ b/Z/src/ngldb/nsqlquery.cpp @@ -0,0 +1,457 @@ + + +#include "nsqlquery.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngldb_logger.h" +#include + +static QString getSqlErrorString(const QSqlError &error) +{ + return error.driverText() + QLatin1Char(' ') + + error.databaseText() + QLatin1Char(' ') + + error.nativeErrorCode(); +} + +NSqlQuery::NSqlQuery(const QSqlDatabase &db) + : QSqlQuery(db) + , m_db(db) + , mLogger(NGLDB::getLogger("NSqlQuery")) +{ + DB_TRACE + setForwardOnly(true); +} + +NSqlQuery::NSqlQuery(const QSqlDatabase &db, NGL::INGLLogger &logger) + : QSqlQuery(db) + , m_db(db) + , mLogger(logger) +{ + DB_TRACE + setForwardOnly(true); +} + +NSqlQuery::NSqlQuery(const QString &query, const QSqlDatabase &db) + : QSqlQuery(query, db) + , m_db(db) + , mLogger(NGLDB::getLogger("NSqlQuery")) +{ + DB_TRACE + setForwardOnly(true); +} + +NSqlQuery::NSqlQuery(const QString &query, const QSqlDatabase &db, NGL::INGLLogger &logger) + : QSqlQuery(query, db) + , m_db(db) + , mLogger(logger) +{ + DB_TRACE + setForwardOnly(true); +} + +void NSqlQuery::addBindValue(const QVariant &val, QSql::ParamType paramType) +{ + DB_TRACE; + DEBUG_LOG(mLogger) << "type: " << val.type() << " paramType: " << paramType; + QSqlQuery::addBindValue(val, paramType); +} + +int NSqlQuery::at() const +{ + DB_TRACE + return QSqlQuery::at(); +} + +void NSqlQuery::bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType) +{ + DB_TRACE; + TRACE_LOG(mLogger) << "placeholder: " << placeholder << " type: " << val.type() << " paramType: " << paramType; + QSqlQuery::bindValue(placeholder, val, paramType); +} + +void NSqlQuery::bindValue(int pos, const QVariant &val, QSql::ParamType paramType) +{ + DB_TRACE; + TRACE_LOG(mLogger) << "pos: " << pos << " type: " << val.type() << " paramType: " << paramType; + QSqlQuery::bindValue(pos, val, paramType); +} + +QVariant NSqlQuery::boundValue(const QString &placeholder) const +{ + DB_TRACE + TRACE_LOG(mLogger) << "placeholder: " << placeholder; + return QSqlQuery::boundValue(placeholder); +} + +QVariant NSqlQuery::boundValue(int pos) const +{ + DB_TRACE + TRACE_LOG(mLogger) << "pos: " << pos; + return QSqlQuery::boundValue(pos); +} + +QMap NSqlQuery::boundValues() const +{ + DB_TRACE + return QSqlQuery::boundValues(); +} + +void NSqlQuery::clear() +{ + DB_TRACE + return QSqlQuery::clear(); +} + +const QSqlDriver *NSqlQuery::driver() const +{ + DB_TRACE + return QSqlQuery::driver(); +} + +bool NSqlQuery::exec(const QString &query, bool bEmitMessageOnError) +{ + DB_TRACE; + DEBUG_LOG(mLogger) << "query: " << query; + if (QSqlQuery::exec(query)) + return true; + if (bEmitMessageOnError) + printLastSqlError(); + return false; +} + +bool NSqlQuery::exec(bool bEmitMessageOnError) +{ + DB_TRACE + DEBUG_LOG(mLogger) << "query: " << lastQuery(); + + if (mLogger.isDebugEnabled()) + { + const QMap &boundValuesMap = boundValues(); + for (auto it=boundValuesMap.begin(); it != boundValuesMap.end(); ++it) + { + if ( it.value().canConvert()) + DEBUG_LOG(mLogger) << "key='" << it.key() << "' value='" << it.value().toString() << "'"; + else + DEBUG_LOG(mLogger) << "key='" << it.key() << "' value cant Convert to string'"; + } + } + if (QSqlQuery::exec()) + return true; + if (bEmitMessageOnError) + printLastSqlError(); + return false; +} + +bool NSqlQuery::execAndFetch() +{ + DB_TRACE + if (!exec()) + return false; + return (next()); +} + +bool NSqlQuery::execAndFetch(const QString &query) +{ + DB_TRACE + if (!exec(query)) + return false; + return (next()); +} + +bool NSqlQuery::execBatch(BatchExecutionMode mode) +{ + DB_TRACE2("mode: " << mode) + DEBUG_LOG(mLogger) << "mode: " << mode; + if (QSqlQuery::execBatch(mode)) + return true; + printLastSqlError(); + return false; +} + +QString NSqlQuery::executedQuery() const +{ + DB_TRACE + return QSqlQuery::executedQuery(); +} + +void NSqlQuery::finish() +{ + DB_TRACE + QSqlQuery::finish(); +} + +bool NSqlQuery::first() +{ + DB_TRACE + if (QSqlQuery::first()) + return true; + printLastSqlError(); + return false; +} + +bool NSqlQuery::isActive() const +{ + DB_TRACE + return QSqlQuery::isActive(); +} + +bool NSqlQuery::isForwardOnly() const +{ + DB_TRACE + return QSqlQuery::isForwardOnly(); +} + +bool NSqlQuery::isNull(int field) const +{ + DB_TRACE2("field: " << field) + return QSqlQuery::isNull(field); +} + +bool NSqlQuery::isSelect() const +{ + DB_TRACE + return QSqlQuery::isSelect(); +} + +bool NSqlQuery::isValid() const +{ + DB_TRACE + return QSqlQuery::isValid(); +} + +bool NSqlQuery::last() +{ + DB_TRACE + if (QSqlQuery::last()) + return true; + printLastSqlError(); + return false; +} + +QSqlError NSqlQuery::lastError() const +{ + DB_TRACE + return QSqlQuery::lastError(); +} + +QString NSqlQuery::sqlstate() +{ + const QVariant resultHandle = this->result()->handle(); + + + + + if (resultHandle.isValid() && (qstrcmp(resultHandle.typeName(), "PGresult*") == 0)) + { + + const PGresult *pgresHandle = *static_cast(resultHandle.data()); + + if (pgresHandle != nullptr) + { + + return QString::fromLocal8Bit(PQresultErrorField(pgresHandle, PG_DIAG_SQLSTATE)); + } + } + + + return QStringLiteral("58000"); +} + +QVariant NSqlQuery::lastInsertId() +{ + DB_TRACE + + QVariant ret; + + if (this->driver()->hasFeature(QSqlDriver::LastInsertId)) + ret = QSqlQuery::lastInsertId(); + + if (!ret.isValid()) + { + NSqlQuery q(m_db); + if (q.execAndFetch(QLatin1String("SELECT LASTVAL()"))) + ret = q.value(0); + } + return ret; +} + +QString NSqlQuery::lastQuery() const +{ + DB_TRACE + return QSqlQuery::lastQuery(); +} + +bool NSqlQuery::next() +{ + DB_TRACE + return QSqlQuery::next(); +} + +bool NSqlQuery::nextResult() +{ + DB_TRACE + if (QSqlQuery::nextResult()) + return true; + printLastSqlError(); + return false; +} + +int NSqlQuery::numRowsAffected() const +{ + DB_TRACE + return QSqlQuery::numRowsAffected(); +} + +QSql::NumericalPrecisionPolicy NSqlQuery::numericalPrecisionPolicy() const +{ + DB_TRACE + return QSqlQuery::numericalPrecisionPolicy(); +} + +bool NSqlQuery::prepare(const QString &query) +{ + DB_TRACE2("query: " << query) + if (QSqlQuery::prepare(query)) + return true; + printLastSqlError(); + return false; +} + +bool NSqlQuery::previous() +{ + DB_TRACE + if (QSqlQuery::previous()) + return true; + printLastSqlError(); + return false; +} + +QSqlRecord NSqlQuery::record() const +{ + DB_TRACE + return QSqlQuery::record(); +} + +const QSqlResult *NSqlQuery::result() const +{ + DB_TRACE + return QSqlQuery::result(); +} + +bool NSqlQuery::seek(int index, bool relative) +{ + DB_TRACE2("index: " << index << " relative: " << relative); + if (QSqlQuery::seek(index, relative)) + return true; + printLastSqlError(); + return false; +} + +void NSqlQuery::setForwardOnly(bool forward) +{ + DB_TRACE2("forward: " << forward); + QSqlQuery::setForwardOnly(forward); +} + +void NSqlQuery::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy) +{ + DB_TRACE2("precisionPolicy: " << precisionPolicy); + QSqlQuery::setNumericalPrecisionPolicy(precisionPolicy); +} + +int NSqlQuery::size() const +{ + DB_TRACE + return QSqlQuery::size(); +} + +QVariant NSqlQuery::value(int index) const +{ + DB_TRACE2("index: " << index) + return QSqlQuery::value(index); +} + +NSqlQuery &NSqlQuery::operator= (const NSqlQuery &other) +{ + DB_TRACE + QSqlQuery::operator= (other); + return *this; +} + +bool NSqlQuery::export2CSV(const QString &filename) +{ + DB_TRACE2("export csv to file: " << filename) + QFile data(filename); + QTextStream output(&data); + if (data.open(QFile::WriteOnly | QFile::Truncate)) + { + if (isSelect() && isActive()) + { + bool isHeaderWritten = false; + while (next()) + { + QSqlRecord rec = record(); + if (!isHeaderWritten) + { + for (int i = 0; i < rec.count(); ++i) + output << QLatin1Char('\"') + rec.fieldName(i) + QLatin1String("\","); + output << QLatin1Char('\n'); + isHeaderWritten = true; + } + for (int i = 0; i < rec.count(); ++i) + output << QLatin1Char('\"') + rec.value(i).toString() + QLatin1String("\","); + output << QLatin1Char('\n'); + } + } + data.close(); + return true; + } + return false; +} + +QVariant NSqlQuery::qDateTimeToQVariant(const QDateTime &dt) +{ + if (dt.isValid()) + return dt.toMSecsSinceEpoch(); + return QVariant(); +} + +QDateTime NSqlQuery::qVariantToQDateTime(const QVariant &var) +{ + if (var.isNull()) + return QDateTime(); + return QDateTime::fromMSecsSinceEpoch(var.toLongLong()); +} + +QString NSqlQuery::qVariantToJsonString(const QVariant &value) +{ + if (value.isNull()) + return QStringLiteral("{}"); + return value.toString(); +} + +QString NSqlQuery::jsonValueToJsonString(const QJsonValue &value) +{ + if (value.isNull()) + return QStringLiteral("{}"); + return value.toString(); +} + +void NSqlQuery::printLastSqlError() +{ + ERROR_LOG(mLogger) << getSqlErrorString(lastError()) << " " << lastQuery(); +} + +QString NSqlQuery::getLastSqlError() +{ + return (getSqlErrorString(lastError()) + QLatin1Char(' ') + lastQuery()); +} diff --git a/Z/src/ngldb/nsqlquery.h b/Z/src/ngldb/nsqlquery.h new file mode 100755 index 000000000..a813283e4 --- /dev/null +++ b/Z/src/ngldb/nsqlquery.h @@ -0,0 +1,222 @@ + + + +#pragma once + +#include + +#include "ngldb_export.h" +#include "dbcommon.h" + +namespace NGL +{ +class INGLLogger; +} +class QDateTime; +class QJsonValue; + + + +class NGLDB_EXPORT NSqlQuery final : public QSqlQuery +{ +public: + + + explicit NSqlQuery(const QSqlDatabase &db); + explicit NSqlQuery(const QSqlDatabase &db, NGL::INGLLogger &logger); + explicit NSqlQuery(const QString &query, const QSqlDatabase &db); + explicit NSqlQuery(const QString &query, const QSqlDatabase &db, NGL::INGLLogger &logger); + + + + NSqlQuery(const NSqlQuery &other) = default; + + + + ~NSqlQuery() = default; + + + + void addBindValue(const QVariant &val, QSql::ParamType paramType = QSql::In); + + + + int at() const; + + + + void bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType = QSql::In); + + + + void bindValue(int pos, const QVariant &val, QSql::ParamType paramType = QSql::In); + + + + QVariant boundValue(const QString &placeholder) const; + + + + QVariant boundValue(int pos) const; + + + + QMap boundValues() const; + + + + void clear(); + + + + const QSqlDriver *driver() const; + + + + bool exec(const QString &query, bool bEmitMessageOnError = true); + + + + bool exec(bool bEmitMessageOnError = true); + + + + bool execAndFetch(); + + + + bool execAndFetch(const QString &query); + + + + bool execBatch(BatchExecutionMode mode = ValuesAsRows); + + + + QString executedQuery() const; + + + + void finish(); + + + + bool first(); + + + + bool isActive() const; + + + + bool isForwardOnly() const; + + + + bool isNull(int field) const; + + + + bool isSelect() const; + + + + bool isValid() const; + + + + bool last(); + + + + QSqlError lastError() const; + + QString sqlstate(); + + + QVariant lastInsertId(); + + + + QString lastQuery() const; + + + + bool next(); + + + + bool nextResult(); + + + + int numRowsAffected() const; + + + + QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const; + + + + bool prepare(const QString &query); + + + + bool previous(); + + + + QSqlRecord record() const; + + + + const QSqlResult *result() const; + + + + bool seek(int index, bool relative = false); + + + + void setForwardOnly(bool forward); + + + + void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy); + + + + int size() const; + + + + QVariant value(int index) const; + + + + NSqlQuery &operator= (const NSqlQuery &other); + + bool export2CSV(const QString &filename); + + + + static QVariant qDateTimeToQVariant(const QDateTime &dt); + + + static QDateTime qVariantToQDateTime(const QVariant &var); + + + static QString qVariantToJsonString(const QVariant &value); + + + static QString jsonValueToJsonString(const QJsonValue &value); + + static inline QString fixupEmptyJsonString(const QString &str) { return str.isEmpty() ? QLatin1String("{}") : str; } + + QString getLastSqlError(); + +private: + void printLastSqlError(); + QSqlDatabase m_db; + NGL::INGLLogger &mLogger; +}; diff --git a/Z/src/ngldb/sql_query_janitor.cpp b/Z/src/ngldb/sql_query_janitor.cpp new file mode 100755 index 000000000..8c15015cb --- /dev/null +++ b/Z/src/ngldb/sql_query_janitor.cpp @@ -0,0 +1,24 @@ + + + +#include "sql_query_janitor.h" +#include "nsqlquery.h" +#include + + +SqlQueryJanitor::SqlQueryJanitor(NSqlQuery *query) + : m_query(query) +{ + Q_ASSERT(m_query); + Q_ASSERT(!m_query->isActive()); +} + +SqlQueryJanitor::SqlQueryJanitor(const std::unique_ptr &query) + : SqlQueryJanitor(query.get()) +{ +} + +SqlQueryJanitor::~SqlQueryJanitor() +{ + m_query->finish(); +} diff --git a/Z/src/ngldb/sql_query_janitor.h b/Z/src/ngldb/sql_query_janitor.h new file mode 100755 index 000000000..f26e4bcf2 --- /dev/null +++ b/Z/src/ngldb/sql_query_janitor.h @@ -0,0 +1,22 @@ + + + +#pragma once + +#include "ngldb_export.h" +#include + +class NSqlQuery; + + + +class NGLDB_EXPORT SqlQueryJanitor +{ +public: + explicit SqlQueryJanitor(NSqlQuery *query); + explicit SqlQueryJanitor(const std::unique_ptr &query); + ~SqlQueryJanitor(); + +private: + NSqlQuery *m_query; +}; diff --git a/Z/src/nglsettings/CMakeLists.txt b/Z/src/nglsettings/CMakeLists.txt new file mode 100755 index 000000000..6a234d4f7 --- /dev/null +++ b/Z/src/nglsettings/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# CMake Script für nglsettings +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(nglsettings_SRCS + nglsettings_connections.cpp + nglsettings_settings.cpp +) + +SET(nglsettings_HDRS + nglsettings_connections.h + nglsettings_export.h + nglsettings_settings.h +) + +NGL_ADD_LIBRARY(ALL nglsettings SHARED ${nglsettings_SRCS} ${nglsettings_HDRS}) +NGL_TARGET_LINK_LIBRARIES(nglsettings + PRIVATE + ngltools + Qt5::Network + PUBLIC + Qt5::Core +) + +NGL_TARGET_INCLUDE_DIRECTORIES(nglsettings + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_INSTALL_TARGET(nglsettings) diff --git a/Z/src/nglsettings/nglsettings_connections.cpp b/Z/src/nglsettings/nglsettings_connections.cpp new file mode 100755 index 000000000..1ac078cc0 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_connections.cpp @@ -0,0 +1,175 @@ + + +#include "nglsettings_connections.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace NGL +{ +namespace Connections +{ +enum class eHostConfig +{ + public_local, + localhost, + server, + server_avs +}; +struct configStruct +{ + eHostConfig host; + unsigned short port; + QString name; +}; + +static QMap *s_config = nullptr; +static QSettings *s_settings = nullptr; +static unsigned short s_portOffset = 9000; +static QString *s_serverHostname = nullptr; + +static void cleanupSettings() +{ + delete s_settings; + s_settings = nullptr; + delete s_serverHostname; + s_serverHostname = nullptr; + delete s_config; + s_config = nullptr; +} + +static void insertConfig(eConnection conn, eHostConfig host, unsigned short port, const char *name) +{ + if (!s_config) + s_config = new QMap(); + configStruct s; + s.host = host; + s.port = port; + s.name = QString::fromLatin1(name); + s_config->insert(conn, s); +} + +static void initConfig() +{ + if (s_config && !s_config->isEmpty()) + return; + + insertConfig(eConnection::AVS_WORKSTATION, eHostConfig::localhost, 6370, "AVS_WORKSTATION"); + insertConfig(eConnection::AVS_WORKSTATION_VD, eHostConfig::localhost, 6380, "AVS_WORKSTATION_VD"); + insertConfig(eConnection::AVS_ROOT, eHostConfig::server_avs, 6350, "AVS_ROOT"); + insertConfig(eConnection::AVS_FM, eHostConfig::server_avs, 6360, "AVS_FM"); + insertConfig(eConnection::AVS_MOTION_RECORDER, eHostConfig::server_avs, 6390, "AVS_MOTION_RECORDER"); + insertConfig(eConnection::AVS_AVA, eHostConfig::server_avs, 6391, "AVS_AVA"); + + insertConfig(eConnection::PWS_WEBSOCKET, eHostConfig::server, 5701, "PWS_WEBSOCKET"); + insertConfig(eConnection::SCM_WEBSOCKET, eHostConfig::server, 7300, "SCM_WEBSOCKET"); + insertConfig(eConnection::ISM_WEBSOCKET, eHostConfig::server, 2080, "ISM_WEBSOCKET"); + insertConfig(eConnection::FLM_THP_SERVER, eHostConfig::server, 2090, "FLM_THP_SERVER"); + insertConfig(eConnection::FLM_PDF_SERVER, eHostConfig::server, 3000, "FLM_PDF_SERVER"); + + insertConfig(eConnection::LVS, eHostConfig::server, 94, "LVS"); + insertConfig(eConnection::ZWLVSV, eHostConfig::server, 95, "ZWLVSV"); + insertConfig(eConnection::ZWLVWCS, eHostConfig::server, 97, "ZWLVWCS"); + insertConfig(eConnection::ZWLVWMS, eHostConfig::server, 98, "ZWLVWMS"); + insertConfig(eConnection::ZSLV, eHostConfig::server, 99, "ZSLV"); +} + +void setIniFile(const QString &iniFileName) +{ + if (!s_settings) + qAddPostRoutine(cleanupSettings); + delete s_settings; + s_settings = new QSettings(iniFileName, QSettings::IniFormat); +} + +QString iniFile() +{ + return s_settings ? s_settings->fileName() : QString(); +} + +unsigned short portOffset() +{ + return s_portOffset; +} + +void setPortOffset(unsigned short portOffset) +{ + s_portOffset = portOffset; +} + +unsigned short port(eConnection connection) +{ + initConfig(); + unsigned short port = s_config->value(connection).port; + + if (s_settings) + { + bool bOk; + QString key = s_config->value(connection).name + QLatin1String("/port"); + unsigned short port2 = s_settings->value(key, port).toString().toUShort(&bOk); + if (bOk) + port = port2; + } + if (port < 100) + return portOffset() + port; + return port; +} + +QString hostName(eConnection connection) +{ + initConfig(); + + QString host; + switch (s_config->value(connection).host) + { + case eHostConfig::public_local: + host = QString::fromLocal8Bit(qgetenv("HOST")); + break; + case eHostConfig::localhost: + host = QLatin1String("127.0.0.1"); + break; + case eHostConfig::server: + if (s_serverHostname) + host = *s_serverHostname; + if (host.isEmpty()) + host = QLatin1String("EXCTDS01"); + break; + case eHostConfig::server_avs: + host = QStringLiteral("EXCAVS01"); + break; + } + if (s_settings) + { + QString key = s_config->value(connection).name + QLatin1String("/host"); + QString host2 = s_settings->value(key, host).toString(); + if (!host2.isEmpty()) + host = host2; + } + return host; +} + +void setServerHostname(const QString &serverHostName) +{ + if (!s_serverHostname) + s_serverHostname = new QString(serverHostName); + else + *s_serverHostname = serverHostName; +} + +QString connectionName(eConnection connection) +{ + if (s_config) + { + auto it = s_config->constFind(connection); + if (it != s_config->constEnd()) + return it.value().name; + } + return QString::number((int)connection); +} +} +} diff --git a/Z/src/nglsettings/nglsettings_connections.h b/Z/src/nglsettings/nglsettings_connections.h new file mode 100755 index 000000000..205e4a9c3 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_connections.h @@ -0,0 +1,59 @@ + + +#pragma once + +#include +#include "nglsettings_export.h" + +namespace NGL +{ + + +namespace Connections +{ + + +enum class eConnection +{ + UNKNOWN = 0, + AVS_WORKSTATION, + AVS_WORKSTATION_VD, + AVS_ROOT, + AVS_FM, + AVS_MOTION_RECORDER, + AVS_AVA, + ZWLVSV, + ZSLV, + ZWLVWCS, + ZWLVWMS, + PWS_WEBSOCKET, + SCM_WEBSOCKET, + ISM_WEBSOCKET, + FLM_THP_SERVER, + FLM_PDF_SERVER, + LVS , +}; + + + +NGLSETTINGS_EXPORT void setIniFile(const QString &iniFileName); + + +NGLSETTINGS_EXPORT QString iniFile(); + + + +NGLSETTINGS_EXPORT unsigned short portOffset(); +void setPortOffset(unsigned short portOffset); + + +NGLSETTINGS_EXPORT unsigned short port(eConnection connection); + + +NGLSETTINGS_EXPORT QString hostName(eConnection connection); +void setServerHostname(const QString &serverHostName); + + +NGLSETTINGS_EXPORT QString connectionName(eConnection connection); +} +} diff --git a/Z/src/nglsettings/nglsettings_export.h b/Z/src/nglsettings/nglsettings_export.h new file mode 100755 index 000000000..0da7e5511 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLSETTINGS_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLSETTINGS_EXPORT +# else +# ifdef MAKE_NGLSETTINGS_LIB +# define NGLSETTINGS_EXPORT Q_DECL_EXPORT +# else +# define NGLSETTINGS_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/nglsettings/nglsettings_settings.cpp b/Z/src/nglsettings/nglsettings_settings.cpp new file mode 100755 index 000000000..b795651f1 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_settings.cpp @@ -0,0 +1,320 @@ + + +#include "nglsettings_settings.h" +#include "nglsettings_connections.h" + +#include + +#include +#include +#include +#include +#include + +namespace NGL +{ + QSettings *Settings::s_globalSettings = nullptr; + + Settings::Settings(const QString &iniFile_) + : m_settings(nullptr) + { + QString iniFile = iniFile_; + if(iniFile == QLatin1String("gfs_ws.ini")) { + const QByteArray defUser = qgetenv("USER"); + if( defUser == "ctc_aar" || defUser == "ctc_rbf" ) { + QByteArray home = qgetenv("HOME"); + if(!home.isEmpty()) { + QString fn = QString::fromLocal8Bit(home) + + QLatin1String("/gfs_") + + QString::fromLocal8Bit(defUser.mid(4)) + + QLatin1String(".ini"); + QFileInfo fi(fn); + if(fi.exists() && fi.isFile() && fi.isReadable()) { + iniFile = fn; + } + } + } + } + + initializeGlobalSettings(); + + initPre(); + if(!iniFile.isEmpty()) { + if(QFileInfo(iniFile).isAbsolute()) + m_settings = new QSettings(iniFile, QSettings::IniFormat); + else + m_settings = new QSettings(basePath() + iniFile, QSettings::IniFormat); + initPost(); + } + + if (!m_settings) + m_settings = new QSettings(QLatin1String("RDE")); + } + + Settings::Settings(const QString &organization, const QString &application) + : m_settings(new QSettings(organization, application)) + { + initPre(); + initPost(); + } + + Settings::~Settings() + { + delete m_settings; + } + + void Settings::initializeGlobalSettings() + { + if (s_globalSettings) + return; + + if (!s_globalSettings) + { + QString globalSettingsFile = NGL::findProjectConfigFile(); + + + if (!globalSettingsFile.isEmpty()) + s_globalSettings = new QSettings(globalSettingsFile, QSettings::IniFormat); + } + if (!s_globalSettings) + s_globalSettings = new QSettings(QLatin1String("RDE"), QLatin1String("LTS-CC")); + Connections::setPortOffset(portOffset()); + Connections::setServerHostname(serverHostname()); + } + + QString Settings::globalSectionName() + { + QString secName = QLatin1String("Global"); + static const char envGlobSecName[] = "LTS_CONF_GLOBAL_SECTION_NAME"; + if (qEnvironmentVariableIsSet(envGlobSecName)) + secName = QString::fromLocal8Bit(qgetenv(envGlobSecName)); + + return secName; + } + + QString Settings::basePath() const + { + return m_paths["GFS_PATH"]; + } + + QString Settings::tempPath() const + { + return m_paths["TMP_PATH"]; + } + + QString Settings::printPath() + { + return getDirectory("PDF", tempPath()); + } + + QString Settings::logoProject() + { + return QLatin1String(":project/logo.png"); + } + + QString Settings::bitmapPath() + { + return getDirectory("BITMAPS", basePath() + QLatin1String("DATA")); + } + + QString Settings::zsks_rxPath() + { + return getDirectory("ZSKS_RX", tempPath()); + } + + QString Settings::zsks_txPath() + { + return getDirectory("ZSKS_TX", tempPath()); + } + + QString Settings::aarServerPath(int exerciseId) + { + return getDirectory(QByteArray::number(exerciseId), QString::fromLocal8Bit("/data/aar/")); + } + + bool Settings::isDatabaseConnectionLocal() + { + return (databaseHostname() == QStringLiteral("localhost")); + } + + QString Settings::databaseName() + { + initializeGlobalSettings(); + + return s_globalSettings->value(globalSectionName()+ QLatin1String("/DatabaseName"), QLatin1String("lts_ets_pro")).toString(); + } + + QString Settings::databaseHostname() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/DatabaseHostname"), QLatin1String("EXCDBS01")).toString(); + } + + QString Settings::databaseUser() + { +#ifdef Q_OS_WIN + QByteArray defUser = qgetenv("USERNAME"); +#else + QByteArray defUser = qgetenv("USER"); +#endif + QString ret = m_settings->value(QLatin1String("db/user"), QString::fromLocal8Bit(defUser)).toString(); + return ret; + } + + QString Settings::databasePassword(const QString &databaseUser) + { + QString defaultPw = QStringLiteral("ctc11de"); + if (!databaseUser.isEmpty()) + { + const QVector &sl = databaseUser.splitRef(QLatin1Char('_')); + if (sl.size() > 1) + defaultPw = sl.at(0).toString() + QStringLiteral("11de"); + } + return m_settings->value(QLatin1String("db/passwd"), defaultPw).toString(); + } + + QString Settings::databaseDriver() + { + return m_settings->value(QLatin1String("db/driver"), QLatin1String("QPSQL")).toString(); + } + + int Settings::avsKeepAliveTimeout() + { + return m_settings->value(QLatin1String("avs/keepalivetimeout"), 20000).toInt(); + } + + QString Settings::avsServerHost() + { + return m_settings->value(QLatin1String("avs/serverhost"), QLatin1String("EXCAVS01")).toString(); + } + + quint16 Settings::avsServerPortAVE() + { + static const quint16 defaultPort = 6350; + bool bOk; + quint16 ret = m_settings->value(QLatin1String("avs/serverport_ave"), defaultPort).toUInt(&bOk); + return bOk ? ret : defaultPort; + } + + QSettings *Settings::settings() + { + return m_settings; + } + + const QSettings *Settings::settings() const + { + return m_settings; + } + + QString Settings::fixupPath(const QString &_path) const + { + QString path = QDir::fromNativeSeparators(_path); + if(!QDir::isAbsolutePath(path)) + path = basePath() + path; + path = QDir::cleanPath(path); + if(!path.endsWith(QLatin1Char('/'))) + path += QLatin1Char('/'); + return path; + } + + QString Settings::getDirectory(const QByteArray &_dir, const QString &defPrefix, bool bPathLowercase) + { + if(m_paths[_dir].isEmpty()) { + const QString lowerDir = QString::fromLatin1(_dir.toLower()); + const QString dir = bPathLowercase ? lowerDir : QString::fromLatin1(_dir); + QString def = defPrefix + QLatin1Char('/') + dir + QLatin1Char('/'); + m_paths[_dir] = fixupPath(m_settings->value(QLatin1String("paths/") + lowerDir, def).toString()); + QDir d(m_paths[_dir]); + if(!d.exists()) + d.mkpath(d.absolutePath()); + } + return m_paths[_dir]; + } + + void Settings::initPre() + { +#ifdef WIN32 + QString path = QString::fromLocal8Bit(qgetenv("GFS_PATH")); + if(path.isEmpty()) + path = QCoreApplication::applicationDirPath(); + m_paths["GFS_PATH"] = fixupPath(path); +#else + QByteArray path = qgetenv("GFS_PATH"); + if(path.isEmpty()) + path = qgetenv("HOME"); + m_paths["GFS_PATH"] = fixupPath(QString::fromLocal8Bit(path)); +#endif + + QByteArray tmppath = qgetenv("TMP_PATH"); + if(tmppath.isEmpty()) + tmppath = qgetenv("TMP"); + if (tmppath.isEmpty()) + tmppath = QDir::tempPath().toLocal8Bit(); + m_paths["TMP_PATH"] = fixupPath(QString::fromLocal8Bit(tmppath)); + } + + void Settings::initPost() + { + NGL::Connections::setIniFile(m_settings->fileName()); + } + + int Settings::getInteger(const QString &key, int defVal) const + { + bool bOk; + int ret = m_settings->value(key, defVal).toInt(&bOk); + return bOk ? ret : defVal; + } + + float Settings::getFloat(const QString &key, float defVal) const + { + bool bOk; + float ret = m_settings->value(key, defVal).toFloat(&bOk); + return bOk ? ret : defVal; + } + + double Settings::getDouble(const QString &key, double defVal) const + { + bool bOk; + double ret = m_settings->value(key, defVal).toDouble(&bOk); + return bOk ? ret : defVal; + } + + bool Settings::getBoolean(const QString &key, bool defVal) const + { + return m_settings->value(key, defVal).toBool(); + } + + QString Settings::getString(const QString &key, const QString &defVal) const + { + return m_settings->value(key, defVal).toString(); + } + + unsigned short Settings::domainId() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/DomainId"), 0).toUInt(); + } + + unsigned short Settings::portOffset() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/PortOffset"), 9000).toUInt(); + } + + QString Settings::serverHostname() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/ServerHostname"), QLatin1String("EXCTDS01")).toString(); + } + + QString Settings::logPath() + { + initializeGlobalSettings(); +#ifdef WIN32 + return s_globalSettings->value(QLatin1String("Global/LogPath"), QStandardPaths::writableLocation(QStandardPaths::TempLocation)).toString(); +#else + return s_globalSettings->value(QLatin1String("Global/LogPath"), QLatin1String("/shd/CTC/LOG")).toString(); +#endif + } + +} diff --git a/Z/src/nglsettings/nglsettings_settings.h b/Z/src/nglsettings/nglsettings_settings.h new file mode 100755 index 000000000..e59947099 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_settings.h @@ -0,0 +1,142 @@ + + +#pragma once + +#include +#include +#include "nglsettings_export.h" + +class QSettings; + +namespace NGL { + + + class NGLSETTINGS_EXPORT Settings { + public: + + + explicit Settings(const QString &iniFile); + + + + explicit Settings(const QString &organization, const QString &application); + + Settings(const Settings&) = delete; + Settings &operator=(const Settings&) = delete; + + + + virtual ~Settings(); + + + static void initializeGlobalSettings(); + + + QString basePath() const; + + QString tempPath() const; + + QString printPath(); + + QString logoProject(); + + QString bitmapPath(); + + + + QString zsks_rxPath(); + + QString zsks_txPath(); + + + + static QString databaseName(); + + static QString databaseHostname(); + + QString databaseUser(); + + QString databasePassword(const QString &databaseUser = QString()); + + QString databaseDriver(); + + + + QString aarServerPath(int exerciseId); + bool isDatabaseConnectionLocal(); + + + int avsKeepAliveTimeout(); + QString avsServerHost(); + quint16 avsServerPortAVE(); + + + QSettings *settings(); + + const QSettings *settings() const; + + + int getInteger(const QString &key, int defVal) const; + + + int getInteger(const QString &group, const QString &key, int defVal) const + { + return getInteger(group + QLatin1Char('/') + key, defVal); + } + + + float getFloat(const QString &key, float defVal) const; + + + float getFloat(const QString &group, const QString &key, float defVal) const + { + return getFloat(group + QLatin1Char('/') + key, defVal); + } + + + double getDouble(const QString &key, double defVal) const; + + + double getDouble(const QString &group, const QString &key, double defVal) const + { + return getDouble(group + QLatin1Char('/') + key, defVal); + } + + + bool getBoolean(const QString &key, bool defVal) const; + + + bool getBoolean(const QString &group, const QString &key, bool defVal) const + { + return getBoolean(group + QLatin1Char('/') + key, defVal); + } + + + QString getString(const QString &key, const QString &defVal) const; + + + QString getString(const QString &group, const QString &key, const QString &defVal) const + { + return getString(group + QLatin1Char('/') + key, defVal); + } + + static unsigned short portOffset(); + static unsigned short domainId(); + static QString serverHostname(); + static QString logPath(); + static QString globalSectionName(); + + private: + + QString fixupPath(const QString &path) const; + + + QString getDirectory(const QByteArray &dir, const QString &defPrefix, bool bPathLowercase = false); + private: + void initPre(); + void initPost(); + QSettings *m_settings; + static QSettings *s_globalSettings; + QHash m_paths; + }; +} diff --git a/Z/src/ngltools/CMakeLists.txt b/Z/src/ngltools/CMakeLists.txt new file mode 100755 index 000000000..fa6688a8f --- /dev/null +++ b/Z/src/ngltools/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# CMake Script für ngltools +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(ngltools_SRCS + ngltools_bitset.h + ngltools_convert.cpp + ngltools_convert.h + ngltools_dtg.cpp + ngltools_dtg.h + ngltools_export.h + ngltools_filesystem.cpp + ngltools_filesystem.h + ngltools_helpevent.cpp + ngltools_helpevent.h +) + +NGL_ADD_LIBRARY(ALL ngltools SHARED ${ngltools_SRCS}) +NGL_TARGET_LINK_LIBRARIES(ngltools + PUBLIC + Qt5::Core +) +NGL_TARGET_COMPILE_DEFINITIONS(ngltools PUBLIC BUILD_BASE_PATH="${CMAKE_BINARY_DIR}") +NGL_TARGET_COMPILE_DEFINITIONS(ngltools PUBLIC INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") + + +NGL_TARGET_INCLUDE_DIRECTORIES(ngltools + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_INSTALL_TARGET(ngltools) diff --git a/Z/src/ngltools/ngltools_bitset.h b/Z/src/ngltools/ngltools_bitset.h new file mode 100755 index 000000000..4141cf376 --- /dev/null +++ b/Z/src/ngltools/ngltools_bitset.h @@ -0,0 +1,100 @@ + + + +#pragma once + +namespace NGL { + template + class BitSet { + public: + BitSet(T bitset = T()) + : mBitSet(bitset) + , mSize(sizeof(T)*8) + {} + BitSet(const BitSet &other) + : mBitSet(other.mBitSet) + , mSize(other.mSize) + {} + BitSet &operator=(const BitSet &other) + { + if(this == &other) + return *this; + mBitSet = other.mBitSet; + mSize = other.mSize; + return *this; + } + bool operator==(const BitSet &other) const + { + return (mBitSet == other.mBitSet && mSize == other.mSize); + } + bool setBit(unsigned int bitNum) + { + if(bitNum >= mSize) + return false; + mBitSet |= getBit(bitNum); + return true; + } + + bool clearBit(unsigned int bitNum) + { + if(bitNum >= mSize) + return false; + mBitSet &= ~(getBit(bitNum)); + return true; + } + + bool at(unsigned int bitNum) const + { + if(bitNum >= sizeof(T) * 8) + return false; + T compVal = getBit(bitNum); + return ((mBitSet & compVal) == compVal); + } + + bool operator[] (unsigned int bitNum) const + { + return at(bitNum); + } + + size_t size() const + { + return mSize; + } + + bool resize(size_t newSize) + { + if(newSize >= sizeof(T) * 8) + return false; + for(unsigned int i = mSize; i < newSize; ++i) + clearBit(i); + mSize = newSize; + return true; + } + + void clear() + { + fill(false); + } + + void fill(bool bBitsSet) + { + if(bBitsSet) + mBitSet = ~T(); + else + mBitSet = T(); + } + + T operator()() const { return mBitSet; } + + protected: + static T getBit(unsigned int bitNum_) + { + T bitNum = bitNum_; + const T one = 1; + return (one << bitNum); + } + + T mBitSet; + size_t mSize; + }; +} diff --git a/Z/src/ngltools/ngltools_convert.cpp b/Z/src/ngltools/ngltools_convert.cpp new file mode 100755 index 000000000..f3f77b3ac --- /dev/null +++ b/Z/src/ngltools/ngltools_convert.cpp @@ -0,0 +1,91 @@ +#include "ngltools_convert.h" + +#include + +namespace NGL +{ +QByteArray quoteForTelnet(const QVector &sl) +{ + QVector tmp; + tmp.reserve(sl.size()); + for (const QString &s : sl) + tmp += s.toUtf8(); + return quoteForTelnet(tmp); +} + +QByteArray quoteForTelnet(const QVector &sl) +{ + QByteArray cmd; + for (QByteArray s : sl) + { + s.replace('\"', "\\\""); + if (s.contains(' ')) + s = '"' + s + '"'; + if (s.isEmpty()) + s = "\"\""; + cmd += s + ' '; + } + cmd += '\n'; + return cmd; +} + + +QVector parseFromTelnet(const QByteArray &ba, const int iStart) +{ + QVector ret; + const char *p = ba.constData() + iStart; + const int iLen = ba.length(); + const char *p_end = ba.constData() + iLen; + if (iLen <= iStart) + return ret; + char quoteEndChar = '"'; + + while (p < p_end && *p) + { + while (isspace(*p)) + ++p; + if (*p && p < p_end) + { + bool escaped = false; + bool bQuoted = (*p == '\"') || (*p == '{'); + if (bQuoted) + { + quoteEndChar = (*p == '\"') ? '\"' : '}'; + ++p; + } + const char *start = p; + while (true) + { + while (p < p_end && *p != (bQuoted ? quoteEndChar : ' ')) + ++p; + if (bQuoted) + { + + if (* (p - 1) == '\\') + { + ++p; + escaped = true; + continue; + } + } + QByteArray result = QByteArray(start, p - start).trimmed(); + if (escaped) + { + if (quoteEndChar == '}') + { + result = result.replace("\\{", "{"); + result = result.replace("\\}", "}"); + } + else + result = result.replace("\\\"", "\""); + } + ret += result; + ++p; + break; + } + } + } + return ret; +} + +} diff --git a/Z/src/ngltools/ngltools_convert.h b/Z/src/ngltools/ngltools_convert.h new file mode 100755 index 000000000..46d0af437 --- /dev/null +++ b/Z/src/ngltools/ngltools_convert.h @@ -0,0 +1,23 @@ + + + +#pragma once + +#include "ngltools_export.h" + +#include +#include +#include + +namespace NGL +{ +NGLTOOLS_EXPORT QByteArray quoteForTelnet(const QVector &sl); +NGLTOOLS_EXPORT QByteArray quoteForTelnet(const QVector &sl); + + +NGLTOOLS_EXPORT QVector parseFromTelnet(const QByteArray &ba, const int iStart = 0); +} + + + + diff --git a/Z/src/ngltools/ngltools_dtg.cpp b/Z/src/ngltools/ngltools_dtg.cpp new file mode 100755 index 000000000..66c4f656c --- /dev/null +++ b/Z/src/ngltools/ngltools_dtg.cpp @@ -0,0 +1,372 @@ +#include "ngltools_dtg.h" + +#include +#include + +namespace DTG +{ + +static char s_timezone = 'Z'; +static char s_userDefinedTimezone = s_timezone; +static char s_exerciseDefaultTimezone = s_timezone; +int timezone2Hours(char tz, bool *bOk) +{ + if (!isTimezoneValid(tz)) + { + if (bOk) + *bOk = false; + return 0; + } + if (bOk) + *bOk = true; + if (tz < 'J') + return tz - 'A' + 1; + if (tz < 'N') + return tz - 'A'; + if (tz < 'Z') + return 'Z' - tz - 13; + + return 0; +} + +int timezone2Secs(char tz, bool *bOk) +{ + return 3600 * timezone2Hours(tz, bOk) ; +} + + +bool setTimezone(char tz, bool bUserDefinedZone) +{ + if (!isTimezoneValid(tz)) + { + + if (!(tz == 0 && bUserDefinedZone)) + return false; + } + if (bUserDefinedZone) + s_userDefinedTimezone = tz; + else + s_exerciseDefaultTimezone = tz; + + s_timezone = s_userDefinedTimezone != 0 ? s_userDefinedTimezone : s_exerciseDefaultTimezone; + return true; +} + +char timezone() +{ + return s_timezone; +} +char timezoneUserDefined() +{ + return s_userDefinedTimezone; +} +char timezoneExerciseDefault() +{ + return s_exerciseDefaultTimezone; +} + +bool isTimezoneValid(char tz) +{ + tz = toupper(tz); + return !(tz < 'A' || tz == 'J' || tz > 'Z'); +} + + + +static DateTimeType s_dateTimeType = DDMMYYYY_Z_HHMMSS; +static DisplayFormat s_defaultDisplayFormat = Long; + + +void setDateTimeType(DateTimeType dtType) +{ + s_dateTimeType = dtType; +} + +DateTimeType dateTimeType() +{ + return s_dateTimeType; +} + +void setDefaultDisplayFormat(DisplayFormat dtFormat) +{ + s_defaultDisplayFormat = dtFormat; +} + +DisplayFormat defaultDisplayFormat() +{ + return s_defaultDisplayFormat; +} + +QString toString(const QDateTime &dt, DisplayFormat format, DateTimeType type) +{ + if (format == Default) + format = s_defaultDisplayFormat; + static const QDateTime dtNull = QDateTime::fromSecsSinceEpoch(0); + if (!dt.isValid() || dt == dtNull) + return QString(); + + const QDateTime dateTime = dt.toUTC().addSecs(timezone2Hours(s_timezone) * 3600); + QString ret; + + switch (type) + { + case DTG: + { + + + + QString str1; + + if (format == Long) + str1 = dateTime.toString(QLatin1String("dd hhmmss")); + else if (format == TurboLong) + str1 = dateTime.toString(QLatin1String("dd hhmmss.z")); + else + { + ret = dateTime.toString(QLatin1String("ddhhmm")) + QLatin1Char(s_timezone); + break; + } + + + const int month = dateTime.date().month() - 1; + const int year = dateTime.date().year() - 2000; + ret = QStringLiteral("%1 %2 %3 %4") + .arg(str1) + .arg(QLatin1Char(s_timezone)) + .arg(months().at(month)) + .arg(year, 2, 10, QLatin1Char('0')); + } + break; + case DDMMYYYY_HHMMSS_Z: + { + if (format == Long) + ret = dateTime.toString(QLatin1String("dd.MM.yyyy HH:mm:ss")) + QLatin1Char(s_timezone); + else + ret = dateTime.toString(QLatin1String("dd.MM HH:mm")) + QLatin1Char(s_timezone); + + } + break; + case DDMMYYYY_Z_HHMMSS: + if (format == Long) + ret = dateTime.toString(QLatin1String("dd.MM.yyyy ")) + + QLatin1Char(s_timezone) + + dateTime.toString(QLatin1String(" HH:mm:ss")); + else + ret = dateTime.toString(QLatin1String("dd.MM ")) + + QLatin1Char(s_timezone) + + dateTime.toString(QLatin1String(" HH:mm")); + break; + } + + + return ret; +} + +QString toStringMSec(qint64 msecSinceEpoch, DisplayFormat format) +{ + if (msecSinceEpoch <= 0) + return QString(); + return toString(QDateTime::fromMSecsSinceEpoch(msecSinceEpoch), format); +} + + +static bool check24(const QChar *input, int *output) +{ + const int i1 = input[0].unicode() - '0'; + const int i2 = input[1].unicode() - '0'; + if (i1 > 2) + return false; + if (i1 == 2 && i2 > 5) + return false; + if (output) + *output = i1 * 10 + i2; + return true; +} + +static bool check31(const QChar *input, int *output = nullptr) +{ + const int i1 = input[0].unicode() - '0'; + const int i2 = input[1].unicode() - '0'; + if (i1 > 3) + return false; + if (i1 == 3 && i2 > 1) + return false; + if (output) + *output = i1 * 10 + i2; + return true; +} + +static bool check60(const QChar *input, int *output) +{ + const int i1 = input[0].unicode() - '0'; + const int i2 = input[1].unicode() - '0'; + if (i1 > 5) + return false; + if (output) + *output = i1 * 10 + i2; + return true; +} + +static DTGValidation validate18(const QString &input, QDateTime &dt) +{ + int hh, mm, ss; + + for (int i = 0; i < 2; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + if (!check31(&input.data() [0])) + return Invalid; + + if (input[2] != QLatin1Char(' ')) + return Invalid; + + if (input.length() == 7) + { + for (int i = 3; i < 7; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + return Intermediate; + } + for (int i = 3; i < 9; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + if (!check24(&input.data() [3], &hh)) + return Invalid; + if (!check60(&input.data() [5], &mm)) + return Invalid; + if (!check60(&input.data() [7], &ss)) + return Invalid; + + if (input[9] != QLatin1Char(' ')) + return Invalid; + + const QChar c = input[10]; + if (c < QLatin1Char('A') || c > QLatin1Char('Z')) + return Invalid; + if (c == QLatin1Char('J')) + { + + return Invalid; + } + + const QString mon = input.mid(12, 3); + int month = months().indexOf(mon); + if (month < 0) + { + + return Invalid; + } + + for (int i = 16; i < 18; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + + + const int day = input.leftRef(2).toInt(); + const int year = input.midRef(16, 2).toInt() + 2000; + dt = QDateTime(QDate(year, month + 1, day), QTime(hh, mm, ss), Qt::UTC); + if (!dt.isValid()) + { + + return Invalid; + } + dt = dt.addSecs(-timezone2Hours(c.toLatin1()) * 3600); + + + return Acceptable; +} + +static DTGValidation validate7(const QString &input, QDateTime &dt) +{ + int hh, mm; + + for (int i = 0; i < 6; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + if (!check31(&input.data() [0])) + return Invalid; + if (!check24(&input.data() [2], &hh)) + return Invalid; + if (!check60(&input.data() [4], &mm)) + return Invalid; + + + const QChar c = input[6]; + if (c < QLatin1Char('A') || c > QLatin1Char('Z')) + return Invalid; + if (c == QLatin1Char('J')) + { + + return Invalid; + } + + + const int day = input.leftRef(2).toInt(); + const QDate curDate = QDate::currentDate(); + dt = QDateTime(QDate(curDate.year(), curDate.month(), day), QTime(hh, mm), Qt::UTC); + if (!dt.isValid()) + { + + return Invalid; + } + dt = dt.addSecs(-timezone2Hours(c.toLatin1()) * 3600); + + + return Acceptable; +} + +QDateTime fromDTGString(const QString &str, bool *bOk) +{ + if (bOk) + *bOk = false; + + QDateTime dt; + if (str.length() == 7) + { + DTGValidation state = validate7(str, dt); + if (state == Acceptable && bOk) + *bOk = true; + } + else if (str.length() == 18) + { + DTGValidation state = validate18(str, dt); + if (state == Acceptable && bOk) + *bOk = true; + } + return dt; +} + +DTGValidation validateString(const QString &str, QDateTime &dt) +{ + const int len = str.length(); + if (len == 7 || len == 18) + { + + if (len == 18 || (str[2] == QLatin1Char(' '))) + return validate18(str, dt); + return validate7(str, dt); + } + return Invalid; +} + +QStringList months() +{ + return { + QLatin1String("jan"), QLatin1String("feb"), QLatin1String("mar"), + QLatin1String("apr"), QLatin1String("may"), QLatin1String("jun"), + QLatin1String("jul"), QLatin1String("aug"), QLatin1String("sep"), + QLatin1String("oct"), QLatin1String("nov"), QLatin1String("dec") + }; +} + +} diff --git a/Z/src/ngltools/ngltools_dtg.h b/Z/src/ngltools/ngltools_dtg.h new file mode 100755 index 000000000..fe14277b8 --- /dev/null +++ b/Z/src/ngltools/ngltools_dtg.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include "ngltools_export.h" + +class QDateTime; + + +namespace DTG +{ + + + +enum DateTimeType +{ + DTG = 1, + DDMMYYYY_HHMMSS_Z = 2, + DDMMYYYY_Z_HHMMSS = 4 +}; + + + + +enum DisplayFormat +{ + Short, + Long, + TurboLong, + Default +}; + +enum DTGValidation +{ + Invalid, + Intermediate, + Acceptable +}; + + + +NGLTOOLS_EXPORT void setDateTimeType(DateTimeType dtType); + + +NGLTOOLS_EXPORT DateTimeType dateTimeType(); + + + +NGLTOOLS_EXPORT void setDefaultDisplayFormat(DisplayFormat dtFormat); + + +NGLTOOLS_EXPORT DisplayFormat defaultDisplayFormat(); + + + +NGLTOOLS_EXPORT QString toString(const QDateTime &dt, DisplayFormat format = Default, DateTimeType = dateTimeType()); + + +NGLTOOLS_EXPORT QString toStringMSec(qint64 msecSinceEpoch, DisplayFormat format = Default); + + + +NGLTOOLS_EXPORT QDateTime fromDTGString(const QString &str, bool *bOk = nullptr); + + +NGLTOOLS_EXPORT DTGValidation validateString(const QString &str, QDateTime &dt); + + + +NGLTOOLS_EXPORT bool setTimezone(char tz, bool bUserDefinedZone); + + +NGLTOOLS_EXPORT char timezone(); +NGLTOOLS_EXPORT char timezoneUserDefined(); +NGLTOOLS_EXPORT char timezoneExerciseDefault(); + +NGLTOOLS_EXPORT bool isTimezoneValid(char tz); + + +NGLTOOLS_EXPORT int timezone2Hours(char tz, bool *bOk = nullptr); + + +NGLTOOLS_EXPORT int timezone2Secs(char tz, bool *bOk = nullptr); + + +NGLTOOLS_EXPORT QStringList months(); + +} diff --git a/Z/src/ngltools/ngltools_export.h b/Z/src/ngltools/ngltools_export.h new file mode 100755 index 000000000..1ae2a789c --- /dev/null +++ b/Z/src/ngltools/ngltools_export.h @@ -0,0 +1,19 @@ + + +#pragma once + +#ifndef NGLTOOLS_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLTOOLS_EXPORT +# else +# ifdef WIN32 +# ifdef MAKE_NGLTOOLS_LIB +# define NGLTOOLS_EXPORT __declspec(dllexport) +# else +# define NGLTOOLS_EXPORT __declspec(dllimport) +# endif +# else +# define NGLTOOLS_EXPORT __attribute__((visibility("default"))) +# endif +# endif +#endif diff --git a/Z/src/ngltools/ngltools_filesystem.cpp b/Z/src/ngltools/ngltools_filesystem.cpp new file mode 100755 index 000000000..8f3dda2fe --- /dev/null +++ b/Z/src/ngltools/ngltools_filesystem.cpp @@ -0,0 +1,289 @@ + + + +#include "ngltools_filesystem.h" + +#include +#include +#include + +namespace NGL +{ + +bool removeDirContentsRecursively(const QString &d, bool bAlsoDeleteBaseDir) +{ + + QDir dir(d); + if (!dir.exists()) + return false; + + bool success = true; + const QFileInfoList list = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries); + for (const QFileInfo &fi : list) + { + bool ret = false; + if (fi.isDir()) + { + ret = removeDirContentsRecursively(fi.absoluteFilePath()); + if (!ret) + { + + } + else + { + ret = dir.rmdir(fi.absoluteFilePath()); + if (!ret) + { + + } + } + + } + else if (fi.isFile() || fi.isSymLink()) + { + ret = dir.remove(fi.fileName()); + if (!ret) + { + + } + } + success &= ret; + } + if (bAlsoDeleteBaseDir) + success &= dir.rmpath(d); + return success; +} + +bool copyDirContentsToDir(const QString &source, const QString &destination, bool sourceIsRelative) +{ + QString srcPath(source); + + if (sourceIsRelative) + { + QVector pathsToSearch = directories(FileType::ConfigFile); + pathsToSearch.append(directories(FileType::ProjectConfigFile)); + for (const QString &basePath : qAsConst(pathsToSearch)) + { + QString absolutePath = basePath + QLatin1Char('/') + source; + if (QDir(absolutePath).exists()) + { + srcPath = absolutePath; + break; + } + } + if (srcPath.isEmpty()) + return false; + } + + QDir srcDir(srcPath); + QDir dstDir(destination); + + if (!dstDir.exists()) + { + bool succ = dstDir.mkdir(destination); + if (!succ) + return false; + } + + const QFileInfoList dirList = srcDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); + for (const QFileInfo &fi : dirList) + { + + if (!dstDir.exists()) + { + bool succ = dstDir.mkdir(fi.fileName()); + if (!succ) + return false; + } + bool succ = copyDirContentsToDir(fi.filePath(), dstDir.absolutePath() + QLatin1Char('/') + fi.fileName()); + if (!succ) + return false; + } + + const QFileInfoList fileList = srcDir.entryInfoList(QDir::Files | QDir::Hidden); + for (const QFileInfo &fi : fileList) + { + QString targetFileName = dstDir.absolutePath() + QLatin1Char('/') + fi.fileName(); + QFile targetFile(targetFileName); + if (targetFile.exists()) + targetFile.remove(); + bool succ = QFile::copy(fi.absoluteFilePath(), targetFileName); + if (!succ) + return false; + } + return true; +} + +qint64 getDirectorySize(const QString &dir) +{ + QDir d(dir); + qint64 ret = QFileInfo(dir).size(); + + const QFileInfoList dirList = d.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); + const QFileInfoList fileList = d.entryInfoList(QDir::Files | QDir::Hidden); + + for (const QFileInfo &fi : dirList) + ret += getDirectorySize(fi.absoluteFilePath()); + + for (const QFileInfo &fi : fileList) + ret += fi.size(); + + return ret; +} + +bool isAppInBuildBasePath() +{ + bool ret = false; +#ifdef BUILD_BASE_PATH + const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH)); + if (!bbp.isEmpty()) + ret = QCoreApplication::applicationDirPath().startsWith(bbp); +#endif + return ret; +} + +QString projectConfigFileName() +{ + return QLatin1String("lts-cc.conf"); +} + +QString findProjectConfigFile() +{ + return findFile(FileType::ProjectConfigFile, projectConfigFileName()); +} + +static QString searchFileInDir(const QString &path, const QString &filename, bool bRecursive) +{ + if (QFile::exists(path + QLatin1Char('/') + filename)) + return path + QLatin1Char('/') + filename; + + if (!bRecursive) + return QString(); + + const QDir d(path); + const QStringList entryList = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); + for (const QString &entry : entryList) + { + const QString foundPath = searchFileInDir(path + QLatin1Char('/') + entry, filename, bRecursive); + if (!foundPath.isEmpty()) + return foundPath; + } + return QString(); +} + +QString findFile(FileType fileType, const QString &filename) +{ + const QFileInfo fi(filename); + if (fi.isAbsolute()) + return fi.exists() ? filename : QString(); + const bool bRecursive = (fileType == FileType::ConfigFile); + const QVector pathsToSearch = directories(fileType); + for (const QString &path : pathsToSearch) + { + const QString foundPath = searchFileInDir(path, filename, bRecursive); + if (!foundPath.isEmpty()) + return foundPath; + } + return QString(); +} + +QVector directories(FileType fileType) +{ + QVector pathsToSearch; + switch (fileType) + { + case FileType::ProjectConfigFile: + { +#ifdef BUILD_BASE_PATH + const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH)); + if (!bbp.isEmpty()) + { + + + + if (QCoreApplication::applicationDirPath().startsWith(bbp)) + pathsToSearch += bbp; + } +#endif + pathsToSearch += QDir::homePath(); +#ifdef Q_OS_UNIX + pathsToSearch += QLatin1String("/etc"); +#else + pathsToSearch += QStringLiteral("C:/Rheinmetall/Lts/"); + pathsToSearch += QCoreApplication::applicationDirPath(); +#endif + break; + } + case FileType::ConfigFile: + { +#ifdef BUILD_BASE_PATH + const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH)); + if (!bbp.isEmpty()) + { + + + + if (QCoreApplication::applicationDirPath().startsWith(bbp)) + pathsToSearch += bbp + QLatin1String("/share/Lts"); + } +#endif + pathsToSearch += QCoreApplication::applicationDirPath() + QLatin1String("/share/Lts"); + pathsToSearch += QCoreApplication::applicationDirPath() + QLatin1String("/../share/Lts"); + pathsToSearch += QDir::homePath() + QLatin1String("/share/Lts"); +#ifdef INSTALL_PREFIX + pathsToSearch += QString::fromLocal8Bit(INSTALL_PREFIX) + QLatin1String("/share/Lts"); +#endif + break; + } + } + return pathsToSearch; +} +QString findServiceXmlFile(const QString &serviceShortName) +{ + return findFile(FileType::ConfigFile, serviceShortName + QLatin1String(".xml")); +} + +QString directory(FileType fileType, const QString &subdir) +{ + const QVector pathsToSearch = directories(fileType); + QFileInfo fi; + for (const QString &path : pathsToSearch) + { + fi.setFile(path + QLatin1Char('/') + subdir); + if (fi.isDir() && fi.exists() && fi.isReadable()) + return fi.absoluteFilePath() + QLatin1Char('/'); + } + return QString(); +} + +QString postgresExecutablePath(const QString &psqlProgram, QString &errStr) +{ + errStr.clear(); +#ifdef Q_OS_LINUX + return QStringLiteral("/usr/bin/") + psqlProgram; +#else + static QString s_postgresBinariesPath; + if (s_postgresBinariesPath.isEmpty()) + { + QSettings s(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\PostgreSQL\\Installations"), QSettings::NativeFormat); + const QStringList installations = s.childGroups(); + if (installations.isEmpty()) + { + errStr = QStringLiteral("Could not find a valid PostgreSQL windows installation..."); + return psqlProgram; + } + if (installations.size() > 1) + errStr = QStringLiteral("More than one PostgreSQL windows installation found - using the first one: %1").arg(installations.first()); + s.beginGroup(installations.first()); + const QString baseDir = s.value(QStringLiteral("Base Directory")).toString(); + if (baseDir.isEmpty() || !QDir(baseDir).exists()) + { + errStr = QStringLiteral("Could not find a valid PostgreSQL windows installation... - Base Directory is empty or does not exist (%1)").arg(baseDir); + return psqlProgram; + } + s_postgresBinariesPath = baseDir + QStringLiteral("/bin/"); + } + return s_postgresBinariesPath + psqlProgram + QStringLiteral(".exe"); +#endif +} +} diff --git a/Z/src/ngltools/ngltools_filesystem.h b/Z/src/ngltools/ngltools_filesystem.h new file mode 100755 index 000000000..cfd571e66 --- /dev/null +++ b/Z/src/ngltools/ngltools_filesystem.h @@ -0,0 +1,38 @@ + + + +#pragma once + +#include "ngltools_export.h" + +#include +#include + +namespace NGL +{ + NGLTOOLS_EXPORT bool removeDirContentsRecursively(const QString &d, bool bAlsoDeleteBaseDir = false); + NGLTOOLS_EXPORT bool copyDirContentsToDir(const QString &source, const QString &destination, bool sourceIsRelative = false); + NGLTOOLS_EXPORT qint64 getDirectorySize(const QString &dir); + + + enum class FileType + { + ProjectConfigFile, + ConfigFile + }; + + NGLTOOLS_EXPORT bool isAppInBuildBasePath(); + NGLTOOLS_EXPORT QString projectConfigFileName(); + NGLTOOLS_EXPORT QString findProjectConfigFile(); + NGLTOOLS_EXPORT QString findFile(FileType fileType, const QString &filename); + + + NGLTOOLS_EXPORT QString findServiceXmlFile(const QString &serviceShortName); + + NGLTOOLS_EXPORT QVector directories(FileType fileType); + + NGLTOOLS_EXPORT QString directory(FileType fileType, const QString &subdir); + + + NGLTOOLS_EXPORT QString postgresExecutablePath(const QString &psqlProgram, QString &errStr); +} diff --git a/Z/src/ngltools/ngltools_helpevent.cpp b/Z/src/ngltools/ngltools_helpevent.cpp new file mode 100755 index 000000000..dec4675d3 --- /dev/null +++ b/Z/src/ngltools/ngltools_helpevent.cpp @@ -0,0 +1,19 @@ + + +#include "ngltools_helpevent.h" +#include + +QEvent::Type NGLHelpEvent::sHelpEventId = (QEvent::Type)(-1); + +void NGLHelpEvent::sendHelpEvent(const QString &helpContext) +{ + NGLHelpEvent he(helpContext); + QCoreApplication::sendEvent(qApp, &he); +} + +QEvent::Type NGLHelpEvent::helpEventId() +{ + if(sHelpEventId < 0) + sHelpEventId = (QEvent::Type)(QEvent::registerEventType()); + return sHelpEventId; +} diff --git a/Z/src/ngltools/ngltools_helpevent.h b/Z/src/ngltools/ngltools_helpevent.h new file mode 100755 index 000000000..5ec87af55 --- /dev/null +++ b/Z/src/ngltools/ngltools_helpevent.h @@ -0,0 +1,34 @@ + + +#pragma once + +#include +#include +#include "ngltools_export.h" + + + +class NGLTOOLS_EXPORT NGLHelpEvent : public QEvent +{ +protected: + + + explicit NGLHelpEvent(const QString &helpContext) + : QEvent(helpEventId()) + , mHelpContext(helpContext) + {} +public: + + + QString helpContext() const { return mHelpContext; } + + + static void sendHelpEvent(const QString &helpContext); + + + static QEvent::Type helpEventId(); + +protected: + QString mHelpContext; + static QEvent::Type sHelpEventId; +}; diff --git a/Z/src/ngltranslator/CMakeLists.txt b/Z/src/ngltranslator/CMakeLists.txt new file mode 100755 index 000000000..3058ff8f7 --- /dev/null +++ b/Z/src/ngltranslator/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# ngltranslator lib +# $Id$ +# $HeadURL$ +# $Author$ +# +SET(my_SRCS + ngltranslator.cpp + ngltranslator.h + ngltranslator_export.h +) + +NGL_ADD_LIBRARY(ALL ngltranslator SHARED ${my_SRCS}) +NGL_TARGET_LINK_LIBRARIES(ngltranslator + PUBLIC + Qt5::Core +) +NGL_TARGET_INCLUDE_DIRECTORIES(ngltranslator + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) +NGL_INSTALL_TARGET(ngltranslator) diff --git a/Z/src/ngltranslator/ngltranslator.cpp b/Z/src/ngltranslator/ngltranslator.cpp new file mode 100755 index 000000000..ec8c0e4ed --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator.cpp @@ -0,0 +1,222 @@ + + + +#include "ngltranslator.h" +#include "ngltranslator_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace NGL +{ + +struct TranslationData +{ + QByteArray isoCode; + QString qmPrefix; + QTranslator qtTranslator; + QTranslator kdReportsTranslator; + QTranslator ltsTranslator; + Translator dynamicTranslator; + + TranslationData() + { + QCoreApplication::installTranslator(&qtTranslator); + QCoreApplication::installTranslator(&kdReportsTranslator); + QCoreApplication::installTranslator(<sTranslator); + QCoreApplication::installTranslator(&dynamicTranslator); + } + ~TranslationData() + { + if (qApp) + { + QCoreApplication::removeTranslator(&qtTranslator); + QCoreApplication::removeTranslator(&kdReportsTranslator); + QCoreApplication::removeTranslator(<sTranslator); + QCoreApplication::removeTranslator(&dynamicTranslator); + } + } +}; + +Q_GLOBAL_STATIC(TranslationData, s_translationData) + + +Translator::Translator(QObject *parent) + : QTranslator(parent) +{} + + +void Translator::setTranslationCatalog(const TranslationCatalog &catalog) +{ + m_catalog = catalog; + m_md5Sum.clear(); + isoCodeChanged(s_translationData()->isoCode); +} + +bool Translator::setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed) +{ + if (m_md5Sum == md5Sum) + return true; + + const QJsonObject jObj = QJsonDocument::fromBinaryData(bCompressed ? qUncompress(jsonData) : jsonData).object(); + const QString translationKey(QStringLiteral("translations")); + if (jObj.empty() || + !jObj.contains(translationKey) || + !jObj.value(translationKey).isArray()) + return false; + + const QJsonArray arr = jObj[translationKey].toArray(); + + m_catalog.clear(); + m_catalog.reserve(arr.size()); + TranslationEntry te; + for (const QJsonValue &element : arr) + { + const QJsonObject obj = element.toObject(); + + te.isoCode = obj.value(QStringLiteral("isoCode")).toString().toUtf8(); + te.context = obj.value(QStringLiteral("context")).toString().toUtf8(); + te.key = obj.value(QStringLiteral("key")).toString().toUtf8(); + te.disambiguation = obj.value(QStringLiteral("disambiguation")).toString().toUtf8(); + te.translation = obj.value(QStringLiteral("translation")).toString(); + + m_catalog += te; + } + + m_md5Sum = md5Sum; + isoCodeChanged(s_translationData()->isoCode); + + return false; +} + + + +QString Translator::translate(const char *context, + const char *sourceText, + const char *disambiguation, + int n) const +{ + + if (n != -1) + return QString(); + + const auto itCtx = m_translationLookup.find(QByteArray::fromRawData(context, strlen(context))); + if (itCtx == m_translationLookup.end()) + return QString(); + const auto itKey = itCtx.value().find(QByteArray::fromRawData(sourceText, strlen(sourceText))); + if (itKey == itCtx.value().end()) + return QString(); + const auto itDis = itKey.value().find(disambiguation ? QByteArray::fromRawData(disambiguation, strlen(disambiguation)) : QByteArray()); + if (itDis == itKey.value().end()) + return QString(); + return itDis.value(); +} + + +void Translator::isoCodeChanged(const QByteArray &isoCode) +{ + m_translationLookup.clear(); + for (const TranslationEntry &te : qAsConst(m_catalog)) + { + if (te.isoCode != isoCode) + continue; + m_translationLookup[te.context][te.key][te.disambiguation] = te.translation; + } +} + + + + +void setTranslationCatalog(const TranslationCatalog &catalog) +{ + s_translationData()->dynamicTranslator.setTranslationCatalog(catalog); +} + + +bool setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed) +{ + return s_translationData()->dynamicTranslator.setTranslationDataJson(jsonData, md5Sum, bCompressed); +} + + +bool setTranslationLocale(const QByteArray &isoCode, const QString &qmPrefix) +{ + + if (s_translationData()->isoCode == isoCode && + s_translationData()->qmPrefix == qmPrefix) + return true; + + s_translationData()->isoCode = isoCode; + s_translationData()->qmPrefix = qmPrefix; + + const QString relTranslationPath = QLatin1Char('/') + QString::fromLatin1(isoCode) + QLatin1Char('/'); + const QStringList possiblePaths = { QCoreApplication::applicationDirPath() + QStringLiteral("/translations/"), + QCoreApplication::applicationDirPath() + QStringLiteral("/../translations/"), + QDir::homePath() + QStringLiteral("/translations/") + }; + const QString qm(QStringLiteral(".qm")); + + QString ltsQmPath; + for (const QString &path : possiblePaths) + { + const QString absPath = path + relTranslationPath; + if (!QDir(absPath).exists()) + continue; + if (QTranslator().load(qmPrefix + qm, absPath)) + { + ltsQmPath = absPath + qmPrefix + qm; + break; + } + } + + + QString kdReportsQmPath; + const QString kdReportsPrefix(QStringLiteral("kdreports")); + for (const QString &path : possiblePaths) + { + const QString absPath = path + relTranslationPath; + if (!QDir(absPath).exists()) + continue; + if (QTranslator().load(kdReportsPrefix + qm, absPath)) + { + kdReportsQmPath = absPath + kdReportsPrefix + qm; + break; + } + } + + + QStringList isoCodeList(QString::fromLatin1(isoCode).split(QLatin1Char('_'))); + if (isoCodeList.count() == 2) + { + s_translationData->qtTranslator.load(QLatin1String("qt_") + isoCodeList.at(0), + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + } + else + { + + qWarning() << "translation iso code not compatible with qt translations"; + } + + s_translationData->kdReportsTranslator.load(kdReportsQmPath); + s_translationData->ltsTranslator.load(ltsQmPath); + s_translationData->dynamicTranslator.isoCodeChanged(isoCode); + + return !s_translationData->ltsTranslator.isEmpty(); +} + + +QByteArray translationLocale() +{ + return s_translationData()->isoCode; +} + +} + diff --git a/Z/src/ngltranslator/ngltranslator.h b/Z/src/ngltranslator/ngltranslator.h new file mode 100755 index 000000000..5f661505d --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator.h @@ -0,0 +1,40 @@ + + + +#pragma once + +#include "ngltranslator_export.h" +#include +#include +#include + +namespace NGL +{ + +struct TranslationEntry +{ + QByteArray isoCode; + QByteArray context; + QByteArray key; + QByteArray disambiguation; + QString translation; +}; +using TranslationCatalog = QVector; + + + +NGLTRANSLATOR_EXPORT void setTranslationCatalog(const TranslationCatalog &catalog); + + + +NGLTRANSLATOR_EXPORT bool setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed); + + + +NGLTRANSLATOR_EXPORT bool setTranslationLocale(const QByteArray &isoCode, const QString &qmPrefix = QStringLiteral("tds")); + + + +NGLTRANSLATOR_EXPORT QByteArray translationLocale(); + +} diff --git a/Z/src/ngltranslator/ngltranslator_export.h b/Z/src/ngltranslator/ngltranslator_export.h new file mode 100755 index 000000000..90f802157 --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator_export.h @@ -0,0 +1,19 @@ + + +#pragma once + +#ifndef NGLTRANSLATOR_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLTRANSLATOR_EXPORT +# else +# ifdef WIN32 +# ifdef MAKE_NGLTRANSLATOR_LIB +# define NGLTRANSLATOR_EXPORT __declspec(dllexport) +# else +# define NGLTRANSLATOR_EXPORT __declspec(dllimport) +# endif +# else +# define NGLTRANSLATOR_EXPORT __attribute__((visibility("default"))) +# endif +# endif +#endif diff --git a/Z/src/ngltranslator/ngltranslator_p.h b/Z/src/ngltranslator/ngltranslator_p.h new file mode 100755 index 000000000..e8f7501b0 --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator_p.h @@ -0,0 +1,34 @@ + + +#pragma once + +#include "ngltranslator.h" + +#include +#include + +namespace NGL +{ +class Translator final : public QTranslator +{ + Q_OBJECT +public: + explicit Translator(QObject *parent = nullptr); + + QString translate(const char *context, + const char *sourceText, + const char *disambiguation = nullptr, + int n = -1) const override; + + void setTranslationCatalog(const TranslationCatalog &catalog); + bool setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed); + + void isoCodeChanged(const QByteArray &isoCode); +private: + + QHash>> m_translationLookup; + TranslationCatalog m_catalog; + QByteArray m_md5Sum; +}; + +} diff --git a/Z/src/nglwidgets/CMakeLists.txt b/Z/src/nglwidgets/CMakeLists.txt new file mode 100755 index 000000000..90110a1c3 --- /dev/null +++ b/Z/src/nglwidgets/CMakeLists.txt @@ -0,0 +1,52 @@ +PROJECT(nglwidgets) + +FIND_PACKAGE(PopplerQt5 REQUIRED) + +# +# NGL Widgets library +# +SET(nglwidgets_SRCS + ngldialogbuttonbox.cpp + ngldialogbuttonbox.h + ngldialog.cpp + ngldialog.h + nglmainwindow.cpp + nglmainwindow.h + nglpdfdocument.cpp + nglpdfdocument.h + nglpdfpage.cpp + nglpdfpage.h + nglstandardbutton.cpp + nglstandardbutton.h + ngltreeitem.cpp + ngltreeitem.h + ngltreemodel.cpp + ngltreemodel.h + nglpdfwidget.cpp + nglpdfwidget.h + nglwidgets_export.h +) + +NGL_WRAP_UI(nglwidgets_SRCS + nglpdfwidget.ui +) + +NGL_ADD_BIG_RESOURCES(oxygen_SRCS nglresources.qrc) +# SV: logView +NGL_ADD_LIBRARY(WS AAR SV nglwidgets SHARED ${nglwidgets_SRCS} ${oxygen_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglwidgets + PRIVATE + ${POPPLER_QT5_INCLUDE_DIR} +) +NGL_TARGET_LINK_LIBRARIES(nglwidgets + PRIVATE + NGLLogger + ngltranslator + ngltools + ${POPPLER_QT5_LIBRARY} + PUBLIC + Qt5::Core + Qt5::Widgets +) + +NGL_INSTALL_TARGET(nglwidgets) diff --git a/Z/src/nglwidgets/icons/16x16/LICENSE b/Z/src/nglwidgets/icons/16x16/LICENSE new file mode 100755 index 000000000..82f24a630 --- /dev/null +++ b/Z/src/nglwidgets/icons/16x16/LICENSE @@ -0,0 +1,24 @@ +Icon theme + +Oxygen icon theme is dual licensed. You may copy it under the Creative Common +Attribution-ShareAlike 3.0 License or the GNU Library General Public License. + +Creative Common Attribution-ShareAlike 3.0 License (short form): + +You are free: + + * to Share — to copy, distribute and transmit the work + * to Remix — to adapt the work + +Under the following conditions: + + * Attribution. You must attribute the work in the manner specified by the + author or licensor (but not in any way that suggests that they endorse + you or your use of the work). + + * Share Alike. If you alter, transform, or build upon this work, you may + distribute the resulting work only under the same, similar or a + compatible license. + +See also http://creativecommons.org/licenses/by-sa/3.0/ and +http://creativecommons.org/licenses/by-sa/3.0/legalcode diff --git a/Z/src/nglwidgets/icons/16x16/application-pdf.png b/Z/src/nglwidgets/icons/16x16/application-pdf.png new file mode 100755 index 0000000000000000000000000000000000000000..9498f0ffdba67b6960afdf662653a8432f615e4a GIT binary patch literal 688 zcmV;h0#E&kP)xjkU5C9ymSw>(jDCVpAk4(f3{vy+a1Rb(udM+W7f2?Pq0rw6 z#JvCre_&z)>c$5A^K;y7Z2^OWNUg6UJ~q}*fUZE8Bp_=ws8s0F+;O5w6A6f*xw?wa zv$Ic(@JPXDaB~BUjzSRb-R>@$*(}85Br?axczJTtHv$ug-;X(660okXVICbJwz7g} z`}+|0Mj}Va{vGsCc(gF{@DSS464J#YG;(FT-NtRb&MqvM%kKev~uQv zd$A}R%gge1Z%>l@B<(<&rYS3x3ZI2Sp$gzNC4Wb~OJuV+trqmfMI>ovG7UHIJdepr zrBW@I%e?_mkraOrc+{y&VOFcM-E4Aa66BN26Xf&x)85WuhM)5*{_~%~GhcD%p7;ex WLIk?6j(Oq$0000qm|rIM*THKYbgj#5EThHVGp>QQ+y$SGVUd5n>Vi^Dhi? z=Gp7p`&O_%-wyUezg*(nRzm^8q$r;Q0FLwje&-*R0-@+#lQ?Ps0000pf9L*rlU&o38m%ZUnjts@YN3Td9RC#dB77qOajaU&u6O)=K#zfzH-=kSAiP1c8rUMV0-#Lev z8NDFz0Gg#tWInR=YylWcD~l^XV;^H%^n>Whf)-}LP;Mc&JbXC(o2IG%X@Uq)yez_n zoyg8+-z1WWKa`0RBbh$8C34Rcj#RA+eYcCV{7O06WHTD-0gS$h;5 zR8G#OIM3y-4@oE?$NnX7{r7hFyjq^%RW73g|9zv%hvq;uXumZ#(FHxf^BsRnl`~7B R;>7>}002ovPDHLkV1m8G+5Z3l literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/audio-x-generic.png b/Z/src/nglwidgets/icons/16x16/audio-x-generic.png new file mode 100755 index 0000000000000000000000000000000000000000..017b00da90f5f743e448303e13a74aed5f27494f GIT binary patch literal 643 zcmV-}0(||6P)#_p*zkRy zNrnOp1DdGG>^V}+I4~yliNsLEFp@8BW4pS|aU`@pF&%N2FgYl;IDZpQKRtmoFjZJ7 zkl_MM9u9~2U9C=Sw9FV*bE_zQ-$JEQf$O^5Y<2{m?fB>jsZ$qL^&b))c zV1Ps-!8y9}OC#j-dDQE5#9}cb1qFKSm+mZ~rj!*51^U(_m|+FcXcU=D2A{hh@#^?F zetbJY`|zA|bCEeXjzjN-RO(wWG4s;?_y>6Q^C311U+~s@4fF3;%JTU%n@w~&|6tpe zPv+W!2QL0DE@kkYvLB(JbK4n8;u5Xxg6-VmP%Xi0qiqDN>;M0WJ%BSB+W+h z6p5h-vfuB^ot<6IZEUQ6pnk+7=mM0yg3RdkdU9`Xe_VW7TxVhklixW-S51`}+NR>Z d+Ixr@y8u>P6SCqpiBbRn002ovPDHLkV1kEiA;16t literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/bg.gif b/Z/src/nglwidgets/icons/16x16/bg.gif new file mode 100755 index 0000000000000000000000000000000000000000..808f4b245d18c30e13c973af60ac53d28cff3f9c GIT binary patch literal 958 zcmZ?wbhEHbIt} zp$r8n40QzzlbRT2b}%gHXIMCaVc8Uh71J2j&1TrVfMLfHhW)D;JDE|G!KA|334;u8#ko zd;Wi02ekkH&(r^b;P;0G3zjrAH2eoT!SR5VM@&nuParW->7ckVSDHzn z01InBUjjqNLna0;1|-?)JUISV`@i-D@I zgD|6$#_S59pk#?_L`iUdT1k0gQ7S`udAVL@UUqSEVnM22eo^}DcQ#T$MV~!g977}| zTMypVYEEQec<{Wow)_3;Pn#$0-_$Y1`Ry)8ls|n|+*IG0*Na0=-de=W z?WNTBG>qrfu1(32{yJNFGnFzL_6@M}g(^s_Xs{Qsoaz7o literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/configure.png b/Z/src/nglwidgets/icons/16x16/configure.png new file mode 100755 index 0000000000000000000000000000000000000000..5ce478b1adfefacc19d35d61e88a6c02ebe97454 GIT binary patch literal 717 zcmV;;0y6!HP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02{9W02{9XUK)`c00007bV*G`2iXAx z12+)F5m%`I00K=(L_t(|+KrN3NRx3C#*f?DM%ip+yqb-i;h^3{#n{|Ose_>C#@NE# z7GW2nLRnqZRk>l z!E^IGoWld>6hQ%)Ob;ZrwY8lTqK?F3D=U#m#6CX$#%MA3twKK3jp{=S3-bwzqR{g1 zWn_6|PHT0V4^ml84HUxVD;?&gUq4YYxrThci3GMzVQs_8wx>aE7+A7!I1H&&3b@>z z8%!qi9rhAf2rzWW0VzB{sMRWCC={ZTLLqRr7qhDNRaNlz?0&5`==X~y;%hk@XtmlC z)z#Ho0)bh$({nG|qLN>Ej>p>@6bJ+}b93`2b1k5YM55;Lw?1I9w}RI{3DeUbfmgwU zk`fL#FdNvgKDCcf%4E{WJ?36(INk6~Szl-8a=AAFK#9fNG~C_Y#rJsJGrheQ zBv;6hcfyN?hOCn~Qef@KUgduny7b2#PFv(s$3;Yx5y)(Lh@2zNPdMU39%!A08&{uL z2UAU&vxvjtpqADa^wRZWsl2>Q3i-Hgymh^|--2{HEh0%0sm`d7%`u#mNW_}#x8;FB z5JX#iH3q4425MvyP%7)Gf&RxmQ&aDUagOpXV6s?qkSO9GJthSE-4*}<0=h{= zK~#9!WzSn^)dc{@@z4K%&e_h+uIFq=%jRlhi`pDHEu;s75`r%D5=B@K77|LMhcYtB zu_)9aeCwfntVjt2>7mQOAXr+9^^#1|9GtD`ZtZrqbGCB}A8nt9-{Tj40h@h9LxO!V z9temQ$rQNw4io<8j=*th8yKhw!#7%Y@2*Yv^ax`yi{s-m!^7olE_Z&Nw~vw86c}Jj z6W_OP-`>~P->3c$VnnTx?4w_de8rShOxK5(ZQP zN|Z|!OC5~hy?t0~b6;C=n z)zxm_N=G8;IHwSVh$J|ijD%uMd4=Yrnr+*49Xe*Zv@SC@uH(%k>N`8dd%G=7PDs_) zOYq`*G)E4Q?%sk^EO23`--RVK`hNN^?k3WC<(delcw71NvYRrn(QjIEF!*z;P z2uhTT6iX}?Q+l6#4nX_Phs8U3RT`;kCQ?HTF$&>1CPG%%bL18opHJB{Fr;&U2HSaeDWsC5=5FFCVs!)oxmmJTNUXBK&;g!bWF-JV!{;2kpSPBY zt%j7V5fT=NZ_tEgE_}eDQKnIe0AT%Feu*)BAN9$KbX`#*QJ}75wan!|7&yquoBWFk r1U3tiK&qRTdZHuDlvzL)B>?yjfS~`FyINaO00000NkvXXu0mjf;$wU` literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/dialog-ok-apply.png b/Z/src/nglwidgets/icons/16x16/dialog-ok-apply.png new file mode 100755 index 0000000000000000000000000000000000000000..f1d290c6473dabb354d792a7724cc4d786e0d0b6 GIT binary patch literal 597 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH}&M z2FBeW%xLxI@gtz1WQl7;NpOBzNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~*BaQ29J1}sCcHRXtt1GHXmOGH)lM%P_}?T46j72hL`z}7OUIX7+O}{2xziz{THCiFfy5WZ;A{IDB&UcKSV;{RoH)Uf$$}Xeg zEh%MNlgsu*mLCYM+>uzlJFWgeM*RuXrem(nhrButRdw$5?mSlAbuhf^V07P+gudf0 z{U>84?9HBVFn{9F%!&8xCLb%9d?IVw;hY&)-Dh6tpLuD*tP>ftPFK%8nY-*l`L!VqTUG;r_P$YVDX-7H*P%?hDcmaPEcUoz-6%T!%dO3OC%>g6+NVstLmszmzt<>Qt7?C z&>Lmel#iLN65NIcr+@CUs@5)KU`=t-W%hANv3>KFDb&Kzily|<*}Xn@bJiRV-Knsw z^Od!vMbwO)D+&*u5x-n~!R%AWbGI8Bc`wA5oa}w0#u>{i7ZUz?lkj_IhPvbY2j=Pd RmjhkH;OXk;vd$@?2>>yI)$afR literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/dialog-ok.png b/Z/src/nglwidgets/icons/16x16/dialog-ok.png new file mode 100755 index 0000000000000000000000000000000000000000..c173526fa5f970742fedafc67792a6ac49a03c90 GIT binary patch literal 601 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH}&M z2FBeW%xLxI@gtz1WQl7;NpOBzNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~*bXFer+E;(Cn1#2ETprARAs<)hZB%ivkq+zI(k*}<2n5=1(lxd8Z zag?Y*xRgnltYy56X|R-`o4A34grS|ZiM_sWnU+hijz^}hTdc89xT#N+Sx}sHNWM#a zrAtDyZ&sCmR%bwNXJB@FQ2w-#g2|zU?O_E|qROU6m(7kYpAuU&Exu+&LhY=i+8If8 zvyvLtBsDKhuAZFIFekNfc3R{7^yc~LEpszEmSwii%WPkf-@T%sXGO`xl_gX5*3Q~m zH+xh4>`hZPomhS9-l_MwZNSjbEeY}qW?5Ge8Doi%V2}Xj<)unD+(A`pUBki?K%1+_fKtXh^3=d z%U2!QIlO20*xFv%sj#f`_3Y@|H*e3%C^&p(`h~4UMVl`?alE0CDe!3d(e5WKZko!u hb|UUZpNfUwJ2Tui5{OlJmjFsQ44$rjF6*2UngD(H)oTC% literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/dirs.png b/Z/src/nglwidgets/icons/16x16/dirs.png new file mode 100755 index 0000000000000000000000000000000000000000..b348848b988f8be3a171eeccbfd89abca7c8e322 GIT binary patch literal 1049 zcmV+!1m^pRP)Nk@eQLJA$C zLhvD|QW1nu1Qiwe0wCz9pbIG|(;$VCNQhYc5f5V7IDWgf_uV@b@2%gnf!G$ryODgP zE%sh%bB^;7m*2gQ{0_t(s-C&x-tFN8ApDz`h~)ULuBTJJ$tJE~scVw=LWm8)7+|=*z2z&b zbJ@3uqLKDFbz;-h(?&c#mUjmT8)GfgSA!vJVE{xpGYByV&?s1qd+$B_? z^~qeKc6YDbCuSr->bH%iq?v%AayPHsX4X2}?k9p-j^{$<1GCy~z8#d~XLTgZa=a93 zADE415eSH$SFr@sC`5^oo2A<4tf%i2rsf2cl4^HX)d~n8O1~8-3AF-3l@BacKFy#A zC_T@hq-hob5vg+DFQDfNQqnYyAVQT7Ja%g!0_85*9Rg;%{DG+5G>gC_{repOGm+W| zlt~0eW)p8!L49{2OHxX05tNaescui8rT>i>PiXhNW~zO`*=QAI1<~_HW(GFpn-m*v zilG^aiGwQa-Vf*+p3wB*kaEP(7d040ifM0^nUrEd6^JA$t=zhKquN|Qt!Ppr zlT`Y7kx?|M+FU=qa_i;|Nl8q`{HK98fn{L6mGz|}=2IdAYryBgZAAo<9C#df5_k+4 z96!fHp#kmyzXE?m#CZ27pC)sTF^NcD-u!+9lMh!pro?sfr@mvH2Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00!&;00!&<9(6c100007bV*G`2iOY{ z7a2C-AH01400LG?L_t(|+KrK2NK3O( zt1}KT&;|T(yOCwtC`po#_0k7ph9JvdOL^V;h3l;{2P{)smPaJXL|`(R!U9vMn@q;+ zw^z~I)5VRZcy?}fbNa00YRQt%#X%S&(MZ=zpTpfZ^$5qeH`waqS#O@X&Ms zw`tRn7yOwXN}hd>GX8`M)jn289%?QISxBuwU-kf#VSyA%jF1G>A++hoT)FFEUQwwo zQP5J$P~{x}4q!3nf{-NOa}u0>i0#f8pNHMtJT-@T(?Mned04GhfF)xm>J5w%nu5@m zs~QJ+*X_i1bdD|CavAj%l9rZ+#bN;oc5!lIL8@MUQTpt6Hc~)EKLdP1 zT>t<74`kv2DJdyE{SzimnbO?R-qO|i?*03(U%!3({v9Zuk&#hUR8&(_)78~AXU?2? z^X4sCvSbAitX#Qn-MVetw(Z`%dp{5y0D)u2j-5Pp>h$T;XV0EJfByW13l}b3x^(5r zm8(~;Ub}Yf)~#E2fZ*=k`wzh2(Zd%nU%h+<0hTZ(#5p1bzU)PZ0R^3y6OG27*5z@b~ZEfB*ggeSQ4qGY+7)g-e3`f*BZ@WE53& zOalUgb{s!`^CnQmoZ>Vkp!9A}7sn6@N!Ei0y$(A_v|fCF@29%hqeUINvNFZ=Tt14{ zRJgL-cbupdo6)5gWsqX@QO5Bc1H%D{3HitGO^-aZM4b8S>o+C#&8mqCS5w991qCe& zs_*SPA6+i&drt7kBe@m9as4OVSQsYFWn%pJU18OwnN%OxuujB|) eX2_bE_JjS4mZiJDa*ZD-ay?!BT-G@yGywpIGB=R` literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/document-new.png b/Z/src/nglwidgets/icons/16x16/document-new.png new file mode 100755 index 0000000000000000000000000000000000000000..8431237bd374e68931a13df798bc0996452f705f GIT binary patch literal 579 zcmV-J0=)f+P)VxXK$hi6FoGM6#-0&DYi+BPO7z*s9d>{0vUq8c z&G}94mG91_zoj3m9VHsT2!GA?={D6)mHkfz06td>m_bcrSPcMDDeJM*+y>fjK<#^t z=uU*oi<@Nt)FU+;02V?7_3H~3cIR1VuFMcTS6l_&FA2GV;y{3lgxXDZuxrZSS;?#* z=QUvpn-9RT!7#-`zX5oG|B7vHE(aR6zHX6znI;PO!UTD_B~KNw&}=sMyujCO=T4U( z2yTeTTYCpkegjtzCeCEM0NlE6vV;ClKoWLfLST%sZMP!Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L0B*Vf0B*Vg*50uf00007bV*G`2iXc1 z4FEa_^Swj>00HAkL_t(|+KrMwXj4%X#=mp#eSeZPjY$KHE1R;S|sUqr28v9=EyPo?@ho;`(4?Z58cfNDJ z`|cx5C>DzgQ55+A2>(X2_E-iEmW%_fwdr&^uK=8zUZAc&`DjKl5V083?RH5@2{xf# zufx)6wa{oZZfpH^wOS397jFi5 zy8anT5<&$iL7?8(0}KxS4&VfsPS9?*Q7V-X1Oe`>-ay$ug<>f2=p_#VfrhchkP|T0 zbSy!$**ubLZxCUWXb=GkuusB-=>*Q&p+^Z4ln?kNa4Z2FHQS$Ku@|)bV8i^}Pk?wI z1MTr9<-BNOX+6fAI3DTDQD!aAbh|I*(;ox%!B(~j4OjpG002ovPDHLkV1g~v0QCR> literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/document-open.png b/Z/src/nglwidgets/icons/16x16/document-open.png new file mode 100755 index 0000000000000000000000000000000000000000..eb211e2332d811f9cfcba08c7b5353298b1b02fe GIT binary patch literal 531 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH})6 z^6MbX=%g{b0w^e1;u=vBoS#-wo>-L1P+nfHmzkGcoSayYs+V7sKKq@G6j0HV0G|-o z|Ns93nQ-9LaT|o%Z#%Z%R!rHXoV{N;=b&cc5yP})hUKTM>dphjom;PZ)a>)_xfL?` zL1@dtj0s2brk*HT`lMpTv&t1u>ZWb3o4%!W*5>YQZ>B8WK6U%U8GBwYIQnVfp|?wp zzFB(g&9Y-}Rvv%1_SD<;r-A7G#xo!GT>iNK+Lr@2K0bc(^x5+l&tJTF`ReuSH*em& zef##^yLa#3zyAORAHm?$r%#{3;LDdUU%}uT2z>wk{l||VKY#xG_3PK~-@pI-`SbVh z-+%x90X@i}$DaW7A!kXDUoeBbjh+3kKY#ym=`)D|1$#VQ977}|Sr0mTF$apU9C-Cl zzp1lBVaFF6xtq+KP1ekLB}U1i9-K1Y4qq^5cyC_3>rTxQ-%05{ar?Kv&3d$_=YFhp z_Sz3$K3Lu?n>%yrhWkEF&#$N@sHAQ6RC_J%|MqFV7uRE!|Ni!!d&litp4W03 xB2RwV@}1{G@bb&@4By{A;bNGi!c-u0+X-bgZ;%;O*!ahWj|2Z1A=pPYR6 zabY=z!23TawVIF!aWI}%aHGkHt5;fJHk-k595nDe52L~0A%kfU#OCG;^|Om%ynMS3 z|D9{7K2r{Zq{FY(7~Z^|fvo?4&JJH8sgQW!L55zhw|_FYgX_0iQB_+G)u_i78QAPr zT)NqU`Be_TqfzjJ0D-7&upgq)WGYK$I9O{ekPJE)WD$7^;3Nro29#7*;M?~fa5x>2$8tWQA-fLJ5h@0-&QAMdhKI^r*7Q)R`-!6ZUSgS0Nk;FV1%F6Br4Ex~O-q~UF#W6)uSSFKU*=&~OaygdI=b5UiED#7V zzu(Woktmy+n^yt27-P`L?_TyKYG`O^fXn5=<3|rsEEjVV6BB)1U0p&!OY~6sly)fM z5d+!+!C(+>w;O%^cca!)i_PQl6zO!jsqyjg%Y2~^4W0z51xc^R;FF=RBhQ{XmzI_~ zL!nSI8jUvg^z^&}!JSN{R2tN}ALy?k9{;Nj3_h3!An*3>?(X&u4-bFt?d^4F(Gu|- maQJ`O`*m}~PbAFZ82kf6#TWb|m_-c$0000oc5!lIL8@MUQTpt6Hc~*<905Kd zuK)l42damIj*bpE8^{21Cr+HWdiCm6t5yNoTefUjvSi7+b?dfo-wx!iT)C2+ot=}D z)6dT@JUl!yGBPSEDmpqkAt50tDJdl-B`qy0FR!qqqy*@K%F4>Bs;c((c8HmiCr_R_ zb?VHSGv~~iGjHBPps_1gu3ocd&Dyn_*RNl{Y177S+x7r$*|X>1-o1zRfxzMY`}ZF> zaNyvC@-WoH=v(^7U)iZr-?Y`_7&F_wGHockkiDhff}Xz>}vS@Z$ON zmoHzwe*OB*>(_7JzkmPnjO#kpsqDJ`5TWvd1Mq?{NC| zeW~oS)XuQ}*|RU3{eIEkUZu74+D=`boAy*+9=^$XvFNP){%E1Xz3;fb gz7uWqIbiaUf9V4+zFSM)?FU7zr>mdKI;Vst0OvR^9RL6T literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/document-properties.png b/Z/src/nglwidgets/icons/16x16/document-properties.png new file mode 100755 index 0000000000000000000000000000000000000000..d79aa515177ef7252c144f87900e3c77b9449d10 GIT binary patch literal 668 zcmV;N0%QG&P)T6hRb*|LUG4ipy2(4j2_h1WCNe;6X2X7X%do zV(?;M)I{Slc*r3}BN&7X2BHMqz+m(uxI|I#Af7zvXpe!w2qw53oWa4dt9#~IujopX zG2mj3(Zjm~2>bxsHxg#NWw7H( z^m+3gm;()ZGC7Eq{$uow{KT3t)-Xa+bDm2FIB5m3W9*bFeDYAMx#N6LP2}2R-;_*%uN6`gR>nQ@P7BM zo#DH;uP8rwfGU*=sZI+3TnylF-|3SRJiWPxRYHi_E$dUCuU24!A&6m00000)+jEP)sITwjyZi2Y z^*)xFloJ2y!Sae9MUnmD^&227F&eA@R$!Q6Oz#_8A5bh72L`4Tgn@l+eja!4-G`ho zV4!{!lnKo*d%HONd1#+A;9MXKhnOwS;PdXcu>n0wD!}vlB9bK0ch4CJ!F4fCIG(NE zN;{-f142qY{cxo2=(}uXX*p%yAZA>|EQxswvzCpU^>sX1s$%oiI)1q>jGVdlKjuBf zjEA=u;0IBffO8m^Wq!Z8LD6Np7i4f*=2PFNn$!se7dnA1_D>`1eEp7GQVngSnDYcb z4i3mv;A(k}&SFZy(*%Er>(S!%alceksyV^zI9Jeaw_({fj*gEh!5PB4w=Y%tNy+Rr zW{%@nt@VdZVx2&M(?Kxsae*e7UDwt7{r#po8yJd%{sVk$d_t$wfn`}Jl}dTz!~KheI@*O*FQ*QK?pOqf$X8r|h78asoSL&Kh$WoNNcaZ+5#~ zgh7CQzmHz8hfFc0iwTjjlzCbP89wd)?(KMnu~K~#9!os(NgQ*j)}Kj&=erZ$hYk*7#(3o?udr2AMcyNK0O zVi$|9^R==@7bGaUM+HHJy+m{`4Jws_z=CcFCEYJ}ql>j_bJOiC-8rs#Kwb0_ec}6d zz8}87@1G;Y<8l5))obKIdC&73)JXJAKUpr%udejB1l3QGH-(y;BMH7W(hJZM0992H zMOa)o3IX&cuNte!wLGP`q67cW@0{J5Mkr+(x8JlRG8zD4PXkTUXpeRh?Nm_`e*e6d zywu~AZSCaU#{fsxn;|Wa#xD~vnau$7ouFxYgKz?H{@OiKWAE`yeogrwmGsVy0bDy}|6k^Hr2=0P(E;h{|f5dPK#=E+| z*PS$?hNh})TepG(-l3en{*|iJFDS_UOj)6k<$FYekp>(N2XCJ|peNHeqLv_PoormH zaqGq<_MXZjcc70Qn0SeudkjHE%(_&(u=Q~&L2%M;oVYAtAI-P_Hxr@e~noV!m<65F1LMku?h>?!UBhs3wg8QWnL<#e~D*UO*%g(SuP%(MJa`_A_N{uH0G0 ztg#mLY`xFuE-GdDN&^6aK!9X@X=wrCJZx%0G>Aa}DpnOO@|28obpMtAXvKK@k7Ytwo{YB(9F? z;2_0Ku;{F~yQsL?!9iy?1;;|c4%SjZ%{70TwwHKcBH=J-%EN&+{;d zhN(E7P<- zOhP?!y}wyJm`;b*`kqJvqBiX|nL~L2fd*Ux1d!eYF6Tbg5P<9ZC&&uF5~UDVJ~Kya z$B9GKW9yGCk1)gXRIvtRXipPk@<6(R{ z10;&Qkze=csdPHpgO1qUX}3Wtm&>>~JBMXkI4Be#D>XTZ+DDB(A$cT#*xhj)kQiey zO%sM;K-YE1@`TY9(UZv}-m29|6TcYK$LKUNox!$kO4I`&Fl}aA7Py>1;e44jn~%EA z#v7jv1002ovPDHLkV1jI` B^11*3 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/download.png b/Z/src/nglwidgets/icons/16x16/download.png new file mode 100755 index 0000000000000000000000000000000000000000..d0746f6637f91b80648a44684017b096020c2fbf GIT binary patch literal 901 zcmV;01A6?4P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXT6 z3@0|{X2oLw00RX{L_t(I%bk&3OjCCl#-IN=2iu;OewU95XpxqRb-+N`05_9em<2Rw zLZZg6L=(MW%WkII%wQrhaTiO}Eb&H{UF~9I7u#;OOcIE%+jLu8@JG*wA*XuZ6zE~n@xe%V8iQh>H z*MDJP1Z1B=d+ZrND6vG(~M(T?tIet0R$( z7cdsH;WVRX;c(kYN};HB+aQP;MAHSx3=7V}LoTl2+{Yhao5yv2a|T?wS?~LOB1W6u z^^thG2%g^pmZR9YvkKvO5?~mZtUR1H9$WNfzRdy#lu*hNj0K+pEQ_g_i2KiSSS~SO z%{&;B0XiK6J=HL9c8}xrVnhFTuUc@qhi{o1>;raxH4HTlcy?5xuA&@c;TK4YS*%GJ zoN9Gp^j-wdQ~8prYO+zs%!PkE(+L1vS}cCgCh`MZTA?n!jO_DQpvGxLm$w2Fk>{A0 zibB&$SP}$$eX*NmInMgg;IGYZUMMId50#bt4VqI)WHCi2V+ojaWpMHg-t*YeR%Zh( zFwk-$ot<02+}u-Wxx{*igc(9|Rk>t(BG9d7<0rC|hs{XnQd&h)%8*A>A?UH~p8rmsmYwW}SfwR_s%UL|P bH_l!Hjq5YnqXgLB00000NkvXXu0mjfZJe5J literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/draw-bezier-curves.png b/Z/src/nglwidgets/icons/16x16/draw-bezier-curves.png new file mode 100755 index 0000000000000000000000000000000000000000..a77e19a4835ec660ff685dae2bbf06d3c06dfb61 GIT binary patch literal 540 zcmV+%0^|LOP)gJB%Uf6r@w?0vVk`BU1(K@JYwD3`fR6c?ho z$btO1xKRqjqSyhag%g?_b`UplP);kQ{5z0H4mi-vYc2NpKCRWpyUo7!>G%6R-{<$O z_pOI<&Phw7!Kevk5I8{%2!mU&zR*#)o4m(Vq777|iF0@IaA5P(g|Y^Y!45b9W>5_# zzys)7={CLU(Ae(DR#C-96wZAgU8`y(&bC13cE5Z?={koWL|p|w&_{_+7%Mf9$1D2g z#fTqFi9QqXEqY@u2kC~9CYx#}o`dysVYisGkqnS1MLPOAy$&*M6?l`SzgEmIarnG9x!b$L+}2b@IVXx#Ra8GET=5#NL!6q eywP-iz5gErFbtf4rJi5_0000oc5!lIL8@MUQTpt6Hc~)E9|C+r zT>t<7fA;Lf6DQ7W+_-tmmTen0Y+1T=<$(i7cI?=*cI^hB_{x=QfKn?~tX;Tp8AKV7 zT(Dp%P|e)Ai-1x({T}zJ2@t z{ris}KYsrF`RmuO-@kwV`Sa)R-@ic5h6Ty*2l`#MB*-tAftiJi*U}**DmgX1bjI8b z2d>?@^WfQYpr${6{(arb_zkFViKmNWh=gS6!9>494kE1=-|sV54(@i*R?Iu_SKmh{ z_h?XtHNUX%|3bbyiXYt@rslM+JQvJ*Fzt43P~7v=m*(qrY_i{TW~}G?vG>MIdpv(mEQ~v+{XghYpLD<$$Ei^XFG0zM!PC{x JWt~$(69C_ZQ{n&s literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/draw-line.png b/Z/src/nglwidgets/icons/16x16/draw-line.png new file mode 100755 index 0000000000000000000000000000000000000000..f45eb91e50d4730a9b87b3a344ae67c05659a207 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH}&M z2FBeW%xLxI@gtz1WQl7;NpOBzNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~)E$pJng zuK)l4mnr_hneiTuc(dMX*M9Wq{{kd|Y`8d3nPuB2AR;E8Rj2S4uGeeA?{%VQsZuRf&Fr+J98ZS#={ f#{|3|truT?nCat_+{#rz;}|?${an^LB{Ts5ELDq; literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/draw-polygon.png b/Z/src/nglwidgets/icons/16x16/draw-polygon.png new file mode 100755 index 0000000000000000000000000000000000000000..7125d33abdc8cc5811f4cab9aaf7883b580fe38b GIT binary patch literal 679 zcmV;Y0$BZtP)@6E@Xi5s)BAYGW+jnYk_74kC@0>!Lq z{Q>S&@He=Y?p@4alSPX(AZF!K5DE=7LjyI<#7R4ijmfn0^}IKB#vzhkxZFE4=bU%$ zeM5v0bF5w_zBW6ZQJuqtR&mg>(HY^y~9*6jf%UR@;5fn0U3cRN#^%(RSPN z0Jj|k*KaG8N;F3RPp#((k=}8xuCA;+)-_EdaU7E%2$*FZd#>w#CnSDWDwXX21WdD5 zWQ=YvF5bVhy!=qXcSuHzEX$ly%1%#vSBHnK%P@>yY;08aryp@qgTcj1=r`BaR<(To zZgxo&Mo^H9SQK;|$2&M^O+aMN^DbXg!`OKbr1fI)i4I^AMbR`7%ovkz$PC3`6dyA3 zeV-g1wXe_4+zyK(!3u>3dM=kEV0D@(BtcM!n^6U11fmg$5>-{n!oocs$AU7?^GwU? z{03}7#!9h=cLEayz*T@`#9{6CohvY8FwW^G+wQ4h7!ruA1A&QPJRL<6GFIE}!>H^d zt5&Nc&b4pdZV!R8B1o9phnkXy!(T*El-}0X({A!78Yd?|#^hg!jDr{jXYBj1*AEC} ze@_$**r<$~&qU%PhD=?di0fX2u*cn00DjM*rty~J46=NInI&V6#}lZ`EtkukQ~(36 z#IWt36KH2e&~|#o=jSfmhP0FJD`|9H-iI;XG#a1DZGqP+%W6G&{sYr_H;MI>7AOD! N002ovPDHLkV1g7DElL0Y literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/draw-polyline.png b/Z/src/nglwidgets/icons/16x16/draw-polyline.png new file mode 100755 index 0000000000000000000000000000000000000000..35d7c0e05d3e8d0a5e2b06a7773e1196c25bc180 GIT binary patch literal 529 zcmV+s0`C2ZP)*oIL)UjTqWL!)6YDVdB16h*l)jECD&spS0=002A) zR33)NvMkc+Lp2y&KlA(5XIIshmls{5)8-XBoYUKNMvUh(QE3uk^Bw7QRXBz zDTx{Gvk{B-9?T%4nJ zFzyCnMyofE9{~j=OI#yLg7ec#$`gxH8OqDc^)mCai<1)zQuXqS(r3T3kpe1u>gnPb zQgLhUL~E|Y1_Cbb^2-Y*XD|8q)K~AJ+S1u`lw4UR{^3lPkeR~E$lt;0`FYFcqQeE% zOc{kf{WFU5cE4lFiVZK;J-zAbvP^;GmhW;)MS33p^VS?xC&Z!bRB^k)vc_TF{x*XuK=%LG?3S3bD&h+Fk6Fo+l!JYD@<);T3K0RXO_ BiCX{w literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/draw-text.png b/Z/src/nglwidgets/icons/16x16/draw-text.png new file mode 100755 index 0000000000000000000000000000000000000000..8db19da057d7c14a421616d94c5e04bb7791d8fd GIT binary patch literal 465 zcmV;?0WSWDP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00VXa00VXbebs`@00007bV*G`2iXS< z3;_%nqyXUn00B`+L_t(|+NG1dN&`U@h0kmTf0F%+V42Pr5OjSLo75t{gSDk?9zat` zAQnQ9fYuvSti>h~t#$)Z5zXvg=LQBGW5QxSI1G38%;7N1f;qVw5DH`aB{Y6@9Xs2b zW7l7kLI^NVx}C`unO1nwz}P}Ux<%0cIK$ea1+P~XtG#W6N1}sCpUdO0^d#tqI zx&uLkPH*ts=^a=BN-0PwVQ4m+yu9oa*#QukqFgTPW*JJQ5^QY0#0-YR;p_ku2uRa( zv4A8=_$}}o_;-WF0=R*BiSzg~K8hmA0o;OBtJPNKHprC1502tE-i6J*)|uAfZ@)Ob zexjx2RmEYBzVV7100PtSkMuS|o@G2u{9m6Rn7|<@jP3shw5pqIO^M6W00000NkvXX Hu0mjf6E4Jq literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/edit-clear-locationbar-rtl.png b/Z/src/nglwidgets/icons/16x16/edit-clear-locationbar-rtl.png new file mode 100755 index 0000000000000000000000000000000000000000..6c4b83b7ac6e451f461973dac0c9a6c53dedef25 GIT binary patch literal 644 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH}&M z2FBeW%xLxI@gtz1WQl7;NpOBzNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~*(*`Bv~l~6?FSDYJaY8Nv17;1UpRl|%9VTf?mc|? z@cHxSFJHcV_3G8zw{Jgu`0)Aj=PzHr{QC9l_wV0-{`@KR`o0Pn77`^ve!&d#@_Ksq z_8}pusXI=cy7Kht(+?kh{P_EqYvr0*Ks9qcT^vIsBJkEM|1so z>*;dxIy;s3ojI&$kq&AP_I<(sjr(m{G3O!W1aTUgGKN%6@}cL`d0sS5o>yped=IE{-7;x28@w z?{(Ng;8?o(vZal2UCV9SDn2q^kz14h;ArvQ8^O9iIQDs;w`*7+VDp{f_ZlWKjr z)#jWRvnDK(uc_Jn=1hKh7{h^v8aJ_m2#-3&dS~D8ALfP$ET*!d=Iaj$ESaLv%HXJJ zadX**`|pc8)DD~|l;Q1I%+aL4pv!&XZJDLtiIt|8wDsLQZsnLs95p=my!g*?kHg2f ze}skYh-*HqEXlpecGB}onN3VDlz0sp?)p^E4K+@`E$^}V!kg~`uY(tgCWzj2SkAUA zhv5~wSpvTuPll7r+MOC)9ESz0WW}p&`9(OEY-(cc;=5QH8+dok<}z*b-~0I2y#2;5 zm%ceYifxa*+WiUnz4IqbQQ=IBY~#^CEhHY#9paTJbKGK|^!~uRnp-kXG?@4ro-by5 zaqMZ<%Gv6Zf0wV?sdn1z0IR9imMNmDb$a0zwKG0V)~~O%Gci?|KU*m}BkiApw!tmN Y4DJ^lh1J@%z&K#=boFyt=akR{0F^SkGXMYp literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/edit-cut.png b/Z/src/nglwidgets/icons/16x16/edit-cut.png new file mode 100755 index 0000000000000000000000000000000000000000..f4a55e3d8a9df86b0da8e7377eb4b21620e42580 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n2Mb|LpV4>-?)JUISV`@i-D@I zgD|6$#_S59pk#?_L`iUdT1k0gQ7S`udAVL@UUqSEVnM22eo^}DcQ#T$MejXb978H@ z<@Oq8F$Ida_AlUg=iqzbmh20?rl|@>J}bFBvZddo?kbdj=ip)NEYWoIwxfrjspE&I zf7kzXeO5gCv;OnD{r8;bw;$;L!puHH-#BVsl-uWB6J%O8F5eg^B)IOC*`2?k$%mE* zZGZSqJ26OnS7zPD-qf;-Cd;FRd6qBT6YZ6_>Ilp2AJ^pTp`U_QHfz-`{!$52l`)9UY%*8-9&1?@*h#)SHUM zk6ZgL_O)%DJ$u9RPC53rhxZrmt-AK^znEXmL=D9W5yeH^`@hV2(!JrW#zdgk89ZJ6 KT-G@yGywp$wU*=n literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/edit-delete.png b/Z/src/nglwidgets/icons/16x16/edit-delete.png new file mode 100755 index 0000000000000000000000000000000000000000..d04a554ee17853a053c7c6a795d6aa20ed32aa9d GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH}&M z2FBeW%xLxI@gtz1WQl7;NpOBzNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~*<;sHJ( zuK)l4Z(v|p!N9PVfuWs&p^JfGA_Kz=28KBd467IzAX4jDSb*GiKE6H%hCBv_Tn2_L z28Klp4AZo=>*d6nRHQFelpgl-Jed$XS6*hniPlkf`z7+iOXNkDC`v6+mRl+(v`kK5 zwTk$9b?ME9YMZs?_j%bL_HsDk<9sU2r$Je2`?nP^4n zy$lTd7#Q|j8XpwoI%I5o$k*ermDN#8qhmrm$Ax%K+S#3Uu|MtSb;ix@0t3SZA)d=& zVVA>0E~h43Ns7Cc5PLm2@wTwQZ4try!urld@myOUR3yfXZwfVuCELX$$gHBz;HAv3GxeOFfuao00U1?PcLu(fWV*& z*YDnY^6b^8FJFJbz;6)v0|bBn{{8pwYTmshp#C|YE{-7*lD!9A#hMrxSP$@P+)yej zFHd4mDu4d>{K5|<=Xn;eJT-f8`oR(f<-O;7#4aq4w-XY2{jJDX@@(tpr)jM&lV@~v z*Ho&Vn=Ex=#*GE`IlapY+3ZWUT+T69GWmBUabMW;!&!e;{7GJTTlg5GXv(e!RomBu zh3)n|!O~g#f1h~dx-S*-ITHltB~N4Bap$D7gPVoUk4G^qQ+_ZwZx+t3%CQ#%x|6}v L)z4*}Q$iB}L2Ua6 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/edit-paste.png b/Z/src/nglwidgets/icons/16x16/edit-paste.png new file mode 100755 index 0000000000000000000000000000000000000000..a4e0a02fdadfe5f865ba960d84025ab991ae92bb GIT binary patch literal 529 zcmV+s0`C2ZP)j6lR&1TgAAr&ZD!k+qP}W%jJ@CJRS#CRRM9ND9TBQ-xjmkjMQ-h5{U#%r&Fla zYOo82VSMr$Ij3T=SddLTjly+Z+O#GUI#oqsWi!YTYX~Mp1c=N6n29LEN`M@2&z|S8 zz?K6UxCItq2SjA@zXAxJ_(ltgM1XRn1uCLIxCJIj9r$!Vb_lQ|29qtzg5l3_{kb(5 zjm9I~{uX%RpAOcb`;j_K(Y$)So_lkBnZvay{frS1X+EDb*~^{h3eETC3$-v9491ub zaDdSvvJ-f{HKXqXOVUsMh>g{Fm38Z8Qn zsEFDGZQ8UhvUNerpno7-6$Ig?O-OCZAcUYVBpM^NPct)}nS1ZtxpU7wZ`0MvMd6|c z-o-iReV_ANoI}ivrO-8MC!*7qA@>qQmmn!jDPFpPe?QXt2KV#F#lAKGIuXP^yGsPkXpA4yj=jcrVLkFMzX$T>)v3>(A z0>~ho*mKZ;7WkFisNKFpkhrij*O{2|zQvJWJL8xw&4A{a>&!ajSBw!16Wh}5NEvoK zC|NED0G!F#E0YD`0s-*O|Ag{eN4u^cfG|`#|c1v ziImB6L9trVfmeq9Q3zc~B|y*%2^gG<()vw7mA-q* zn-jCqDiA;73-NFcz(CLT4OYO+hBg329O)`pX$59wphhVyj=2=fYSzViZCdz){8=N< zC(U@J5kR4Ys8$LEL>MptjEXsSqf9goz_BydL^&Uxrz_OLmv|IFGin?d+-yuWmB^1m zHF;>Bv50{JZnCBHbo1MP;Wz0EAXK54)Pxl|$9E2%NB?_cZp~4ajOyOqe zsAJ8W?5|$3;xR|DNig)WhgH%*UQYyE>2D?NY%?PN}v7CMhd7%J-{c# z_5c6>9WXF)(u7^Rb{;r*;ONn#7cO3S^XARlw{PFQdk0jr(_cj#sD-&C$S;_|`i9?` zLLiU9(9^{+gyVX0f&vqVWOJiZ^RG8|9X4$4IQVMDaY==UGYPe7Y)5YNv@(V>UuQLE aH)mjws#a^|o9@yJ((UQ$=d#Wzp$PyKYFkPG literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/edit-select.png b/Z/src/nglwidgets/icons/16x16/edit-select.png new file mode 100755 index 0000000000000000000000000000000000000000..e5a6e33974ba16cb15a6e08713b3bbf2f6fcc79b GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf67>k44ofy`glX(f`a29w(76TPu z2Vq7hjoB4ILG}_)Usv{<>{7hSX1uHZvIB*flDyqr82-2SpV<%Oeera045_$Pdcjto zB~YaOn~RZMVV z&S5u2sn*{!j(8j8y_-De)t^a|W&Wm3I@QYAyXS0C#$tA5eN86oDeImnvod5&k(LW$ z5z?6*!dKV9-DmNvx%823<~`Q=F-7M%->)&;u6;C8VCjQCwe%~M$*ozwdKn*&@O~9} zcl*aZ+k@KrHkY1UnI<{w6#IXrUTVEq(umzf2d|J$AGF|HrM{0LOS~m0q^oYKY8h@9Y|M83@4XWHY zECcUdwx+H6y0*Dw@~Eb3Ei2<|uWan=tLI~$=WkaMu7g5T-YL9`nX{*XHh^>zs;}ePFs;~PxDud5m0G&V*hkWWOq-{Z?)8y0!<{$YI z7r*@s>}^cUXuG+C)`o3N1Ja_=m{~5(AJK>aoLmxwTLg&?1e;r-aTQ>59ZIIjTm9#~ zgRxd;wbh0^^W*DuIh9Cxwq0xrGblT3hvqIi;?wMeJM;dfOn#h{3u#W0A{6fonT)ZU z>dY=xR+cewR|NHc>YXa-q=Fc3yA!i#|2ks!VJ?SiT6A(Uni zHXU1_w?nHjV-s`BcBHMbmRZOfk@FBb-29pMYNm4HwrR?~s$eHL%3}H?zh4$V6F{d!s7&8>3Hq5QWDof7Tt33K<8dCg)0ru5k&9s^DKt sKJG!8&0P(;2>*xT4ebXW2R=J?Uu^O6H-EjXt`-)6_k+@X7eV>2fa3R8 z$>GCGu8z=02V2(LS{l)@7T*?)#`b?#+n)o zyLORMRU8fnPNx%5=lJ>b)WF48)<5osERZ%RA*B`QO`Q6)Wt;CS-AxgaKmu4Xnb?2) zIPQJ>&@>He@lWHBTO-+fWX>teJttq*BcCRdl4~dpI zFU8yqN&eciak0twL=c}vcM_%A=b^La#iApT%l%}u+0g6t02I?dkRLz5R=Ld5LXeHj zILbyGOT_~QXYcsi9*)%NfHuHe*2p8eL?SXjKmTJcm%Du!n-{aqfyH7&%U(fE{(_qR zjRK_@YuE0dce|h00pA0cGSdv|N=l3q6BGT>XmkTWF_clP?!j!eaZkCG>E8onmx2`5 z;;dWta<#4P1|oup&;YfcIGuhGVQ6URR4f+zXA4CsTq2163k|-|v5KWMo8=$)qeVFH36rLy66e$=KM~x!&I1iaR{T2d~w*-5vLO zJhfY_)^atQRpY_nY~=d&q2jymG&`NHMtikAzM5VAE*uV@>FeveBqG{o13rfy9kl16 zQnzCV8y3s0R3Z@>PNmL$3k!O^eoLWH;PxyCkOx+PB_Q)R8yT^+u=-nh00000NkvXX Hu0mjfBqq## literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/format-justify-center.png b/Z/src/nglwidgets/icons/16x16/format-justify-center.png new file mode 100755 index 0000000000000000000000000000000000000000..2de15bf86600fe1876431809fc80f04e37c0c7b8 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF+I>`7{YNqIiZ31YJfmMLc)jt|G$?+&thh7-eAbVVUWPQ zN?@zPRdvTK#Z?bP0 Hl+XkK2c>H> literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/format-justify-fill.png b/Z/src/nglwidgets/icons/16x16/format-justify-fill.png new file mode 100755 index 0000000000000000000000000000000000000000..a7e111fe51720043274ea4d7deb46cd94bdbcedd GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFGe*XOV=g*&i{`^r;Si}QV&s-AZ7tF9_%eKom zz5}_co-U3d9M_W*8knyJ2m~Y~e7Lta+bwbyGjsC>Lk O7(8A5T-G@yGywqqOHsuD literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/format-justify-left.png b/Z/src/nglwidgets/icons/16x16/format-justify-left.png new file mode 100755 index 0000000000000000000000000000000000000000..53d7d0996d923335dcf20f907e15e178e56855a2 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFYCJbI;+N%YDFZx7W$#^5+21#TbMC1=MQwjMZx8TrO9*v9Ylw8LXbuK;>*b zTDj;~!QJv2xNq95fkda%U3WU2{L<2rVtRV|0wKf*g!F<$dJX_OYstL|0+LG%xSKZe zI14f)^Lo9{Y&P2;3%$scSPUovb0Bs6slH z8#8bm=h0|1*A^BQ9zupbkdb0E&B&w-k3&cUQWFdY+YAQ7F^k3WV0n4D3}gL;g@ubg zpYLNvk5fn;QXsDI7WsrsAb?HYc|4xWjIqUNG@6f7jH^_ttr-ob5HB*B{D>n!O40e% z4eU3hgp*v=YPE;s@wi41gdeDb_--6T5h6}*Lc9_zZo-E_*uPDRzy^VQ zP_M0niT8t%^MeU7@&Op~z3KPH0>#!x~7n>BQ%yR z%i?&cG7%$6feLE29#;#Ah$)ftlMtfCT8i+00aLJ&&a1i>NB{r;07*qoM6N<$f{zkz Ae*gdg literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/format-text-bold.png b/Z/src/nglwidgets/icons/16x16/format-text-bold.png new file mode 100755 index 0000000000000000000000000000000000000000..3abb164d1f5926973993f0d9df78088527b7d6e9 GIT binary patch literal 463 zcmV;=0WkiFP)MzCV_|S* zE^l&Yo9;Xs0003_NklnODn`-6o)5Mc2YL%eF0y8V=7IMM;pNAZ;DL|4&f--cfQqigniN z_i&UH{YMl9Wmx+uvBXkYh*z?rH}4YsYTb)zrs~5IGo7x`J#=snwHQ4r<}2f&AWsLu7nTO zl`UKl;~2Yj30YFYP+i(Uk^@e#Oi?he;gA!CRa{qa`5v0JUXrhaNj$d-l zI2Qa9(7*Ak44ofy`glX(f`a29w(7BeuI z$AU1UWP=-!!N6YP>FdgVlUZ7Tk$GumUlUM>DaqU2h2ejD|C#+j-UUw=#}En0(u4c8 zTNq`If9&5B;p29AE!#hV(`#Qfuke=q;~`lRYdC|iw3)};{%D4X=B|i$uTH-5+rc`! zn&;f)>e=h}#p!3Bc$xAxY4cmrzv`B|7oUE#-CcC`^4NJZ|9|L6VqaQRZ~1wS((mV2 zYs}+icRVh1En}0NSFz;FYfjf|`QIy+H%fQuit?Xa@mTlhoI4XXw{dq>S=$jEo?>$In5nDH+hzM}-Y;tV a!?^ZT&PIv;8xcUiF?hQAxvXMzCV_|S* zE^l&Yo9;Xs00038NklY7z1F3DAAWTA^2p3^&l@b z8VA?B=!4eG5*_Zwz|Rf$Sj@E6Y>@})5Hv1%VjHt=Ce4&NKAKtLYpqGHiMMM->B+WdQ94jnf$PzgP8NU67 mywjz{qb`GjluPl?p1n!(VN#;||?eg=wx;!hSv z2B24TKqi6w#K1P?KzqOnEwT0!?iULJOcdOgWGP4p@Nu`XESBQ?cd@gCghfP2$SS&Wv9q!I_z8$e$tk(=a&vNUa{CL5%gC#` z3h-$0^6>}=i%DuJtCtE1Y6%L7h_6*t%hHk%6LoV{RME)tl985?m6KOiJL>7Gps1v} M;n>B4o{kLG0GYUAZvX%Q literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/go-down.png b/Z/src/nglwidgets/icons/16x16/go-down.png new file mode 100755 index 0000000000000000000000000000000000000000..5891219e49603b6409d5479247ef1fa8a8cf71c2 GIT binary patch literal 623 zcmV-#0+9WQP)9KeakxIdTpje7cQjq<2c!^ z`Zm_SltDZPAt&#frRYyLt2KB&-G(%{q(iVQLTLEmE7;x%Q2E-zMx_cKcr*5=`6qt_ zJ8$Qx>E38HYSm`*8wpg%DHAF6Ak@qu=tdr9ZV&@0hK{|pLTM+EAS1zES!j~^>gMV) zSJgD~g*+^)fTA^sp+W%}T|?#b>p<{m+*@08kigJI_+;7}FTlfl=m%yDpG=!Ydu;Nd zxN@f?(x%l?jNxPW8<>{Ae&FyaVOl4ItmVe>FR)CpL^X>&_z8O)@9BsigdhL_002ov JPDHLkV1jC@76SkP literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/go-home.png b/Z/src/nglwidgets/icons/16x16/go-home.png new file mode 100755 index 0000000000000000000000000000000000000000..aab6a883e12d68057250d8cddc2f449edfe897f6 GIT binary patch literal 935 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H3?x5i&EW)6%*9TgAsieWw;%dH0CG7CJR*yM zqGce=SbMeU3{X(A#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDFz0{LjgV^ zu0X~A|NjS)L;_PAJ2x*cJrgq{3kwqqD>EA#GaEY#J3AXECnq--H!lx2FCRA_9}gcd zFFzl@06)JVzkrZ{ppbx&s3t#CwI-NlO%mt&4Qn@d2W;yN+7ZdR zJDTxu9Mh3w$Brg49zA~iVwW{re9dJ$mr?!NbQO@bvlf=PzD7fBEvwn>X*?z5Dd()3YwVk~K9A7~u2g-@pHY!M}gX;$^^e!zk_P z;us=vIXU47mxO?it7^_6uB=yHGY%EqTDR`jr=DkKd?yYC&AMk=Y8SOha&M@|p-I2q zrB0nH`mSoBuP#R-C-41hc?ucdxASN>aCb*nTs3cYY@Qvd;1hAgWI?@>h|dRO!B!4# z$(Lnc4meKlTWH`Bam=gql8A~y_NQ;3D&n}#W$KIIrF3u?{bDau>Bc6ocTddE~A(Xyf< zE+G6CK4;eCypf5yV^i~IkIkJqGH-Hpe0Uh1{Vh^Cl_$;%${(JtelF{r G5}E+933O@z literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/go-next.png b/Z/src/nglwidgets/icons/16x16/go-next.png new file mode 100755 index 0000000000000000000000000000000000000000..a04c99e2544a55fc0e7a0b2d3b33939ad3644f86 GIT binary patch literal 721 zcmV;?0xtcDP)-QyBq8B=CC0L~nB}pY&r5r?n2O2gdSfeRirxGq%C0L{(Pm?25 zoe3K^Bu8K)QklWe9OLnjyM13buiwGAh z3LQ8LB18)#Mhzf64<<+uAutgqI}$Ba5-vp&E?E;YVH7Y|6fs;CIBOO;ZWl6D7%)s2 zJ8vF8S1U|?ELD;k_ttILqC%8{_mld{j2w9uEe(V)NAro`I0)#v~J z|KYj7cK`qYCv;LyQvd(}0s;a90}Bie85%M+O-@c&ba;=Cnx3Spy1m%k>g(tyM)C7|k8r{la5Hg1p_F?B)3x7&sNRG&R(9lcNH>?4-Hj z?$FCf@KF|KMmWqM%SDzK$)T)P7UCSpE@zVvV88_c7XcqIKS|iV00000NkvXXu0mjf Dy00sk literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/go-previous.png b/Z/src/nglwidgets/icons/16x16/go-previous.png new file mode 100755 index 0000000000000000000000000000000000000000..940797b8a588cd4a74ce79ffd8c3957041c319e6 GIT binary patch literal 634 zcmV-=0)_pFP)Btj8dji$CWjoEB=citM4UJ9wN_<`s6d|`$e{40W==$&{9 zA^C*lynEr<+3RRQ!!~+OJq$DV`&~|Jlal+WYZ*|`LUMdAQ(v4<>^3H^oF9g_zJ%>) zTNj@wQi`i8*!1zCL|`!63j)9|fBto#XMCRyC2mQOz(B@nay$w+%P9Y-(_fU0Ux6r~aPK?(uRIVknvdoE^f zKESv69MQT@&fd`#@8ZE!l*D5p)M`E$1GE4(Bh7#i5{z=#wu^lJ12}V=M-bEj<337j z1VI%D?*NQ81wo-g)i|Uipj4ph_*g4dP$(>8rT7(sHUsMV`{yr=UD-EFAD54QDy&$x z1C(vvn2OC{I~6M_;90gBeRM0fFJWXnt3nLa}#r&B7#jeXfedf&hSgiI4NQzzi9<_UgR zI62a9?LGW1J#tB2yZ>71v6TGdzhLeeG$r?M3Bk@m2zbS}1b;)1?;q8>GCBM&8?MXX UHoH%CfB*mh07*qoM6N<$f(*zK!2kdN literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/go-up.png b/Z/src/nglwidgets/icons/16x16/go-up.png new file mode 100755 index 0000000000000000000000000000000000000000..b3d9cef97e16ca46909765c0a67091c97908660b GIT binary patch literal 672 zcmV;R0$=@!P)0b000McNliru*9;vE5edJ)+6{olpPkPT$sbOg93kgUk5S3}N14Mj zJ9`2QPnU^Q!($^(CTVNfnvCJd_^zB_{%mUB`TqliV3)SpD2)!M;I1`LS5+JxL^j zO~OgoFbrKmJg8}SpP#!u{Y2f#ZY)Tn8ycjY)X_29v1zB_c}-ACQP&!9y++%+cK|hQ zcVTYU5iEd=eDJ6R!6Ub4fC}%BEHs50WXy+95J(Yr%Kip{H}1g9jtZOr0000+f;K8PVh9!*!(H4p;$7};_ilHbUDwTN z?EK+lhc`R_y!UuRN-6x01pX48Suv4qP7`BO!vpET0O+gyXuns$BFJ1;k4`)2(jOVn zLP&)@|>CnmbvB7Sn((ujcbPt6Ul@NW0;qQtu$2F_1Pn zdL+kCE`>_XhusKJI@B)-#kg}{W z9&uoQx@d3IrvW^O3=C;bfeTc%K`7r3&~Sa+c={CK54R{p0ZhOU=EcOIP2%vo zY8yFAz%)4AmW%4$u+JEjmSXz;(N?9I}Yocf`GGok!G?x%fYd3ANf{pVvMA_*YXg{cv7nZBm2@ieWNras&G3D272l_l(i Qb^rhX07*qoM6N<$g0$m2kN^Mx literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/help-contents.png b/Z/src/nglwidgets/icons/16x16/help-contents.png new file mode 100755 index 0000000000000000000000000000000000000000..b3fbea8c5ae0d1f401f4ab31105107d711bfe35e GIT binary patch literal 684 zcmV;d0#p5oP)OpZD(l(H1DJfC`I=!Gu9V!r)}0rt07# zi-W<$82{6Jl0F5e$N49I?XE4}pO7?(2G18Ra__-o{)ZRE6`oHo zjsd>~>vPr5^W9v#a)GdKl+4Ht8ezn4U}>YJ6W=2M!k~d_)cXM>Ek5RY`>!sScgUJN z>Fz!*59Js=nI#A<*^EnPN-{OQ!d$5iz|ZpPGJwNAq9DL^9C96+ht~&LSoL`Nro^L{ zOMLy|^W@eL8KW>tqLkvWAPR9^m$5U)$Y>`Hx)`m{aro7T3deJrOCvqayHpwg$v&*L z$hg7lnJT?qn%N~kJ`FW5q%fQZ0ZZ#atAR`qfQ=hC1d+?L_hkT#bm-}l+&p(QUT2N9 zT0~0kHBg5I4j`pVCZ*ZW_}M(upSE~6?=_zZAyC>R2%NpWHJ#}cZ90v^z!Agb+bY?3 z9svT-34&&=Ts}`n+R)}iuVl6q#&1pmmdIK_pmoAGP_85$2Q$X}ok@q4iY28ruGkX@ zEEc7b8c2y_Eoq}^(}=(dXqOVgHU}!Hfh%2nzmAMgfDQw93WAMom@L|s;7>N;FCZNJ z9iN@uMk@rADk@$fif7@$sBjMmzHQa2c-xzlH#S-LvPhemc@D7~2Gl+8JHRiy*|}Cj SeHG>a0000`F@!(wAO3|!4@$91;oPj|Dyp%0k!?lKh3_m`zMm!H z3d(`fg687KGYtRG?23;tolPPgMSze30JSz$?!olhs2X`qNp1zNay!a5Ip$duuE&|V zRmb4FI4U9ukV=FR5K@wDK2Ak3PnG$d2}|<8eub4bNnA=W^sJ1cC_$PkRQ!pcMNo)u zm-FG&S=^&(&c~*pVwtI{f*T7C<8F13J=74!-w09|NK^8&v7IO43c11{drw~G_E!sE zz3=W04i0c**m145cPx0i$rsa^*|&2=gb)~p z0kCQIJP+4(i8wR!>4|~Po}Qj@Hn0syuG{c$*Y@hWySq!Y)@*dk-}x8s6T|NAO&72L O0000$)Z`J$S2g%9JmbD3M4! zu{h^&92b_wQFA{5fWR1V_gV*t2*d>flL>Ry1##!fag$$Fw5KU?vj4`-mn*DmD0T$F z&QrROfV3<`n(B;+0EkFC3OgmtzRyAtN6-h{npp$$N*Nx;_vDM)F*F8hAOwdcgqgsY z32g;*mkcwboe1;IG-sMxDa;jqWwYQ6dPK(<%H-jc6<8jv*(chIt&gDn$b1JSgBM{)rOK&F=4NbdZGm$ROV%Q%JNg5MFmQQje@{Autbx*AD?_c3k*N=u9qU0` ztRLNxAjtDj`ScO!j>B;kmN&L>x}{F*3gYt;3SH+hI=up0wMKZG*i0=>_9CRWJNarI zdr;LyetZl7Gb2BqPnzfTNq`=X<7mi-g?ks!Lg@__4u^ZA(WniLs&5VQVkQqwhvy#p lBINeJ^wrhX)c^mDe*n71HFqDb<*xt$002ovPDHLkV1k15PuKte literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/led-blue-on.png b/Z/src/nglwidgets/icons/16x16/led-blue-on.png new file mode 100755 index 0000000000000000000000000000000000000000..9b681a03a1a248e1ce60137e8ae8ddc80f45e57b GIT binary patch literal 763 zcmVo6* zh`G9WYhYliu@|}vj_>Mz-CYK6=CN2%bX8IHRee=W{eB<4UJoPLw)5^bDaU4n)O!JJ zjL{Qw_!dL85Tm{9m!sOJvPP>~PDV0u3Nl;2aN@@Wb5QVZ#O;s(;mBsfhpFVFt z`tkMoLVz?(XYF;R(rExtN)fV<6VWZF^NPq zot5Wy7g^?EjD+_qDEM+tD3$IDfkA>G1X}+8iUeI)47Nc7~aR>A7D5aVQq^F z<^bmKOL$*AXE5RrxGV!I8(Sdf8oRQM9V3PmEn@U9g{>BE#!v-c$Ci6hc;rO`RN08U z2q+2<=b9YnB5L;s%=IlXa|Ry(%zIxT499RTBF}3Sg>Q9K93rEtmOvu8f9|YUAZEtY zfhVc2vnSfD+^19uV`Q_S;mJm0TN_YSOK|r0n?$cV^zPZofdGIt-3NvD*%4bU&X?sc zpXYy3RyE2pG+NcjvH|k^Yvfqp(`L<~!+X9A06+nN6u`&V=L-NACZ}%qLnvp6lm={G2JDHha?AnM9|fd(3CTMLp;;6j2>Xsbby zQqb}bbR)R4ZJ?smmEb3EC6#U@g{1esduLoE?=`Ihm%EvBX3m@=^ZA^mr6tC?xxV&s zQe9Tn)4*|emxy@n5u5IQH|2$ASHJpV>X(g;IhQXlv3Bc5-rF0&cz?M493^PMj0WdTAzGv3=XI1qkfZVx%`=eUxA3&Eii&(h8adO#nkJ)LJJA?mmHAYg3=Q;}O4WF6BFS zZ=>Fbpp-%>yF`1IQA(kCo!qFk;_lz;fpq9Ous*I1(7aNHJORs)C$PIS3Cc@Lsn@aC!r8k$pJKF--n1u6NE7kB!|Gt|ut6~Ie9FG}ab4E5x|-)Q#yOMjf(eRpSbw^5{`zf|9HL%WIy#u!utrxkN{$ebPGv;x36M}MiN zw^&_LC!Yhz+K+FYiy{67IO7afEvM?!%vXyH>;QmCYI*Dr*!O$H9Em>B{4*(G6koT^ z;bgO(cMd?s@Vr}Kp?-nq+&n$gpKd-@5OUy2IKuwrQu7 zLMa7+CXN|*Pw8^_UytL6HXV_V=b}&Kn18a91HWY|eP68_)lA5NQTH#YB&=ElrOSb% zIL0SWA(LVzj3T)!U+8;g;~{Xn8%J`^&vFm@JPC)hcaqxaS?A2;z@tvSUavMDNGXNY z`>zhVqx5Y(?=HHb#ZAv*7TJmHuIrc_c-sB&OTFMOfB(V5kph@+mYZ%IuS^cZ?e>w6 z&Epo|dVC1eZaqhb4dXwXoV)T>|5SDPwcp#+T-oj#y{<;y5F;;^ t3?-F4)6<_#ZSG#{efGoEt5;@e{0BoYa8AkWuJ!-`002ovPDHLkV1nJze7pbv literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/led-red-on.png b/Z/src/nglwidgets/icons/16x16/led-red-on.png new file mode 100755 index 0000000000000000000000000000000000000000..909840041de2117b202e5b81131a46ff9a0b90f8 GIT binary patch literal 737 zcmV<70v`Q|P)|O#fB3=lH71)2knUDkAP9+1OZj?AUQtYD=sK9iGdP4Cw{RI3 z>CLh>%X?RsmJY!AZ#SgWR{8E{;&-A$M6DM2N|w=RsFx)k#SAZ0r)UjJV^m<}<*AQvZ z18x3EFR|6Z5M3m9?y$Sd!2!KqfrEp>)^6*R%75Y}KUV(Y#vE@SCY?fMG*TH1B%=}i zKHV;Rd*b$O{Z2<8JNUBL&Uc(Ux8@T*|BSdw?ESxqM4n}lXIVs=Mz{RiCQcD=^7Y!< z8WG`r>M!!cDsj1V>=OMFU7}6=R+6jybb_gfP=!C7 z*7mI=>YC8n0l-870}o}`vHhm|)i;xGetUkhZz;>OK*>IIc$8)t|KOR&Ii_?gsg@K8 zH=@q7@%=ciBUq9n46=Cf7`^u^!dkIsX_e+&kqP_7quYo2+b(@pixPHY(j(az(2{N@ z+1ZQV(n})QL89Kmjb#X{i--~0nj&WAYQu}GT(lo(zI1ZSW;Gmh;v^eGTH9Uf+k3E+ zgV>2}SZ*5S8nj-;HcM1Wd7PLYdIP0IAYlb#W&sD0ML=Q997g^@!U_@s0^Gr`7jCn3PrFGQfm#Sr-k>(EVcb7a zOals`hy+C>9}$Eg3JOI-zQ~I8`xKW;WkVPl$~7n#z*>tS$Ro0h$P(0YSeb}Q9?Ag- zhUtGJR0`PS^p{La>tBIeozA%p>hC8!plSb%&9s-dEo5Bc)zfU+7m`}Vui=;#q| zero)}$Sy`68H|xm$A~!=)}5h@Kokm#3pLJN2pFH>>SMe2?ECKfA95O?SgMt-T;o8o z%7-^*YA^Tog!;aFZ5kRZP>@?UT>m@d$6qmis_*Qc{rztZ4h`i1G=Ob^Kxy(XPE5}; z_S=*kZ)ymi@LW2Kfwgs((_I5UB{!$fy!6V6iw6%LxO@Nq0Bcfj+qFq@ga7~l07*qo IM6N<$g2TS5X8-^I literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/list-add-user.png b/Z/src/nglwidgets/icons/16x16/list-add-user.png new file mode 100755 index 0000000000000000000000000000000000000000..20ec7f27a8aa1c9834013454e0d841769131e8b3 GIT binary patch literal 690 zcmV;j0!{siP)CKjSB z5%Pm~2Ilba&hQS1sBOJjymM~p+1&~MxxZL*`PZw*w~o1$>T}0&jdJezwZQ7rCKtara_S!Rwg z_5i@cn@iKnfTylc+#7Cn@a;$8qR{w#(+n`7X&}Mgepg;zMz*kqXe125IkpOU#DjK5lw39wjhGw+NU6X% z`xD}q-OeHV>nFCVo6t3a=hcvRzq?|)P_mm3q!ckr)4>==I}4|tpyX6AIX8~}?l4}Q zUtwqvN5_&EW@i^Kg?bW`<0A*B8rL|aq%@_XAQ34rRtBi(INs8`^!l7pQIGOlvh_26 Y1Iz^(73%Kp#{d8T07*qoM6N<$g0#Udk^lez literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/list-add.png b/Z/src/nglwidgets/icons/16x16/list-add.png new file mode 100755 index 0000000000000000000000000000000000000000..1e03be9bc896c5f6d8a943ff9d153b42b67e6b16 GIT binary patch literal 564 zcmV-40?Yl0P)8Z)0JRB|3DF3=|YfF7jDEZ>IVpdRI~vVL~%?rHj{Mb-aA4?aN$HkpY6+e zIJ}%A@;qlRND8>Ne);a1hpoZcM@ORNcT0CDpm2lpt8;$t;5m`HA+Mts_V&s9W~>cf zetj;y8B(ff-fq3o6i^ss-tluMK}bpJ9RCvtKmqnoV4WvU2M7e2b^n@kK&}DWEA7Qj z+`01X%TpaFO`sJG5esISB#+&7>@2gVH>sP%}a+DuI`p-7R~pI$1Y5x z9J%rcDSiulyep{dI#Oy%ghc%waq@#~ax=Pj`qhjEu-38}b?Q6+eS$+ zxgkjtHlh#o1_P#oDl|xq z)$=3opuA-AQ-@kiO_W*dZ1Abw6Jy@#*R^Fg!5P*sA&3jgil^7k&X>BCo8zhBfN|0000j literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/list-remove-user.png b/Z/src/nglwidgets/icons/16x16/list-remove-user.png new file mode 100755 index 0000000000000000000000000000000000000000..6ac1d68466b36768e352ad52876cd8699604dc45 GIT binary patch literal 707 zcmV;!0zCbRP)6v2?FEz*a1l+x6s$xJ4h%)Qr{bWv#| z=DVDG;lJ=7&d&koykW)WpFjAr_+so(Yh1*={$}aTv&&|s`oSTeZRqUQ<<- z%;u|^PlctA*Ha7chXLr3o8w=NRCcCru)R~5l0@O9qIifTif}bSIE=^bvGVXXPAMT| zvYSSHH&?!PVKkh|u5Xi6I-?pDvfmyK2wu76V801Do{O#{cK;USLIowu0z`XfJ(e7l zbdx-33n&6OKq+%Nle)=KT&-5FLP;i|F@{{wM|A*FzMyMvK#XysiZTch(1_U71TMyZ z;B8+&-!qKj#BQ$3GkAWvp276=e54nJ zFzyCnMyofE9{~j=OI#yLg7ec#$`gxH8OqDc^)mCai<1)zQuXqS(r3T3kpe0@>FMGa zQgQ3;q>X${1_EvC9b7%{lo;_Hxw!m6mdKI;Vst075>6Bme*a literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/mail-mark-read.png b/Z/src/nglwidgets/icons/16x16/mail-mark-read.png new file mode 100755 index 0000000000000000000000000000000000000000..096ba774a37f51f1afe832d8616609d66cf33464 GIT binary patch literal 680 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~&H|6fVxZ#d zAk65bF}ngN$X?><>&kwUQ&wD(&p6zA9#D@$fKP}kP)a~RfQ5wx$iM@Fz`(}FX40fd zfByXW|NsBoxpNmRSg>^I($%Y1Zv=r&yMSQ#?mc_<96562=+UFcj~_pE>eOiC&YuSFT*WdiC11YuB$|zj^cKt=o5R-@bhZ1n%CyfB(UQ z2Ty?D*~@3oo;`p0`uVFjFJHcV1q83(yn6li_3PJfK;ZqGx9{G(egEd&r?+q4z5{{} zAKwGP$4~D+efjwD<0l~a^6fJaeEs(M>(9^MetrRhuiw6W{r>gq*KgmxeFuUcKY#rA z@$=`;UqJ910{;B__YdgJPWyf9f#D)t666=mz%OlNX5sAR9S{^6o|nJ-=f8g)jYh3N zX~raPcbE9$i-Ed8&LdA3$B>F!p(nDV4<<-3JYavHqw-uJHOTvROJwIXvv!$DSzF%B zefjhM|3kkQ?t1mF;_&t#ihno?T3Upc1}XV)h$kFe_)uZl<&Gb%GTcp7kGCzHJxlAl zW}=|u&rkb`E`PE;f0)BTW9FiF>ZP&Ae{KjqDd1wX+GDul60?_V!;^ex<+%dB&!V&GtzLZIfQ>sZP~c Ra{`oNJYD@<);T3K0RTSXb}0Y= literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/mail-mark-unread.png b/Z/src/nglwidgets/icons/16x16/mail-mark-unread.png new file mode 100755 index 0000000000000000000000000000000000000000..7ac192d52275787ce264ee08ea7af2756aa92b81 GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~&H|6fVxZ#d zAk65bF}ngN$X?><>&kwUQ&wEotlrX%1t_#7z$e5NNDF`gHy8l9XkhV@rR&zM+rDG> z_MN+T?>)F@|H0E|&YnMi;rxXQSFhi^cH`EyoA<8Yx_9H|tvmM~J$U%!@v|3Cp1yeU z?A5cEub)4E@f=9Ldh-ehUcYs$=dWMCe*5w3`}glZe*F0L`_FF>`1}9={}2aOC!j02OM?7@8Tj}` zM9nQ+-P}F6Hb-Oug&C8)-Ce9L`M%@;Ic=UUjv*3~YY(~$H8}_{956I=Hb_u;&MLyZ zYtsM!`l~hgAKc7qu%E%v&6vn_rMII&eQRaC>8pth$+a`>s$P2abAHIWH9Plc#MbEB z&w3f=&wDKYWYd)I`yTJ**wEqR{kZFpsdf(+)0*>c6E>?PRwl$`G3CV0yIU<;9?kU1 h&1HtCiNe{3*V&t1i21!szR3y-TTfR%mvv4FO#nY(;rajo literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/mail-message-new.png b/Z/src/nglwidgets/icons/16x16/mail-message-new.png new file mode 100755 index 0000000000000000000000000000000000000000..ca3bb8e4fa35c04b3fd23f728f4b8a4c09821717 GIT binary patch literal 967 zcmV;&133JNP)p8k>0 zJY4I^S*BR2DIr8OUGChDbJ_}dC?_5F)Wh3-yZe;Yn$Fhe{l{zH@9+D0zu*7-n1kbF zgR`fNzEUFH3tX~Q0++a6$@a=OlI`lE#0~Z56Jz=UB*~Q;NwT_B;F^6$;2QU0xUoA+ ztSCZ(%)GNQQ6;*YbR?6s}!2F74)eb%N+Ne_OfR{JikUs=A1XO{hDb zq{-V?2+(B3YFhYNBC1QYet*bV_C?0x%v2!4Ig3l|+CMOWqYQ{FO$&$wRz%j61<8Po z>D8*h9)KqCSWQx(1rST`CGhXeQyRiV>W0Ar6V`EwRsB*fz)=ddx$!~;#yrgDyfwUU ztv!EY=tN(xq-DJW12{^5WmSd05}0{cKUF85eo+xI~&Yc zdaAvEfKtGiWFv_?br&RaJMXCe*@L;;11rWAfUn4vMc$=z!d;bJdD$7sp z4hHPG2W(_wXcG4dCkT2y>E*0p~PWc>b z2nC3W&03!?W}xQm{nSURf#`${j4wrs%kAoCAztPRDw~ zJK*u+hBSFNaQ#9FZZ-g!lX7BjoFmdby&Kva#dl71Q2yQx@D$$K*i)|XWpj(vi{n=Du1g% zS*Mpy4s;8+h;&cyXm7}8nE%KEhIZ3Zvl(cYcW&-h0@t*)fvQg6b$*NB%TB-$$~AV< z9{G?jOH30{6g_XIolo1L5DbZcbs;J)OezpT0tT@asu2~s5EBqFaY0Nm!G-S7oeN9| z_z7L$P7@P!0qVw>Xh4GrE?f}5u;ZihX-THjDIM<{YXaeOoBQUz`#JZ%`|j(Vvki5c zE8hh`3)Kf2>6^`2k!al=w=U6#bv4%2VrZgpjy6*Jsk#6x{(JQLaUW^aYxT`t6h6tB z)fPu@kW#)LIvte1vOHnOuA67RB>+c3C~z!Xk;Aebizaz&AZ=h^pf?(g-Y1K9gLONF zs;ZLT@4swisJgnklXS{7rCZK~$x=VR#%EiW(YqzegxAg*=XN-lan^lZX3Q%{OQN>@j(KK5!*g=G@T14dwP0D-i^MsK8(F*Kc=QYXSb6P zFpBr@Ls?mwwWnw=Yrl8_KA(@G8Pb9R%`G3{05!9}{=6}C120~Vpz&N2^aSr6peQni zhlddio`C91qw|S~EKSDJl8(N%Eac^CH4gHVT&fDE!-=Y@qtFc}g0a74R3JbQ}R;(NZ(K~t+~M9v?C!@-a=({QOyZk2ciib!oX zGUw*bl2d{p{+k_CnsQq$@ca8;0hiov{ztGq nZSt-pMy0n9YTovtn_DS%zG-IqQ;GLDe=i6H8v;YMZMXjd2&4tF literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-eject.png b/Z/src/nglwidgets/icons/16x16/media-eject.png new file mode 100755 index 0000000000000000000000000000000000000000..e0022f72cc1caea7f582a31581bb2919b9e7bc49 GIT binary patch literal 502 zcmVMzCV_|S* zE^l&Yo9;Xs0004XNkle4gB>ax2ci>8sasUYKu zwU(@l=pm?E1RZ;aS;9jP5EKjLAw&WXO-8j$(LmeC*Y|}GLLAighr?`;5AtEQKRl=j zAw&o^b&B>7RGrs!SEmY*{bUTC5J2z42Y?!WW17KBH0?Tei9vE7@J| z6)Jx`(baa_PfVTbTFGK5?-`r;>xC6{*Im{1Pi5kfr92k$O~(qawA^sTC6`_E+=aqp z3wd<1C1Vp60H88)M<YmG_(~Q~;`Zo#&PZmDaO&9t2e s5kd&jsx^m=Y&M_G8(DMMstF;)f6Wwb8es^!JOBUy07*qoM6N<$f+f7yK>z>% literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-flash.png b/Z/src/nglwidgets/icons/16x16/media-flash.png new file mode 100755 index 0000000000000000000000000000000000000000..04c45981cd1e81f6a2864ad57652205b34476eec GIT binary patch literal 740 zcmVQNC9rOgkUl3LrQNn=S$vMI5#X5ZFi*O??6 zlF;D5+c!Hq-+A+S?=7gR+H+i)47{1VHGP}>Yg2bVUJu;6+MUx=jCLUYJ;^@L#Ioog zUde3KK79JR(w)cAqurc?&gTw?<3deQK$aNLSDj7(#&&??0hlC1a(Q__>NbJCwToSD z*X!|<<9_#`yIx%(wWJEg25nch$Zpn^yARO`+VqpO!?1mO7Z~cNFiNx**l}h6jHjy(NjzBCn58+4z8gcCu z%lW)h0X?<02d>3Vk{wEsLN9G+n4U2%OwRM0>A^x4boS~jnE zy`!gsp|@JxL%EucI?xJj;}oB`c=^ef=(i*IK6mc?rAPBit7oFo+4qh39L3|%X8!=r Wg!SwvNpWca000077{(wcQ$ z_jPx7_lH8EuL6OWVkFI4|KiBK^uT9hZGndP`Z2?`^ebH!i zsjI8&n^Y>*zqq&EX(?(B|?{%mq*vv*Y9p` zZ(YWi_z)OlBA?H@8yg!p$z(DHfJpQ6^I9|-{cde-P1ki@DHe<9>FH_vQYaJB58b`Jy+2XE-#-+IM5bnEXH`W}u(Pv+bUF>wGywpor>B^ko5R!7 z697O}RV*zn1v)x9<|w6oR8f?7jC20G zG&D415<)%;27@2RVlic6Vgj3+n~)?401%BvvAw+wP167Xwrz`SHru$qzW$MO{sRDz zm6esDOeRw>48vuNanAYwLc}>2j4^H)hLg!;eoLiN{Q!t0guve3Ufs6s;?>oa{`&eF zh{a+)LP*;z$8peTG{n)-QEh*J|E^Z6y|35nca=(ox671BBxFTVdcxuGm$EFU`uh54 zJRa9P&qKLfHmlXD>$>jurfGhwY1;GQ;i31RHn!@#y1MFTjA@SJ#3`lY06fq03gK}0 j;raR5JUctH-`4pbs`#Njj9qS(00000NkvXXu0mjfJVcu9 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-play-normal.png b/Z/src/nglwidgets/icons/16x16/media-play-normal.png new file mode 100755 index 0000000000000000000000000000000000000000..500c3801584885ce988f1e84de109ab5e066681e GIT binary patch literal 918 zcmV;H18Mw;P)D_0c8zk4%D%uEtP32H-JBu!K*eH1zcSE(-i z0}_G@T^Lcu}CE1h(@CxLWs!aa;1xl3)3)+pUdU)YhBl`4-O8@ zhJmW8cE8_0(9+WKO(KzK@9*!IolYkxr33&t=b}=nV1IxAX?J(`&&S8dS;H`XshiND zp`p%+iHWn*(^Hc%CjJk`m^e8(F()S{v+;O51c2CjdwUhX-~ZkC__(U7s^jM725W0; z=;`UfzmX&fKA(>gLX<+G&=v>;exglHP2uL|=FeiWm{ZqvjE#*Ul}f!3*KsE zn*h+-+KN~#_M+v*#YF^zLCnm|V0LyEgM)(*Lcp>taLze33`5K3^M7;B#S8U6e+~o! z006h!jrv;8&(BMYv0rJeRy)aNv(MFP^*;@kmzQyPc!*Rgg>*WNqoX4*#zZccW1REf zZQ*cOCxm<|%koE|P{?tAe~;_yYfMj1qgX5=olawJZVvPF^SHXYf~IM(EUTQ&W`E?I z{{R4Fcz8IROeWuGnr1S_IOqJu5pm81V~lH>R!b(6zaFG&qZ*P}2Ha5;mrP7z>a{27?@{%{g)YsQ1IUJ4;yi7_wt-fmPn zbN1)AIENomO5r7h5IQ|Q?EvtFX_{XdhVe#9DWsGipPrsRGRFQnIy!n(O3ByG3t(z$ zN_V^6UYE=D1LyqR@bED8dc7?|2$jiXs@ZH-HX4oJDwWFjcXxNW)6-M?6|lOxYTV!7 zFS*_BNFWgC4g>o)oK;RVi6r39fS~KUR_-cc6WClP}{cOxLmIB`T2RyIR^j~3I%L!Z6O>E zBa_KM2!WlQ9R!0xoS&a#X=%wcP4jEU*bp@gR9_)81+hhhuVNWW-4+CCA6d*x1-WEEa=d7|7@I2#3Q+CX*$7#Kh%lYwPf2nK_&EDP~?9F0Z;4-XG2ole`0M&pc)kB^sy5br6aeWRnJ zx~}VJX=%a4#030)KYDw6q3b$)J|AXgX3*2qgJ?8bOQljrLWrN)<>h75MzCV_|S* zE^l&Yo9;Xs0004FNklB9I38p(Iz6IO^dEMQjt>}>^t3llMXiwcw)!{H|)}++uwH(K|-~|IrqGh@yQpO zH=a3ThfpD++=dBxU5K?1eFDKBVp?BowuED$I} zkR>PRm)K&!hzw1}kQOC^{*qJ33LIZ~rbLxp_E@EaXM7bn6PpN9cKz5(7SqMlOZ>Pz a(ftDwiElIZXxcXb0000MzCV_|S* zE^l&Yo9;Xs0004WNkl zYnIH1=*_xx>SF|Ngh5}Rs6lxM@#19}#d-$sFy8p}`-Kof9M%r9Ebou{qbxtj4r@XP z5kmBny|h<$Z0qaW*3m2X(taXDh~1<&*z(MYp&!nCcVfqu-e5NoA-d^?SHAga?8-ld zU(Oxd&`m|8wav2Y)E}jHu1r-X3KzC*mT4{4vt=LsR+>6?KYoWuxj3n8IOEc8GB)A6pN#dQ-vvRyY8A>?)zk_@Y3Qa+WC^9 zu?lzGbVJ8qRK}iY=h4m@-n%rxJ$HQoOq^+G@5jShvwZ4Yq4Guns1&-I<-=NtRyya% zg~CK-sxnb{YfdW_Ar_L>VAh(UOJjwxGaa*9gM~zd5Ur$<*2`Ioc0Bjkta{lYIBdh20qxn%iZ)DAy5JLP1do6CCFD*BW00000NkvXXu0mjf%^}{d literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-playback-stop.png b/Z/src/nglwidgets/icons/16x16/media-playback-stop.png new file mode 100755 index 0000000000000000000000000000000000000000..180280e8ba359d2a4389e93284454cf943b27dbd GIT binary patch literal 499 zcmVMzCV_|S* zE^l&Yo9;Xs0004UNklyX+scBW;@{ixB;GHteD? zi4zVk%KMm2d+-vpg@ZO1m$9PhNBs_CwvU6gp6B-T^cklp z%LPGv>rmBAl^Q-iHLBFjq4KSMp<&gV+w9V!%@Z9SXtBdK^=89D1o6}c7u@qo%qL%H z-gxGm4LpU2vNw&#BOe&P>Cq!4LGwb5O`~jC4;H!Q9m5r89H7`jk)mm{$oi2~!WHh& zq+HUVf=iBBAfd||l~Br&N1K?GJ(kHa#W>SIO3XgxNJ>$aM>IXMj535U#3;~1b3iGQ zVp#4kxJ)p@Fe6O#7nUi8QVbk!=#sF+43ms8$qbOt!J&90^LD|k@{A_sUnv@of|<7k zaaER6UeF|@gCDNR;wnUtIm>NkSffps7)?xvDjD47oYjZrT8_$_3?+8hV}T5L<0#h} p&_s}e?F9KS7v-XS=mdoU?jMapX0!E+{+R#(002ovPDHLkV1o6$+0Fm} literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-record.png b/Z/src/nglwidgets/icons/16x16/media-record.png new file mode 100755 index 0000000000000000000000000000000000000000..1dc4efd4ef3a107b44c33c26cb1117bc20586cb3 GIT binary patch literal 735 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH}&M z2FBeW%xLxI@gtz1WQl7;NpOBzNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~* zfr5#Ni9n56Sy@1pxw*MO6AB9pfhtQ&OUug2fNlla4zv_#2+-b+j*kBR{s|K%%$YN1 z$BrGlcJ11?Z{N9d=Pq2haQX7(D_5>uy?XT;3&%B6%bRSRH*em&C9ibL)#LW<+jl}E z?%ut7&)n+1uEBjvoBOs7_Y;yIa&SGgw0`vH(PJ68=iEHcEv;X?c=7V(%U7>nz1BB) zJ#WDqAbRuW?c$|xSFC#b_U-%k?>{V9_+iJ+k9+rj{P^+Hr%#_hfBwqP|LxniU%!6+ z{{8#UuU~)u{Q3L$@4sKafFW6LdsYM(`idn%e!&ckK%fQ$K;IRD{nEG<2)1o|4g^30 zzD?sg>%TN_vv}raHT~$3@AZo7_g;FSlO`+?`!mwE zogpDR%%iBAf#brjbb+Sq4koAH;!(LJF7Y zJnmO@Q~C4^jn!w)t?s^M9$~%n^EAEPZq@t=vHLF1)tqv0+tRSg*n900IxL<&EGU}t zE_;?z$MKuLs=qH;=IV4tVZ!ru&pK4LvmUUIT%7Y`wYAV&pcffDUHx3vIVCg!0Gv{2 ACjbBd literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-seek-backward.png b/Z/src/nglwidgets/icons/16x16/media-seek-backward.png new file mode 100755 index 0000000000000000000000000000000000000000..6b7632706d7b2cb5d1332dbecb73c7faf34ef8b5 GIT binary patch literal 505 zcmVMzCV_|S* zE^l&Yo9;Xs0004aNklEaX+%P?;$Kvd*GRS1 z5<{t*egGFi(7{b1K|~#NbC7~MNO5tA6{SSs4Kd|s2|+IRaJd`~_nsq2tFG5v*K-0V zaJ`ya*GcyYI9gSfRgrZZoGunAtEzOglu*&i{u&!x(%^+APu;1+8fCwtB?Mcpu+Jm! zwE5#QoNi)D9)8$MBVxMLFlpO}yaGc50j zd2fLSLSpVIF$-K`01+*gnD;~>uxZfdiY+WgxhBsL5Yz5%3W3N6MV<*cV}b#CIcJ0( zphL(u`9N4+AyJ4qWspALnEq5@4$BjkYj8n}2smUIfFmHHiGj5vru3XzbJ z!X~Gtbb&DC7`wa?5)uFVaKIR*Oq`t5Oh3aC4O+AbyWONn2GgI^(y&a;kXe->Pl-*Y v$&gisG}Exs%ISui^~QtoAnO@!?mzB76^d>}5T;jt00000NkvXXu0mjf(OJw5 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-seek-forward.png b/Z/src/nglwidgets/icons/16x16/media-seek-forward.png new file mode 100755 index 0000000000000000000000000000000000000000..6c3b1c45643c612bae09a60e0b42fd2cb7382371 GIT binary patch literal 506 zcmVMzCV_|S* zE^l&Yo9;Xs0004bNkleeL)p+oS72=)Ow#GpKcc=57~V!VQPSa1CL{Xz&K4$Axee%c%LM*VcZ ze^3@eh!CPz+D*E7+oqnLO>NzLH|dpx2(ex24mLb-V(7bb-<;U8p*z?vi4dJ+%}ZbX zF!sk^nV&Aau%?rUNXqMZ$C=-9|4f}KOk^%?TF;YmwED|F`6c%m?D&X6W@uS!FILh= zzQ_~~oucKQcbK@cY9)=OQOD3&p{4HFeYeawQW)E@G>XMh+nLPNjBDPSaotVtO=X^0 z97Qu-GBj4W;}Eyq@Ct>ohni_L`!&a|OdNr`UW18qHO;+PDA)7HE@TSu0TePF^?acm zqLIvc?owu=FjbhyyfLehh!FFo#-L)=(3P>w*txcf#$diALWoAGmQ?eKMO&VFprV@B wl15305JHH0xz?|ybECOYHLdmQWg&$452k)?+rkR07XSbN07*qoM6N<$g3ib1wEzGB literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/media-skip-backward.png b/Z/src/nglwidgets/icons/16x16/media-skip-backward.png new file mode 100755 index 0000000000000000000000000000000000000000..1de5dbacf00bd8584fbc67c67881bb9eda5458f1 GIT binary patch literal 511 zcmVMzCV_|S* zE^l&Yo9;Xs0004gNklX} zw~01O<`6psdFfWC=r?SHhx!8{gOUjG;$<1t`i#EA+IV`N5JHH(WVhY!wEC@nyR+Ng zON0<2glHAE(`H_`uBByNT{GWKTLmFPY!#Z_HJc9fe0A)z0~^*fyITbjqLHrH_sKT{ z=l;licjAQ=jZ{RMtmX|ze#-qbHa7ChOQ+VY=4lek?FH}s@YZv{p=C2NJqwn1VzKkk zq0DQW`0I_kZnaM4)i zskwgCI`eu4N-pEvo~tgoVr1ZfS|@7lvUkqha}Dspr0a%`mDP4)HmT%~oXCs-{PtX? zp_0!gA*$(=XHI2?M#e^lGOtXjrXs{lq1r84(sO1YGjOb~sM?(=h!CP$D5s^oXwHVm z?kg(g<+NH5B7_j4l9bz}&UAmeU+R?Gl|%?3{sTMTW?MzCV_|S* zE^l&Yo9;Xs0004bNklPHu8N*UY6P4s` zVoj6z5W7`$3L^Rz8)eWJ2x3qkLcDl+8P$3TJFJagzh4L;#9`?m%etMslV{z7?64$+ z5Ftb-*-P8QrY#*ETbkO#y|j}E5n?B4_clFpr0<&(Ume-DsomR2M2J?p?zu0%8~E!& z;fGVttZStr($dDT<=A__{4+5zHc~jVWn-9@Vl7+p(NAx^atzp1SLj=^wjayg6`vJe z+V#*I7g#ZEabo4 zQA=k%b*3;fHZe9*cx_fK6(Q!6T5raxzHqLoy+I)a<`IIOF{_oABo&%w-$tV_5c6?07*qoM6N<$g1p4kZvX%Q literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/oO.gif b/Z/src/nglwidgets/icons/16x16/oO.gif new file mode 100755 index 0000000000000000000000000000000000000000..cdd8e27e422384b6a35a44305c1dbb8e8e14d0e9 GIT binary patch literal 1623 zcmZ?wbhEHb90>_7olFco5&|0+ z9qM5-&3h7Y@xh77%FfGTc3w<4Hd!gUspLh_lcTK?nSOs}1TQ+?Z7Ul!r^7h;&}<7^ zxuYvg79N_w$;#P6#GC zK%7cgBeMjb1Ve)&=^Am^h!!|loQlK76jVQ2BK*kCB`_i2p;H^HyjRVOf<>;4Obi(+ z3<}Eby#kyOb0j7%I?^WLyeQ`6rlqH+^I{J%TO`w%7=WfVF!FHg&H3>m(S?ayJ8O-E upo1%uyrtEX6(1KJ=;X0=%Bi@da(cQ!@~Js94HU4&!7z6pS~OA^e%1hRf%en@ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/object-group.png b/Z/src/nglwidgets/icons/16x16/object-group.png new file mode 100755 index 0000000000000000000000000000000000000000..89459cce3e33c1140dc38cd1044576c97d2448eb GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH})6 z^6MbX=%g{b0w^e1;u=vBoS#-wo>-L1P+nfHmzkGcoSayYs+V7sKKq@G6i|_OfKQ0) z|Ns9bGd@V9zm-UTS6W`TdF$Sait4tut|?PyE?l^5&6gEk{n0<(1p}wrK)y zM5g_Hv)OUSvm^ltHpXYQBF}z@o!RKhnPst7=!(I8j;cHV|8&`E?_ts3d~OfOCk&ph KelF{r5}E+IQH{_5 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/object-ungroup.png b/Z/src/nglwidgets/icons/16x16/object-ungroup.png new file mode 100755 index 0000000000000000000000000000000000000000..39071bc7078365e1a1ef34ec44812a1ee1847449 GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH})6 z^6MbX=%g{b0w^e1;u=vBoS#-wo>-L1P+nfHmzkGcoSayYs+V7sKKq@G6i`t}fKQ0) z|Ns9*(_cxazLrRTCz0`1BK@sI#=DA&>h0V20Liwtt|?PyE?l^5&6>u=6cCWt>VZP_<6l; z`d8=sTNkXzRPgy+W|e2sQvF2jrGU4ylDW#7^SqoMXE(l^Kf!IOT3k2t+5Uhd#~-pU kXgfFcI%}4I?t)|7cVt+rC&_SJ16s)7>FVdQ&MBb@08LkvrvLx| literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/ooo-calc.png b/Z/src/nglwidgets/icons/16x16/ooo-calc.png new file mode 100755 index 0000000000000000000000000000000000000000..23df56dc225f11cb9d4a3e0d394a64f907c0c646 GIT binary patch literal 986 zcmV<0110>4P)l)->vLn%_)uiyK6pqobHbMz$F z{oE(deQW${s`i|E#xC^3nx+*cP0OZh8aAPuN~vHfEe~Jme6IVSdhPbI<*74vSFUw! zOVPU0_Zq9UT$ckw*8#AkWFeN|trM4&KNtiJxISlz@~f;FFa9;Z+woI+b_nFR@~G7Ns|dc^}gN(Oc^N=F=kpls)p=ej$VsLZ}0; zx2m3jY1K0@qk0CW)!vu(tJ~~?Z(5!A{mGP4s^R?~WaXZ&-Nxpc=952v-I=rDE-zgt zKf^GWSff@s-hPD95kDOr$7uVYgKURjtxY3SKw{No=Y2)mxu3@G)pa2X*XOy|w&O|O zIod^U??oCLo~O9DoVH`os_vV$ndCEEKfRqm)1KrphHD7V{f42EJPkGxIU<25XY19uKhDH-z? z6HN)sbedGcVrxYycmH@n>dCY^^yY~^RZ`%l!s|c{`LI$6l9psOtw>rD<+YPll|gse zPEMEBFtmL)r|x-_wUHTJ@9%u}%aKrY?8@jY#T#?b$}2ED8^Gx%DJ_zg#3;|Cq$G|v zJ;U~bT;`XS@C1ihbUH(SN7=}V9Bp~X#b6)4mVJ~oJ&mRrC?UwM%|SYJ=5A_y9?WBT z_$p07*qo IM6N<$g3bQb7ytkO literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/ooo-impress.png b/Z/src/nglwidgets/icons/16x16/ooo-impress.png new file mode 100755 index 0000000000000000000000000000000000000000..d1c23c2d5aa07067f953c7b6e6b8851d95c05548 GIT binary patch literal 651 zcmV;60(AX}P)}EWbFM#LLJIQGA;KW-5K)R@)}ao<0wES= z9j16`^Ef7$c&$?>i=cj5;_y$iUm4WGIkqfh`~CTLkmei)&FA#IywCf-pZCinP$ch- z$mKFcy+R0g*03BT1RRPCX4Z42-TN+lWu!1K{+jBR(K2VHHB;^0eel8cMp5b90Z9Y^ zuxuO2%o^?wzv7slif5AYNbK3AT>gUk_NR_=wR3ssc9Zkdmqomun!}!oU1)7Sjp>g% zv{)Rjy;Zn&@eC#xe&AN{WhQH_R%xLQ0|3x?b7WSVPq1NHoJjuS_)?0;UQBT7y(b(V zea;J?lN?`4@#5DM=M0mzx$k_cGdc?Z!gKC!cdb(&z&52ST{T@u>lh3UVPz%x-v`r~ zGzJEPP^8oW0O-EcwLJu1d&FjD?&}Y5DeCJFa6@~RhWrQZ_1o) zYTlTELy~FPwxci*^@sAFh)`Q|3?vAG1c+pQ&mqZF0QBYb+M(jFU42sr0QlXQ!21uA z|02*;*5n@l@Whx$te2|r_4TF+)YmnDqy!0qk{bkBlY5jFZW}M}jLv)9IK0)6g&=5C zZ?`1S!foRU0J7HVQ2;prIPa~1loCHreuE@}B*5oA0U`pCgi>mAkpMsobr>!E0RX`M leXi1)Sh#rf_+iOC`UAVn_rRjz+Mo3`IcPhnx2K&S)( z0HAoiush~)yQ+pt5mlyK~iS97{G(4p5`6a431dvt+Nl>P&Lv{9z?f! z2*#cP#6*ST!s(;vFiqlW$tQoi$Lr^zjQ$k;bQ2eRvW0RXWluH|yhiE~c*H*QgL=NL72j#G2z7+uQA zr6u3TjxqYsvEU;jx_H0Io0L&|N~J%NUH$boD2ZqqDt^6Uaz=0L;@|31w0D*Y`tE;JUEQ4Qo#WX zP0h^5Ns@@JVF$cKAR@38$xJ4bU$9Ss%R@H{s#+VWt{-PEryFh$7E1wo7s+vPaegKE z6c{Vdy$;B(>u>L~?MTptVbJ;$mZ|wwB(vG<*Fc{F0B|X@yYosvPnG5!(j@64!KGiA znO$z;l7fFh003h}mh7z=9W;mk apz$wyR4f@6P-xiz0000;OkH})6!PkMflQB);^&+4kdx@v7 zEBkF`4jw*b=HnY*1BJ9aT^vI=t|un|K@NlBH+G&m!V)aj5-t7)SFSb+OkjM%#M&4n cV9LY8@QRJ|={Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02{9W02{9XUK)`c00007bV*G`2iOM> z5d$>OhnAH900KlwL_t(|+Le;MYg$nl#-DpVew17rNECVpi6m|frqrP=LO}$B#6^P5 zkf}pcTPXekZRwCLbW4VIZ6Qm8=wwGTNU$ArP*LgN(8RBxF>2MQ_x2p*fHi~k2QQrS zemtD>@Cvc@^|b8u+K1QI7`9q~szSHC3_%ppuT%g*fYxXPp;3;-Qd`BM15*&yY?d0O zl2AH1fl7xN_d_8NNkabU2n>OWtZZ*XSz21a45V4DN>`_+KL{a#hv9HvC(D}p;o$|j zxxu4MMjn*Qnv3IO`BymnRlm4s%w#h6Fkwh(2pbl+q$eR{dK_q`8* z1#_PZaGXvjg27-+mgUc^jqpOXTJ1(6kt|0VENmRl-t zm)|R?)Hi;M44BmGK`5A&e8Kdd(Mh1-nB q^P;gVzD7r6A~qOshSvr62*uv2q2TVFkpgz#D!ZD zOf+naR&7XS0lIOcvgkt8Xbl>K(pKh7+v)Vo<;=N#pA$)pb)Mu|zR$aPUje<$y@60U zRAzAjlprQ0J3f!)f9wc+b`0^r=9KKiOI%uFF&k+yCvM;pIfz4>F~!XJyQ zzPW(y3Cx{DJb75WQhKoPp*wbZOb#3cH9`_wFk9&M72@?zYt`lYxocnAFHS9B02II{ zufw6|#Y^M+#xLb3-y4?B0g}+Lv9e8AtCLePjx&z(p7K2T>#@O+U}@IlxA`TI00Tva zibeMWxA?9nQVX$9+OCk+D`eX~uJR%C5hlbPE<2<5_n$BBp#-2VybQBXi?@a*pDjCu zhd?&FHi%knLVp{rLJGUewe=fVdIh*Huecu2wCpn@EdqMi3vaW_K7T8uq zZbX3_LzaO|0fQba;R=qB<9&@lk+4_xSx^;lOxFyPNJKZ#`Ac!P0=r)f!RA4BkTyYN zdJ>Unjm4UdO>Ml0aGRi9keY1E#jeLtHS9VhK{g=X0Fz*Cku2=afYnA~;x;$3u=gs7)r%d*`6RpfZsv!a!J2;P6h=5oU-<`pqtNM2~lee=L!H!e@_yl51vwzYR z=SL1qz0iM931@5&Ap?@Cp!Gva?fR{2Ymqs(7VvZVGPdWLE*^%yQSy5P&kYy6*K(!d zY2j)Suh;*qZ8ol~ruLg8pk2PY;~RVV=ouKCK%%+=)?lJKru-E>{0&G}IBImXX`uiB N002ovPDHLkV1oE^eMSHP literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/printer.png b/Z/src/nglwidgets/icons/16x16/printer.png new file mode 100755 index 0000000000000000000000000000000000000000..305072b5225a5d9a33a1927622cb71a1780d21e5 GIT binary patch literal 630 zcmV-+0*U>JP)jK~#9!jZ@8PB0&%?wbwY~4;qCWB!~nRTmlR6kb@qAM_qgj z_f>oYA7Bq2LQc5^_26mGIml{)3v)7p8lBY{|Hj#>Vq4r{k$g~8cgAmY}*D2 z7XqCEr(xPhNy70_!EZ}A0qo&NXUM(VNm#Ep@L@O$)a&&hy8athtM&i56lczHOgQ9S zOsDU#-EKiu74Uk!6ayN0v)O=Qn9TX7K&@5_dOV(KCX*5S{T_zH5iFMm`2Bt?@Cn>* zH((qKY%#v1Vi%oG$JTXy*YEewMIw>7MZ$A99ES0DoOpVA3|W>%NiOu%k&9px8x63L zt|*E|v1~SbD+-0erK+kofavvlFc=Kr6q3ngER{;dXl)qAr7%qsBlbPhz6CU56p(P$K^)hhG4-R@_Bl6+W=CBD22AQXy#6I4gy_4OCt)R1p!G#Z6n zl}hDHFc`eUxvom3uiuKrqKA`?vZM+^yWO@P9`3(KB9Uio+&M^1r_=dnvuW>kyMy6_ zIyR0G2X7%S^Mvg1hQPP5#=|^=6Ce(%{VDg(-#Jbkn&7YP$vgHI=4dkK4;3>kq$#1J QkpKVy07*qoM6N<$fT3ZYmz(SzqVG|c5sBvYC8;yxO zSMFq|3m+?&Il=G#E*49tb+=foJF~O)o2zJAzY&PF{ zcQn;xSqPzlrXf8Sr($<54-e-N;#i|37$JfeySwr|H*TiPjViKU2hYP-r|-JdeIIGH zvULAmHS=RRl4$?nxsLQ$&+S_&y<9>lNLMW?6?D~xf(rKqNMIPx zd#_(jYV!-|zE9h^AzFuq)IAV+w4c8~=fz8y0^G?-dasQn115Tdn&%~|A0}vNX+xMM zI1WZ8gLU}|!H6++cMEgqtE(6)(Z>6UZ6-?KfMBzVR#`_c{$geH4(`G{Mt4TRS=_}1 z)}K5ku0+iP0~os4W}*Zhh?V?Xnv7=Z$s~F<8$KdoN!Mj#`V-#t6m{EXEfF$}36PsM z{9MLeU!(oOL(IN@{(Swi-DdxO(vP0vC*p_z(nBUnAYrSfv!k{YxOn;`zVFlX@->=i zA^`zZ^pJ`6U`mLC?_!J(Hk0VGLEG0J+JjFDxRwQa41O0`O2Ldx?YPU)!&1&fixf!S zn2aCUOCnPtj4HxY0=|T$7Qx3gSv%o`aN{OMl2=M{z*k99Nn-Ihx?xcFJjw_rSIV_h z4e)M3BpHVn>L*IXElUe#_ZLw0-b`7f_3!XsT90i$*K8O(yyMzIFDuXPq-=Ci73uKWCH^ zy1Vw-d+oixb=jA*&;G}(XII&^*Ba=!-T4x;JIqSYKSkO2cv1fd_-=Z6`T2LRH@o46 zRR0#UV|&Wa*Uy-}jeR1a8{MKVnb13?)CcaX%z1ONCC)0?)lC4%zG0^C5ViSt{_B;()q% zKeKib`A3f*u=gA?+fnTcSg(Wq9s$pbiGOuJv}qyZN7eSl^PqSCl)V=1??LRHjk>sR z(4H}l{KfkADMsh##}4hWs}>I04Ep*O`nu%p*uJpI`t8fHKK8(ry%p`3P9L;?x{WR; zzuZ2L<2!D&YcMu%hmC$F{J+Q0dIIST)7&~~m)TiZeHm%M^aRp{Zk}O$4mC~~Ka7Ep zhH9^N>ZhA$G^V$rYv%%NLG1 z*`wA!%FH;@cnHsp+h1};B`fLc^FprcH}C)4cM)G@dDK7Hpz-*t#C(+H`+LbJHpbwn z^-po`wy)$zEnj}%7>x5kv_s?emt9F|YmM`Y?z9JSHEw_Q88Ep2>z;{i1oCBb$*oe= zi&B5Q54>{}^KX_xU4sqimr%Eiy04wskA2Gg;ELBmms64F@fZBB{eas)VIdx@$v*%# z?Nc_j9zp(vpj)9g@dWv?KIR=e&kOqYHrwl;C=g{g~_tL*{_o1iRSWT z2R{3_DCjcsk6|DAfr$yjDdFY!vqz?EC;IpTbU4qx>f}Tj%xAvJJV6}7g0qOma zc*yx;K42VXf8{phA6EW~zZgS1j^T`yXQj~VIqFIM;v7j?(qB~aoo-(KicJvD54_uU zBBt(yPk%+-C2K9}xM;Ixk9g_g!aKpPI3QkoP#`xo_l`k;`9+SNGAvKHCG?pF@oP z%Q1}1{_D?c@XgLs_*Ma5{Jc8;|AWK+b4+`Yu14x1+1w`5UbNYT)I+kl7tD6!h;-NB zj2G@2Tml`;Bb`H9Mj9~vgWp}oktUG%eP^A2C7;8;-8n@XV?MSx*1L0xJQt^Vr#q+M zyj#RZm1g?QOb`pGY;B)#PTIqRI*)n$`AI( z+Sj=Kqg>dxEH6FF294XlX749inMO>b)<62Xl6O0eP`>=YG3b7fd{M^12*#h}Mwu#$ zu}55u#~=HoUO~s&XU4z?&_`Qc22>I2p@F=j^qDp{)@KFd943WW1sZtyWelG zLd#tKzmgAos~4cl!;6!4Q{BD7?W&LVX1-U|S~F`u#5wNAj^I2OxOv9Rv@LxT?4RGY zr4#(|SFD?-c<-^P?_f>afqNY#>B6->mO+nYq;H;>wEZczwv9iCGuV68yNB18d7fUF zvLk7{x2}h5E*Dk5YNoxA+eBm6Oxhy6wTikXbDqC>0~kL%U9 zA20Up_W6DG%28lkug{1{HkL0UjeIdL9=65%(?htM{L=O0HC-3&nDH~-EAQXJDVllV zBgbBRAO7-I;};&%h^cC0)kS?*we4GL_}zxd<`KK_R`rY6nfLqrGwtA)ZAByIDo*jl za@W1Z_z@=AJ!9jTM5@zAZN%%(E!aQeP+oe75@XgOt!3gBZ7Y5xUv^xJX8h2FJlgN6 zz0(%Qukgv{!WH!qPpnhEE&Re8amu#UI%1R#?gNew`U5f5CVtBIq}Tv1;gep(=NK6~ zseV;mi}6EDvMp^|#TcM5AtOlTZ*5Eu@1L%ihR| zdZKur-;%Ql;Up!-h?8Z)NvdZrOTMY@HGJ)xwLf57e0Kg;dri~tyVd@LDdJY1b#?XG z-q2TiiBEM-dB)PWub!N>o0Cr(KZBH9Vpd+5IJfwn-GozmiDo|eBJss?=Vf`{esXHo zJ`v7X8i_C9`z6=Th{Vh|2ti)Egt z50bqDmTZ6VmuMya)Q*&L(4UX@yZ70vH-dRJPx1W^adZ@V{8_TuKl7r>OTPG|t7znl zdDU0@Bahb|w7;*$Hr#iIxkutk$bsysCGK-{xK^ z{?wjhYRB_4_Y!-2HF=#jmr18BuzzKIjq$hV_*Quv z?EgKDiK@M&n{*PDE~03^751; z|9U-o$MH8&INqT{{(Dd>W2orkB7W4wKfkuTH&On|iO=|5l~eq-s-U|Q-H|BXGRSAP zcbijakR71-&;K`=2i=P-eiY^u3OZ#4%Liu@#V^ME87&KXCearX zy_D!+zNp7<*4Q4uCQEei-Qw?Sb@#M1 zp4JF$Prqu`6#5!oBXpKzEeg_ijk;a9?v1Bq?5O8;X6~5FZ>a^@RLvVY7=Q&_iQ3A z;ft6f#>gAX*{;p_iMUJH)0ilgr7@s3(!-xy_)Z*gC{MgG5o6XNt!3gBZ7Y5xUv^xJ zX8f|hXquBcE7>%} zNnN@0Y74*YPWiHJJTF(hsC3A@X^!Ie1K6RJd&a^djC@v78L4!v<9EGUm_LP!RJbBe zmdWOkm-(FNgYKTzrrwcdL)l)GYX>4p& y{BPu2Zg)?sx$k=$vG-+px_eq{&gYl4UEU)#?$hp`)&TdIx_es1{i_k*)A}!V%W$Cp literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/rde_16x16.png b/Z/src/nglwidgets/icons/16x16/rde_16x16.png new file mode 100755 index 0000000000000000000000000000000000000000..d801e3adc29ef73aa8c163505e7605a02a1b1706 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg4W*%WZ^ZR!nb^}e(^K@|xu{b?< zlC3^Vph(;N;&&;+TuYslxF%i*`oSu7RE4WGOhD+U$f9{1t!_!uoo#N;H*yxbExk2s z{{jbPA^GC|Lpes9txrD{*}n66?K{i&)vN+e*;z~bAAV$Yxt^&qnIW*jr=$G%gRHeJ=ud#kx^gZ!eal_I^|tXo*aDuo#gw32?m zX8FHj6Z_F{*8@AX-#mVy?r`PltQXvN*2jJ`&yxPW|7jr0oy1M&FMsB|{xW+7cYOJq WD8*&BRx<+wlfl!~&t;ucLK6T8Z>|Rb literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/system-help.png b/Z/src/nglwidgets/icons/16x16/system-help.png new file mode 100755 index 0000000000000000000000000000000000000000..75ebaf7f5f73f57df9cc93159479a672b49176e4 GIT binary patch literal 897 zcmV-{1AhF8P)ll^X4{Z>T-^z>G~pp+RTU*DH>_u zACN&16chTPK!1pS$uAKU{TieonFJR0O9X{qP?pLdjm$y~@e9tTuJ-NJx!t+Do?SZB z7rZ$h?mq9&`+1(vQL-%KAWcn8wAE^L7>&j%mSuB7q0k7=^Pikf=Nb+|4ECv~r>D{H z_iu`#C~s_R$fQtFBodLw#>T$3wY6FHexFRx-rlY*E-oIi+wEoHa2S(IK}>og;G=OI zH88MSIUF`<5s$|sE|<$$S6BBM1R6W!=H|XEDJdzN^Q@ue!xBbUInahI==5m_(CK*E z@59IMK9FRb!{KNn4J}E7uCA`C^78U){y-3q`u>2;$bqyO#0|Rvcdz84+I9#=eJTd$ z;~1Rb6VbWC!ov4S1Jb=w5Cpoz?T4Vt#=Kv|R8WPMcT;%M^9?7hnJ{xAyde=CE-zx+ z6!P=)&ye#lsX#E9OsBTCw&3=NSfjTQiwY28fIF(jJv$VJXV)>aA|Wo)7@Ozeu%&|I zxEdva#bU`Od&2_HAhac6JtkpOkU%4jTbGaHRo_nxEy)OOituj;?ema9)$a}avK*eJ>X4h59 zT0xdjR*(isk`j#v6oZwOm0^uWgWG4dV8jSWQ{-haXt!(3(4CCYD51X5t zrQ{@bc6L_O*4FluSjeh>ey#qW#2lTBOSUxJsWd|*#naQ%U#hFC&w;ROkTfYR zE$ucK3??$NP^na)X-C2g7Z-Vt$Ftnq+xwRMZ2bV1iB?Iiv@Zcg0H7vfccdYrhyoc5!lIL8@MUQTpt6Hc~)E-vWF> zT>t<74`d<(R#sLZcjd~JYu2pUuwlc-jT?Xb`0?}S&jSYzoH={;+_`fXFI@(LD_5>u zy>{(75ZnNRn;>ut2yTPG9U!<12KPYV{{8z89z1yX@ZqCJj~)ZT6EJxC^cfI5fByUh z2)qP=S1(_Iz-u6Q0|IZ~fxvqp_y7hU!Qc}Ze1?E8pTB^>S0MNX2H(K|=x7iCI{fFa zU%!6;{{06C{(`{2fB$0or-=hS$yXBO7tFvYucE1^A9V86g9rcqWtjf`43s(S>Eakt zam)3Ltv7R`0Lz1$H^19?JYmrl(n(HjDG|H&FY_b+471+eNg;wt9uJxX-rqf2dGpxI zXOc5m#D4TwI(;k&;BsY{qR*U=J%8o;I=iWPy0J}_~Q~;7B2?!w)wuRG}GAU{00LD?e%Xk9rzJ|5AgYSm_o8E8{eh1%L$LaWunyaRav==3@w z-;oa)h5-~s71K1`kSwAuC^&kz@=WC;j4cU5t**eWc`!`0!m{k2VW)~UZfmrf>yiY9Q8SEEsRTS9C8B&3#9}dt zCuv$mrlhCmv|C|9?ydvmt@yp!$aT*KW5v zBo9oMO;Y4e-tIyWLdgkygOG?$NW;WxhD0P1_>2TW_$U51A9elQ(mz(T0000YdQ@0+ zQ*UN;cVTj6004N}D=#nC%goCzPEIUH)ypqR2LLwM23QbN%3J^d002ovPDHLkV1k2I Bi2wiq literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/transform-rotate.png b/Z/src/nglwidgets/icons/16x16/transform-rotate.png new file mode 100755 index 0000000000000000000000000000000000000000..11b457914791a4ff280fccc55634076e15adda6e GIT binary patch literal 558 zcmV+}0@3}6P)FE}@D4lSI;J3i{xe_i}gd zpS$-ijIQgBERE)(v(f$OdTUtvuv>EO)GrDo0|qN)>4*@ris8HL`J`rBS}U-zm}gbB zIwlDug=8Kuq98GvuF*wrU=5@p^qu6gs%e@QB(gFu%L-3qm7ze;oc4lsa1sk|^S=tj zli?zf)OIAMAyWMkP^y=hDgo0XAZ0tkPm2xg^oSzal?3I`>*JO&lmIKnv<~`llq(nG zVA=e50lNud7dd)nKnuBNei#hXpaD4A@oijzd$tU1f)OL`GHUQAd$GhV{}BjU;^MCY zvGA6=j=+>9zA>$#Aj?>U<-H*fd~iyH|Pa+y8sEti-he?7AL26FTdVDl+K<6`GblG$Pvw)Pu4E#_cHEot^fc407*qoM6N<$f^pRCumAu6 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/transform-scale.png b/Z/src/nglwidgets/icons/16x16/transform-scale.png new file mode 100755 index 0000000000000000000000000000000000000000..6dea0c2a670a9f1aee538738c17d4ec5c41a24c9 GIT binary patch literal 509 zcmV71MgRZ*WRTNHiReX&=P-ZpFM#kbfbW}}qoARuq@}B*rL3x} zu&=SSud%keyTQc8%OH2}lBdOppvM$$?h|kC3TW;>i0{~vbn zV4n44qW@*0|8bMXcdYl1yZNQb`Logbyw>^A-^#B_u}mOHK_2=j3>gww2>+9|9?e6aG@9*#M@bL2T^7Hfa^z`)g_4W4l_x=6-|NsAqw$da3 z000_vQchC<7cn}YqN&Bj#l^+N#l^+U($?VN>-zrw{+d^Xr2qf`k4Z#9RCwA=%IOxt zFc5~}39408?KGrA?K@Qjx&Paeob+_O^J~8IKpX>Q9?k>w(Zf12WSr}@HOkW4^)hTQ zoniP{9`9-PG6RAU-^1c8<(q_3r(`c5B$QIS`S$rIbeq|l#MmsWX}j#?B53-qSL+Na zp%u(lawgqe*r6Ks`h}qMF9gHlgaC*lpy;7~B8v~IFbPCj00000NkvXXu0mjfW04hQ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/traurig.gif b/Z/src/nglwidgets/icons/16x16/traurig.gif new file mode 100755 index 0000000000000000000000000000000000000000..8a3f4b2db8654c417a543cbf0a3309faf87aa9c1 GIT binary patch literal 1591 zcmZ?wbhEHbv)eATl3hDY(OPt&?zX7s(zp75q*`p5EFpX(NWZ(jPVXYK#Jd-pPo zg3%Bdpb${}&+X?L671|4;A*62z|07AhT=~aPA(v=19B25o3L|iW?D@pk#;_I!A%;8O|6|mN)b654kRgb3yKCWFfe3d>E;%)(o#97)Y>JY?$Odw?n8=$Cjz>7!_^eYFd|+^N*(GTfkzhFCXh)Z(PTiRTM<(}Hh0rAy zj!G=uJi->67(PyP^$=#YoRSi7p}C_;Q}5XphD67MeDW?m2`@G{vvKhYh+MgFkhw!Z z!KUOwfFe^fGplxriA88rGYd;fP{K!s!>rud{2CeslXO`)g;g9X4k$P_GN_B{C0uAY z$i%|V!QdBhp`nq9nZ?DY<5I$*hT$9!8?nbj;-Vui?K(OeBu*r`xQc1`^e}vEY;Eb~ z@{9+%HEhc_JTUrTNs^G#^YNK%> zE?g)PyOUPjC}N?4Q8$4~{SPXLtth%kR&H7m#dRd4re;ypY)qRrHS?9Z-uIG6fu#7P zb#->e05k{!fq>>ZZeXigg|2IiK=ZB(NV3Yt26lCK!{B$rFi0uY+hudJAd}!G*tU)G z`a164dw|KwtN6C|UF=ChRR&~9$#Sz^_prISg-kk)r%#?^ZZ3tHncJ`&2fcguh?D+8 zpbG*WS1wQE;-w2nBoc_7j^n`oeb5><)Ud>#7NBbl&o(Rg@bME;sfQrnLo|98#ji!& znN4Dr!762+D)}{r!{K;7pU+tAd2IAJIy$--K?FDlac~!Th6n7<@`^Umwap%Tj1h&u)}TCC;a=EReDQp&%3r#edamRH;;GXedIXM^Dhg z!b=*Do}-CV=jqMsG#wi|Nh2ep#3bZ-ULC-Mm{kf|=@Ksn7(V#`FKS-ARDe4(_);ij zJlDn2(z|9*Dl82|K3n(!(=-u@96>M`^ach7#(8#mhl1(p>)gPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iOc8 z6elA249V#L00HnxL_t(I%e9p;Z`x20$A89lB#;}`j73d^%F>~&s5&C1Z2kf)S@;f_ zm?I+?Gb1tPGoVa}u|!IhEy$KDv4R8$B-?NuD6gR)U~q0a>D~R`|K9!Yp2pfzBx@@T zcn@3vdP1N};I{#MoX_WvtCb`IoJwiSOeRw_0An(l>St#r0F%k=VB-0?rQ-JaVHoLv zVF1K&Ob`SB*mm|H@XO0U#qINRxf}or*s|UM5Jk~J;MZ~c{5X#P0Y_0p7>0>-Zu6uD zK%wx7q|MkkKd-JxUtVID%h=^I>3seqfQ9cf?sge>yDWl$9}f@etSBP#T&+sSG^Jyj z(svw*r&Bp*@pLME$5DCD)vAby07W%%cDbx>vP&g&%R0(dw=C>ZiG3J~@!a#I?>OSQ zu5?UOyhh_FW3SOz$GWcc9Y^M#rx>d@PUrJ{yT4yE)pgFY+2abxW+~j>lE1m(Vm8~V zQv1vJF-b*en)ZEbt1V~iarT={hOO37fMKhJ-)wH>^8dPA_&!gS3VyxLpjIOsjgA6` zqY;Bz4ZmLJsZwF#`@78>w%bZJp6kk~wrO_9G-cRs@5*i5?W&u`z1~h~dl&C)#<V5RYPi+ulaS zte_KiJZoMciX!xudf*8Mk2$Pg^D*{wHuae@Al88V2E;GG-NixBKHu@62=|wVT>vW? zAT*F@fc^l+FOS~p`X*E&@N{!l$|GlgVT@Am1Y>JxP&({1ACxNP&=r;EdyT zbPH=%RvE>B>gg?za5;q&iDuHogLpuZim>W?d%?xlmX{KtUajU?iBAA%z#x#I9O#ex z7#c%h5m?a6dTunl(%KplDG}7`dDesvpy(A!zCn(rNo{6lm!UMkG!V5~Flx2zF(TK+ zPto`t%m~38Af?>RrlRl#*m_yrQYj$E@fBluaoqreLG}kub~l2nW5)*=`Zvn~(9Qbg lqjF%Lnm#nJ+}8bnuTK`U*?x�oMQk002ovPDHLkV1mwa*^mGL literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/weinend.gif b/Z/src/nglwidgets/icons/16x16/weinend.gif new file mode 100755 index 0000000000000000000000000000000000000000..a3ba665f76360ae8f14329a1ae624c68182dfe16 GIT binary patch literal 202 zcmZ?wbhEHblw{y%*vtR|P7F>GQTG&+?`dYgv8?_cHT7@H*8fxX{$G0T|FQr7|F^XK zKX&Z@b0F*g{|EmSf3h$#0JZ9Xbb`!aU@8A#%dlkbl(>~UU(HaIV)dvEn<{suP$Hyq z1k&WMHrc04AAI A;Q#;t literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/x-office-address-book.png b/Z/src/nglwidgets/icons/16x16/x-office-address-book.png new file mode 100755 index 0000000000000000000000000000000000000000..8fa59df19f2d14696013181e752b67de41f43bf8 GIT binary patch literal 561 zcmV-10?z%3P)0PyXWdo40uU^cnxdtG&;>e7%1cXa#(Gcl7rChox@c@RLT5CK#W^t^%9 zhBQeS#4&wn)d)ffg0+1G#t?~+#*Q9V*C9x3Ux7B7JYO^q`FFwUTe~ShMdZtzWl?e( zO6fJhr<3^++0SF9vtvGd+~;2ub;Tmfz5@IL&W@B0O9bbJ00000NkvXXu0mjfyYTMk literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/yellow-off-16.png b/Z/src/nglwidgets/icons/16x16/yellow-off-16.png new file mode 100755 index 0000000000000000000000000000000000000000..144a99946e2c2f4dc9beda458a8111e47d253c4d GIT binary patch literal 779 zcmV+m1N8ifP)9XK@@&7vwOS8h4Vae z5Do!>&P0Mh0f~u55(}dw#@HFU0~-?{vG5--h8j&gLu_rVtSnT-P8$m&CPq}0oD%u9 zx6AI$?(FzxcJKT#o0pxL_ue<(`{oUS|3;~3O%C?8%@y+IImSp?2uWOz*9L}$R~sT< zy*4wqHa&f@6;GNI47SEk7Vh--WUmVm*-<1Qma-KV1R?D1`@DZ}Y$aD1x*0{%BP0bd z7_p~LmmYT(%?pm}Kwj)b6;$1$xFE9G3A^XEiMflvuE}W4iysw zq(Jqb=(PgVACZvBFev161BB4h?mmCQx=PmgrZKkXM9Pn50UvUj1X z5B<*;uzAxx>->)sA78pK(VH*g4N6tCefvkyq{fcFz72<%-hxzf3UN!I&eq^KF<7Po zS0w~q5q8W#&(jQn?{?=G&{T3UuDyM5(_mlgmD9e6YYj;o$p#P2=_VvQdf+toAf9YT zyq?1{3J7XBD5=oeC@`JzhjI(JtgUala%|mNHe{GFA_pYjLVa5|wB!J^_(pIm4Q5ID zodswzk7}h1)8JTkJ$8Qv4&S%|!!@5H7E>fqAm)&}jt+2#3`{{GwYs*AC}+n76_Z%k zsi8TE?Yd(lEd&pZq)sR>vj)W%NNR?NYd{++l!?xmS%n#5sCD%=N5Vm?Uaf)Y`f4kc zpa`mva)x#$5py&%+GilugD9th5EvatL!W(w{1a_5P2Rw#q$o?UHH(neO~On?NCg+l zqbLh_gi%CZb|uO#=J`L9xLR3}2*R7;11rm1RUjh85*4oo40CfH&W#IPzl)Ew6W^Z9 z&Ogew6z8*BT2c&#rA0CWA_o~?GT z^6s?%Zf|#>KlP-BM1n_dmzE@M-3jpPUyx3!_w3GHeV+^r4wj-WgddGZovBRR#*wKk zM*p5vhZ_^YOSXk}DS^c$%%wZ~e@m`SpL*xLBbWE=+5PzW|0}=%Yf^99aa9Vg00000 LNkvXXu0mjf%5$!T literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/zoom-in.png b/Z/src/nglwidgets/icons/16x16/zoom-in.png new file mode 100755 index 0000000000000000000000000000000000000000..6b7a6826a5dfceacd46838d29fe3641993a4c252 GIT binary patch literal 791 zcmV+y1L*vTP)p@A6^g+~yr4T(3bu-rza>ca$fvG!nPTk$+*6ojXmxK`5D)If~^WY0Fz7W_6 zMN#lZtIHyA;v$T|hggg($q;2-@0T3W84jZIB`W;@;X#X-Xi2k|J+f|Kcq zd|?iz(P_1}2L}hDe*>WBFZwm3=FoLUBHOG|=EH1!+!hjv@Ka+Jj#;!PsftAXt*tlO z008`M0J+)TUO-2ZG9!U_|LP~Hn=1)0MplgYgs zfH8?g{e2Y*pr?*aEehhMT|8o;0|;0Gh@BJ&zink_7_I9Fg<+T)#7Mw#9KpqlX(UNZ zy?Z>|AxJq6Sf2>=UF~UL18z{!{oqMJB%uIUB4PsJaF|RH!*Om1MAZ))?xZImp=Wn( zPj9{K>R1kQ!UgAsl)wZ+h6$0e0N8B)I+QEr4*Zy3#e-3nhhQj75IjHxaEM`fo*~y$ z@}z9)%*@PCEC6vjooj`8IpPv|+GUG}_e8Kne?e9L5E+PyJhRJLD#WWUk|zi=Gvu#y zIvx230JfW)G)$b%Nkdf`2e09wErrMzI3eHkR+R9|#j}RDbF`1nK6k#lQB_-O(d+eA zzu*5G*jd(K&`*qyei%qaqw}oWKEGi8IMVm1`<~5a)j$9wcs!n}(z3Ek+sK;DW}9}o zTwu@1<#MRGx%qx)XD4g?Wa5lQV~<*`hIc;re>6>lU@$mN5X8E7W1|Kqh_gziGHv_x z9szrdqA1{SI6f;Bin&NQT!*4)ad~-pE(G>bZ*Olkj^nR=K3^BuZ4N}rx3{;PN@iQV0WXUO5bt?Ax z`Ny6~jUI+*60o5~z-*Dg`0&9CTB3*nuugy@LRpse=gMJm5QezMdoBIAR76XVa~#7p zppm_lG_aXa5lU3VFbV%r0PJ@E94plbs=bvE&S3~Ek)!cEbyh^ClErzclx6&zxn&wY zZ*FdG>?i`&g|uun}+d>YQfxD`I=U0HR19Upx5YAGC86@KIcz%#1367mk zr-M2>JNx_k`grFzm*8|dpIR&yc>f3gkD@3*)AS@k5S!7ht!p?zG?+}L{LIq_1RS$i zECzf&-*07*qoM6N<$f>N$(i2wiq literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/zunge.gif b/Z/src/nglwidgets/icons/16x16/zunge.gif new file mode 100755 index 0000000000000000000000000000000000000000..d81ba9641f90a4786b50b0e749014edc869148c1 GIT binary patch literal 377 zcmZ?wbhEHbI56zDXJBSz*kjGG+md0s3BwkBhRu2m z8?_lWXfd!bGOSTySRu!-T$W*}6vJY1hDBlwi$odb3o^{(XPCpwFq@lU7B|BTb_ON} z21bTs3=B&c7-lgr?A^PUfoP!k6KD+(=zs{2pBUJtIWz=lXp6ObIDDLtV4>!|q{l!( zM5y<~Qe|mB)?>|u!mqU0H#sCE1XySo1%#I=a4<0)O8mHDg1;*#Ye-l`l&q45D-S0- zn~$Hcq`ZojE1v*27dJ1Tkc5n)j<&0?Ajb+0F*z|^UCkw4;-Vr3`g-~X${HKJWTmB~ j4GydB+3TgKps1vxw&A#ok-CPK_L4MDFSi>`jttfSE$Uh) literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/16x16/zwinker.gif b/Z/src/nglwidgets/icons/16x16/zwinker.gif new file mode 100755 index 0000000000000000000000000000000000000000..d1482880421dde677d3302940aa875ff22a11b06 GIT binary patch literal 170 zcmZ?wbhEHba9D@n#Zhbsv zutHU>;J1F0R>6zE2`tV}8xE^#?@bGklrZsUYAp!;dbG*vY{CM88Jk-qvwbqQUtQFY Pm?x1IA$CiJiNP8Goi0B( literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/dialogbuttonbox.png b/Z/src/nglwidgets/icons/22x22/dialogbuttonbox.png new file mode 100755 index 0000000000000000000000000000000000000000..b1f89fbb36f17920935f3118d2bf4cb7988eb16e GIT binary patch literal 1003 zcmVLKVx5A{$)_0k^@8dOldL@yQu z-3zRQNXxETm=#v5Rz|gMxohNJTz7V6PUp<*Of#EW1HV0U&Ybg^-}!!jXNMFQd%jjw zRJZ{Um@Z0@a#7PbO?gf&|+dA9E{;l3YlQmfvc9n(R~Xc|5dxKBgFB zT2R#0)kOpj(I;A=*6>Gr@LlvG9g|SxTxfa82tfs7Gh=`sd_Rl9^ezmMqj`$zJ)tD4|6js zM}?Y$=O}1ks~kLJSwd^@0($6u*aLZ3RdB!p)8@z)@Slv6Qlvupgce^tx}zYnB-nD9Ego)bGk}sLL6&6mk+z;B zy-rhO=*=5MZroI%(u@+dO+0yuSW~kKRN;EYW+_s)Z_bw2YoN9ci3l@_mDR-4r=ZN7 zp=LQ$e-4Szpay4sOI3^p*5gO*QHUQusd~B&9)Qf|Iri;U`wA<$_{r0wXPgSt$D$n_ zh&_7-;&#JXvjJqEH09PgNGzIgxu002ovPDHLkV1fhR#=HOk literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/edit-redo.png b/Z/src/nglwidgets/icons/22x22/edit-redo.png new file mode 100755 index 0000000000000000000000000000000000000000..45f0450282ce942502b60692c7803ab583884f3b GIT binary patch literal 1245 zcmV<31S0#1P)GN ziX7vfcqi%eq|k}x&gOVH+=PMHFuKA?gtQRW%IlcUT*b}I0@90ja@-YfNzo}erwzc# zdLi%C#aqG{fKLNq^X2^q9;4l%7$SNArmmqPitsS00WMRKb@Es)tzmlVidf4QCIJj5 zdv^^^48DXhr;cjR&EVfvW4nZ2B6A2%T*Slvo)TfBsEq z*ycoQcgLQ-L?2wXi8~d3mqa5UI2gEKKpjFJ3RLWAOUiM9vbzDduGH$)zM`AH7kUz1 z$W>M#Wb;r+LE6e-v3wh;$}$|`Afh*6ml?-Mum`5*2Lw<+(d%mSbiENCH1^rv7=YQ4 zv9U|Wx{3*mwvre ztNWNg6bL&;RUXDFJV;S6Q=Aj6MhyG3BeXbsLuBoga~UYlOCE$dYwL|8x!T9%b9Zsz6T zh7nc`IIIYlIkLA=<+hZ&TjKF}G>XMyx>R7LWtsVvYG!Ik>vwO?EeHT_$a{KHrV8Mz z*3NjWsa=3u1+@5D5u^qP?x4a7$T=%;xV?3FV?t%vVEG$@ur36OHn&TL>pQq%JD%)& zY_tEs-fqe{ImE*WfCvIqyD80R0YE6Nx{%C!Vs2M02ni8khnG7|0SdjbKx>iU5D1%V8T`Q$(YA18pYu*+>BDdoU0ABFo zFV9fR?x40>*<;bK!9Z&pMb|e3EUvqolPf=I~V0rQ^a+9&fmbde{!pHKS zL-LIj7f>hJ(da+5bWRi;i{+oS?kl@iaiwCTsoIc)j#W?WC)K)TtelQop-6+_AGV8? z=ZJ|zhd=E7wtX~lHrduj*Q*Om6Ql-IA4SfXw0^uI?iHU!)xEBi%)pSZvu`$-KJQm_ z+f?-GtyublB#%Y?7DZH0l^9=TO z29$!FJQQ&C(UsRf#wNe(v!6UDXYoZ>5=|E8;$}$5ZbnB7uF0V9!X1eptB3 zq}Z*?ZBx}9zoK!C6#nC(X@LiDpV)(Bo49a17)hkml??b=d6Na@0zp-0hN6q_4*nw` zc}Vd#PyT*{##=kJx%D*f51S%aS{GlBUJ{Tzl=xAg;1TgZ^n)Y&TS`qw00000NkvXX Hu0mjfQR7Rq literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-center.png b/Z/src/nglwidgets/icons/22x22/format-justify-center.png new file mode 100755 index 0000000000000000000000000000000000000000..1907b44d810bf9f767d1bd5100802f900b4ea216 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H3?x5i&EW)6%*9TgAsieWw;%dH0CG7CJR*yM z%CCbkqm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0vc0X`wF z|Ns9F2neXCsPOmq2dV>-$;rt;#)AhB9zJ~d`0?YXPoF+}_Uy%r7cXDFeD&(p+qZAu zy?gih^XDHwe*FCT^Ut3@mR%oC08L{p3GxeOXlU57rD@T2WuQQWr;B4q#jT|mqWKyO zI9vjw1U{}^@%#QN&Q9JR>D6Wh#?1Qzb-NVs^9_r|T?*M6#gWAtn0jUTU>XKS-2ORfF?0B8q;r>mdKI;Vst0K#sE A#{d8T literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-fill.png b/Z/src/nglwidgets/icons/22x22/format-justify-fill.png new file mode 100755 index 0000000000000000000000000000000000000000..eddb7bfa7c1e9fe8d406115dbf8d2f9bad67bbe0 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@I3?$8F6>Q0G|-o z|Ns971O!x6RQUV*1Jwb^)z4*}Q$iB}3(9C@ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-left.png b/Z/src/nglwidgets/icons/22x22/format-justify-left.png new file mode 100755 index 0000000000000000000000000000000000000000..37a9c5e0e2c28b7edbf31bbc1d905ed10684a772 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H3?x5i&EW)6%*9TgAsieWw;%dH0CG7CJR*yM z%CCbkqm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0vc0X`wF z|Ns9F2neXCsPOmq2dV>-$;rt;#)AhB9zJ~d`0?YXPoF+}_Uy%r7cXDFeD&(p+qZAu zy?gih^XDHwe*FCT^Ut3@mR%oC08L{p3GxeOXlU57rD@T2WuQQ$r;B4q#jT|mqWKyO zI9vjw1U{}^@%#QN&Q9JR>D6Wh#?1DC@`4ik&aOOe#;bHFVMDioR?76#30|Kr)ozQK z7^CN?`ssC2Q26P}7uQYI_9xcW$GYtozMWsour{AHd0FQ9=RivsJYD@<);T3K0RRx2 BhGYN$ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-right.png b/Z/src/nglwidgets/icons/22x22/format-justify-right.png new file mode 100755 index 0000000000000000000000000000000000000000..404315b712a2fb21196963f4b2aecc2eac93e8c1 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H3?x5i&EW)6%*9TgAsieWw;%dH0CG7CJR*yM z%CCbkqm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0vc0X`wF z|Ns9F2neXCsPOmq2dV>-$;rt;#)AhB9zJ~d`0?YXPoF+}_Uy%r7cXDFeD&(p+qZAu zy?gih^XDHwe*FCT^Ut3@mR%oC08L{p3GxeOXlU57rD@T2WuQQWr;B4q#jT|mqWKyO zI9vjwHayzgwd?=dSrcwF)StR};4Dv#`(F12rC{JFLdgb*+^`N12z`^RR=;kCXRKq z^saxn-reKxu#k?>7t8$RzV|%O_4j<9-+k}7D`{(M<4h*gTL5r@5K=}dCI5%O<#L^z zo11$ykw`4q?RINXQPIP_y}f^u+YD}WbkuG%8iS3EjrY~m)F>St9p3_g6IV?_`9&LH zlxML7p5$0gP;YU<37=O1k*k5QzYo%uvzfq*R;zv5?RFPeS653tJw438z(7)`)3p;d zSosw^KSTiPNp$f^7aYq&=&N|Gk`npla`?oS5gZH#7hl2jD8_}of>FG**u+wCN*biMMoc9GT1phJU`=8PSz7;Fh?i3H9 zvGL7I*RF+fZMIMrz@361%+=P`{sI8Tjli9>bqS}PMWkBYjFp%NZ?Xc0p%D8H)J4M^ zb^02e?mUYzHa2GGdHzC4NeS=s`D!p%$yB+z$S`!-a40%y>pYMlQhZAwJ z@8YJWrV-rF5su@wpd+(pv-#Kl{{9z8hCpZoHZP(8^?_=IEd^C$D^_pBoif|q-MzP> zq9R986dpY;h(scLtX69?$s7-+pla+=!G6^0o94xed9{P^ey`X28pALVR8}|~UdB7| zI2?|u4B&IAHi`Oe)ng6^T7<^dXCtf~?S2HmC--9IlZAza1rrk!JEPI){04TIu+gB$ z!4+^9f!%na6m`0l(3y2$4#8*g^Yg8uDBgqc5&X7@IBz#9zLp4}$8$rf;_so8k{#H2 zH|39-_zc47I(Qy7gW1{H3cl{!1A)NQ-6aK6m&OAPY2d?nu1$@;Rz23Gna-lL>Clwl zi`eYN+s{=L`Fiudvf`sJmDW{Nl{wPVa?)#2!6T?X)FkRSR=Z3vHh_=o^;xeUKG9iqpB-y#6=ni@M(tLU(NA z!?}cC%mqGVg2)XMBZSm`4hT5TOD++!6atI1L@ZL6SmZFx$9_Jx$;3k8$?H>-$A%}5 zV4c$H_k{bgbKDab*t>+VmW@R;nmDgv;!#$U5Ew2IV>vO-Xv73)wDK~iRYcGcN!Alt s$_8075Lq;mq%0?6S66ozMpA|U3(7@KL;Q0ORsaA107*qoM6N<$f@x<@9{>OV literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/format-text-bold.png b/Z/src/nglwidgets/icons/22x22/format-text-bold.png new file mode 100755 index 0000000000000000000000000000000000000000..a5535e33f58960c2585f4322774c03656ebef3bb GIT binary patch literal 667 zcmV;M0%ZM(P)MzCV_|S* zE^l&Yo9;Xs0006SNkl;75{v%%0*P;+Y$g;{6*KUoU`}l7t_+s83X!dTs{DVfV*7(t{ zem57kIqcvQ&3ixr=c?0x&aVzN=H?ok{`%nh@^!5&*>C<5Pyp0wS)JPZk-){(VfBIMkWwZcUGU%d$lpi;;nn~0JP)jK~#9!#Z*6N8ets$o!nvUayP_?&q+gv2F*5Hj3S6hyG-Ac6*T@(=ij1jRqq)4RU!pqVO-cZNK8 zeDM2@$Gi8v@8fh`r>6iEUqrX4$tkS^?wn_`S#DA-mm9Znv8Wyrd;qNq96G-3v#bRF^4u{Mlz`;?k*HgRQ?uSGo@!hnrEXy0BD9WKw z=wXIN2+3q}hXB)uH=RyrlgXrw!(wePSS%I^xV9vW7&O%E)Mm30;vkOWs8XriW9z3S zVFozf4Fm#)TiiC*-z(&+S`x2z)a#9C3S)if5vI)wLp zKA+*XUaym?s=qMnuS59FU*UGUO~5Oj=Ld-B66CG4qJtOB5Do@|BuUa1t6el2J;Zw< zVZUeAv64=wS+=xTENC{HQ6v)4A^H`~Fhos1oA~7;EGOU#Fb95vXqNtiKXaoOF{ut{ Q;{X5v07*qoM6N<$f`K;}TmS$7 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/format-text-underline.png b/Z/src/nglwidgets/icons/22x22/format-text-underline.png new file mode 100755 index 0000000000000000000000000000000000000000..e511395058555e47b9e0ea82b3b4375b1a49e480 GIT binary patch literal 537 zcmV+!0_OdRP)MzCV_|S* zE^l&Yo9;Xs0004)NklLrB2M*!4w({4#!k9)DhgdHDV3tpL}G#lZ!|Scg5N%fzL&fqL-`Je^W!rdP6PK1 zy$#0}VrzaHtYW=ux`oZ{{&>|o&UbcMuSAbcv{*R8o^G=Q zS{zu~L!`7NR&02M1Kpr zNAY75clb%7TNT!f!X7Dxk>@6UKhH6#T38Z0WY|EyN~g5RGnq7s-^h`viI+Z-BX|3W zDZ1$A9SJVTldFkayYt(e-+k5}O8n)J1-+j-u*F{**=4p#b4G&C^p(5IS+cxFnq64= zBbk*gNy>?QkyUviqjDof*_1{%uAhZN@ep;2JFu@<;h_=*uE>)m&Cy-Hq62&49_keT bk2n7VQXfFMF4Het00000NkvXXu0mjf4Dag% literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/kdialog.png b/Z/src/nglwidgets/icons/22x22/kdialog.png new file mode 100755 index 0000000000000000000000000000000000000000..d25dcb9a7a8db240360f3e0dcf1430a46a6a4f44 GIT binary patch literal 1045 zcmV+w1nT>VP)D?l-+B?`C#)>bXttwp>%AQnBTH zgk5gB8VJ*}jUFHhVvs$sC{78BSSoEniy+-3Z#Kr9R;~v+ltIZT(4l72>_MHZEp(pY zJ^0Pvkrw+SZx!_V`^THl=L^4&ioeircMJc_B>#lonuPy+&uUKtkW~GYnC$N*-)6$% zvJ-F6b2F~a`w6Qxbj)Okq?{d0zW3?YEMio{q!ez-TlQ4YgX05CU12 zxiIn_Pd6NfOM@zvvc58@5-l$;Cp$YEgTa7St0h`WSoOz@9UqPQ*(p=HEhkuCoeCTo}Qln zHe7ngM!G-zn3k3n=I7^8csw4$;V>&SMB(H~FN=#I+S}U*1_RW24lzD9O!i%w)YQ~) z?b;Q*-Vdm%s-mr}E&7Q&ysfxg8>oD6AGwZshFTwGto;CsLnp}EnnGh!BSROzrmxS( zz`y_s&B`ws3WXx8NRq^jde8S$G;k5q;A=cys6#DV(8kIX$RIUc`W_alTL5C{+(8;io{^HE<{kI`tL^}Toaru#5uck7Ul`RYqQNI?qsl`Vg7 zqB{2!*Ij$~d19QSjZNGVTtK5-q@Lwlkvlp@MMVX`YPhxaIH6FO+1V+uFA)p`(V9#g z>laMTh3Vcs!}>TEwrxfDLrc`wK8y3V+u8rnek6b-ccrK6Y$sctsVoVBH9kJ_ECof| z`Q%(D7E2tN&KUHeNn#SVP+XcrN}7#3ODjPV{5H3MygrL3o_vfK552_qKa7w3{XGr^ z!9T}F9dvbd5;OKHdRaoZsR+y|pwY7U%LEJZJ+vG@L0$dpBfxXORTXP+Bqe|G>F1vn zzI*IV_UwHCr+F4la2l;vCal}S0`Z(Vdz$>%)OkWYZ?kf?%D`tzi#gSqY8&VPl-~lW|K~Aul-v-J6yVYiGc)s?axI8s2 z5)02IbI*HZhmQy-a(eomDZ7Qtj+as-kP_daBGV zNL@;rV#FnrtPz?`)Me6Es1S)Ib&Ht8Im}_-{t5e>^FHtMob&$pypKp>1S1#{1^|Fj z5HT(M!7Sir7WR&CxQV5k zF9HEaP}tTKHWF!V6Q7E*L)hCP9qf^g$88;*QKwEixw^WZ#yDd=-952bFE6YY?RP&v zAOD9#xbrw14j&NUjmP5xz1#^zJR$Kmk>E=t5{Qv8!9n=opy1#Td{}5GiA0JZ5u?IG zqNAf@t|rCC#$KY*boTWL44GE%ac(|58cIpnj{ zoOEh#HWj3>gqG|@t7R3C(M697NkH>oj!XM=G`9niP!^49k!-GPhKqwUc z`FcoHFTy#YXhvym)bKM<#qMQ^=NDG4e(aITI`I#K}i; zOyIl&^2BuWxK@Ncn2DdULvX zb7x;8uGYM-)JU2&e|Kt>Y|Sc1v%%Zm-rn8a-P_yS-`_ttI5<2!JUTiWkYbF$3LVdi z2#W+O1%(+H8k<_Xd7ShADwGtLdoPdnpsKO0Qbyiq&lb3zH|Jh+P8j$X&{F%~onlQin$>46 zX(2B$1&wB6Sool?RiN;5KT;7DFjMEFS0eJK9-lWf^$Cu!|>Z|~;oM%Eqtcm}J!k?Q|b zhI-lII*MG?40##m)Ad8*q==UuQ`@0#IHzJ^&^ooh_*FG0(O=zN+lr3%?A%C5Y+~>M zqnk-5dy-O16F9kw<=rUnTstVD>E(kigavj4knjHo6x0{5 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/layer.png b/Z/src/nglwidgets/icons/22x22/layer.png new file mode 100755 index 0000000000000000000000000000000000000000..afa9a344cbeb504b669d69405cd7e6b972d8c96c GIT binary patch literal 570 zcmV-A0>%A_P)u zOf8!552*j6zo02-U(jP$P^+j#(E|!3jG-cGeAJjD-O^0G_sk-#(XkeJ&gQ^5-w(bI z4ly$-DWM`Y099ciA`1ZZD|dIyoO~1Tsn)bM+~F~pK2+yQk3#X=Y`fFGAGnN;GjsOe z9ThSlBAd@?Us@O&u{C|Hl}jPVk(f9-vk*GC2oExIq8z{iz|dM>H#P0=b9cF%&*_Rp ziXf2kTS|)Gre^PsBk_@#B>gM`=o{?2uEBn7m9Zw1-r06I<*d=D76kxcImeuSe9#Jr zWMrAvgJ*I$A$k9^U~Oxg?_HeJnceOpp8ya)3Tjrr`x7^T!0?+E%x>3Y_m4@3{mbX) zFa=SRNfedT)wODQV2J;mochzTSg{3aq(h9t0TUGMu2pZXYSCzP#wS9S6d|R$SE~)@ zN+u)x+T5UI^x6jiU}oeYHgsYS7m&ea`V={IVhez|pkd}0Kps*JFIKRRR9VOk7(EEW zispibN`HZf2p&wpi?67Gt~5+Mg0KpSFWFO+!F#LXXQ~+R7ds~6VG!!0T>t<807*qo IM6N<$f)E?=qW}N^ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/lkm_einsatz.png b/Z/src/nglwidgets/icons/22x22/lkm_einsatz.png new file mode 100755 index 0000000000000000000000000000000000000000..40ec4c08d427b412ed77ac82cbd90caa749216cb GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)k$P6Uwug5$9QfvV}A+G=b{|7Qd4_&SUQcNX5 ze!&d?qbDkD1@e46T^vIy<|HR1T*yjDNGK>wNJwNb`mv)yrczKLaTkNf5}5=>&jM3} zDRKfS2`_>J7&gir=#rL*kdTyYSfeKJkm<_l1&m584l!(O3_6#&oeCzYF9Mp&;OXk; Jvd$@?2>_vKFpmHL literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/pushbutton.png b/Z/src/nglwidgets/icons/22x22/pushbutton.png new file mode 100755 index 0000000000000000000000000000000000000000..61f779ce2bf0c468f3c2e72c8b0d6cd15576be62 GIT binary patch literal 408 zcmV;J0cZY+P)=6A zNtD}P!MXXTj0QTumrDxf^Y0b8H3quGH)kw&M%3&Z!Vt# ztp0P)=8v%5p)27NN&e7YR|;DU2J;QYTZXGJT=WqD0000S literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/22x22/scricon.png b/Z/src/nglwidgets/icons/22x22/scricon.png new file mode 100755 index 0000000000000000000000000000000000000000..9a2b5c7b87a462d5bef3f6e6ab80c3f928a8cf6a GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^GC(ZA!3HE*&&$6DQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfEfy&rdG2S&S1kYvE%tPA46!)< zc8Vj{Ap-%|`}%T6Cm)^5&3_?T)5z8y9ms;GEs_ zKg-r_mVa)3Lu>LQ&8IWY@G-x;_IPg10lm7zp<$kLU({a{U*#-w{u(Fa^{%q@o>kR5 iTCVP&{;x)VFN3mmW|_i+%8NkfGI+ZBxvXSd8<^C((ywd*CjF;u#e~4b!UcGu1I|8+}wdn3M#u>h> ztgJuncKeTYb#;%Mo13dzTU)Ez+S;nRy1J;lyIY{Wy$U$%1} zcJ&P+)JMR|-4E&M>7C`}*YOf~*pkWS#@Vuy~h#DIk z>CT-yovqkdNX>f25A{3cbSy?IU8%02bFe4*_?3@K(WMq=p@1x^SpXdWC`M1}vDI!Ti-4_=Z zsv(=r22$81#6}er6~rk^IXO8X1QI}8M<8Jrin=Wv{-WEr$x&`66aV&kJ#=>Frc;-T z-0m~-F%hiew540Qx%4G#CoeCLGBYzV50ct!5%!G;2nDGmxM#=c8Avx48U&Y^NQt~# zE2|u96Zto^qSpq-TEM=M2FzZsSDWi936li`m>7@YEDE$c)z=Q?$jn9rq_wp*2=$?0^`>FFtrjgQmx?=!UV;RAU*Ua%1mf12tS zr8J}L()|29jkAruzCJoUJfxbM8e!is3m~Y%!a_>n)Y{qJp}Dtj>DP$~N=izi)YMeU z&dL&%G8hV}xsGSZ02hlBM;PK~Wo2a|oqKwEKuC?M;Snfh6>0T#eLa2i=n;MY-2gr9 z{+3!EKBWA-e5f2mAwE<(jG=zqiuCN+Gf_JR1_r33qXW-0<=XfNEZ7|u>#N&Mt_^VR z3wksChTbtDx7$tEaLx!t*m*c4oCbqI07O(0aEjf|%*@cp$O!fK_X}}8c<>;; zEP$wx1rXuKzdzE-$_l-F`4SaSTsrCeJj{;ZRJrT1Hfeob5cm0fm_rtbH>%#=UNOJB zyBptKfSmwoHk-(To9SunIECEjdD^K)5oyJTXaKMg7lBO_ z4MkL84y8(h#fP&G27(B)*xlvjB_PIrzaLuAXMyVc+2&Elan;fN?uuACD*Bo z39vSTVG8&IBqG4V^2h**AQMv}fZa|_P0{f1Fe)N4VuT6S!oJaWf%0KOv$M0g+;u8n zMf}#2osyD*I|93c2(?*&`v9UuBvAX0HD5Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*k_ z1_v?VpO^6f00T8iL_t(o!>!j{h?P|o2H-3yCsADkM!aFwCr(GSBJe{a|xAbNtTC zS+F^Kf8YN0Ui;nede=Ji-X6f&btm`Da+7%&!Z6Ok5)9%YjN%a1;G5$uG*ENH({VNW z^Ud8@+hP7z{M<`eKSZNVYqqoo-s)!IItW~go3lY*jVt}O8wdJp%z2{=zBF-eFQH$K ze>%Y3Y}3BRDZN7A_OQFJI3axB0g)?ka<35B+vbE%;F%dtU$x77LBioeP@ckH*p83! zJhtFip$k=i5bL`oV>`Pur}kAI zKz>s}%&i#9_;Fl0TL;Fo$W`SjR15Zp>CG9w zAH`3Fc-_;j1M_ey{!UwxXMI_8>2btq48IibFP)78i$bs|?8It(5eLp{(S=r9gM*k1 z2j1^C3@eBaC;YZ$vklmXRrn02MfIleD}GBG$IG}5A0&03*(Rc9gm6(d{}C4^#w)a* z%cjHlDo{^^h-Y8~m*Ew>R;)RcFs)@nIq?s1a&3gALSah_>({l6kKo?)|G*0~q21ph zt2K-Mt+)f%=hTZ^=Kt4*Lx=EWps$|QF3A>#M0;^T;mr0ZFpeP_?h%SR6PZ(J+E{iuXtJyA;=? zW?UV#WWxmo$`gsE+728I{3qh1sNkk3+`+U)jp}G8?kf^oZ5?Rj#G^rA03QXF`|)u4 zt5PlRj)VIWE!*;Xu1Qu|B_zqK=2WD}q2z9jI(iiqadB?{_8p?ZMm0khSc8 XINb;)iY^yJ00000NkvXXu0mjf004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000U( zX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHz3$DNjUR8-d%htIutdZEoQ0#b(FyTAa_ zdy`&8VVD_UC<6{NG_fI~0ue<-nj%P0#DLLIBvwSR5EN9f2P6n6F&ITuEN@2Ei>|D^ z_ww@lRz|vC zuzLs)$;-`!o*{AqUjza0dRV*yaMRE;fKCVhpQKsoe1Yhg01=zBIT!&C1$=TK@rP|Ibo3vKKm@PqnO#LJhq6%Ij6Hz*<$V$@wQAMN5qJ)hzm2h zoGcOF60t^#FqJFfH{#e-4l@G)6iI9sa9D{VHW4w29}?su;^hF~NC{tY+*d5%WDCTX za!E_i;d2ub1#}&jF5T4HnnCyEWTkKf0>c0%E1Ah>(_PY1)0w;+02c53Su*0<(nUqK zG_|(0G&D0Z{i;y^b@OjZ+}lNZ8Th$p5Uu}MTtq^NHl*T1?CO*}7&0ztZsv2j*bmJyf3G7=Z`5B*PvzoDiKdLpOAxi2$L0#SX*@cY z_n(^h55xYX#km%V()bZjV~l{*bt*u9?FT3d5g^g~#a;iSZ@&02Abxq_DwB(I|L-^b zXThc7C4-yrInE_0gw7K3GZ**7&k~>k0Z0NWkO#^@9q0fwx1%qj zZ=)yBuQ3=54Wo^*!gyjLF-e%Um=erBOdIALW)L%unZshS@>qSW9o8Sq#0s#5*edK% z>{;v(b^`kbN5rY%%y90wC>#%$kE_5P!JWYk;U;klcqzOl-UjcFXXA75rT9jCH~u<) z0>40zCTJ7v2qAyk54cquI@7b&LHdZ`+zlTss6bJ7%PQ)z$cROu4wBhpu-r)01) zS~6}jY?%U?gEALn#wiFzo#H}aQ8rT=DHkadR18&{>P1bW7E`~Y4p3)hWn`DhhRJ5j z*2tcg9i<^OEt(fCg;q*CP8+7ZTcWhYX$fb^_9d-LhL+6BEtPYWVlfKTBusSTASKKb%HuWJzl+By+?gkLq)?+BTu761 zjmyXF)a;mc^>(B7bo*HQ1NNg1st!zt28YLv>W*y3CdWx9U8f|cqfXDAO`Q48?auQq zHZJR2&bcD49Ip>EY~kKEPV6Wm+eXFV)D)_R=tM0@&p?(!V*Qu1PXHG9o^ zTY0bZ?)4%01p8F`JoeS|<@=<@RE7GY07EYX@lwd>4oW|Yi!o+Su@M`;WuSK z8LKk71XR(_RKHM1xJ5XYX`fk>`6eqY>qNG6HZQwBM=xi4&Sb88?zd}EYguc1@>KIS z<&CX#T35dwS|7K*XM_5Nf(;WJJvJWRMA($P>8E^?{IdL4o5MGE7bq2MEEwP7v8AO@ zqL5!WvekBL-8R%V?zVyL=G&{be=K4bT`e{#t|)$A!YaA?jp;X)-+bB;zhj`(vULAW z%ue3U;av{94wp%n<(7@__S@Z2PA@Mif3+uO&y|X06?J#oSi8M;ejj_^(0<4Lt#wLu#dYrva1Y$6_o(k^&}yhSh&h;f@JVA>W8b%o zZ=0JGnu?n~9O4}sJsfnnx7n(>`H13?(iXTy*fM=I`sj`CT)*pTHEgYKqqP+u1IL8N zo_-(u{qS+0<2@%BCt82d{Gqm;(q7a7b>wu+b|!X?c13m#p7cK1({0<`{-e>4hfb-U zsyQuty7Ua;Ou?B?XLHZaol8GAb3Wnxcu!2v{R_`T4=x`(GvqLI{-*2AOSimk zUAw*F_TX^n@STz9kDQ z$NC=!KfXWC8h`dn#xL(D3Z9UkR7|Q&Hcy#Notk!^zVUSB(}`#4&lYA1f0h2V_PNgU zAAWQEt$#LRcH#y9#i!p(Udq2b^lI6wp1FXzN3T;~FU%Lck$-deE#qz9yYP3D3t8{6 z?<+s(e(3(_^YOu_)K8!O1p}D#{JO;G(*OVf32;bRa{vGf5dZ)S5dnW>Uy%R+02y>e zSaefwW^{L9a%BKeVQFr3E>1;MAa*k@H7+jn6#A%z^gy|{oWC0 z;u7GslYJ>(^mF4-XSdsV0tH?+V0d!hv)3NB+bwFy1}v{M4_()xhHSv{O7pPUY*52F z_jTWd<(1}Pygbhy!s9^qf-~kY4n2qgv8tL z`rPxYpFqGjYFOBcGjlXsH-0z9+0I!o-5OVik^mF4+ Zog1Iwm|;dtJ9+>B002ovPDHLkV1jWM2Z{gy literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/marker-end.png b/Z/src/nglwidgets/icons/32x32/marker-end.png new file mode 100755 index 0000000000000000000000000000000000000000..e8126dd82db88db596b3008e860e308f1a07bca7 GIT binary patch literal 508 zcmVTp;2YTa6oN<^v5^o^Gz!7w=A@XbDC*AKy?P7()v}y3-_AL6zMaTSH6r2?)^QG# zYQnFaz-PSb8WYxVAJ+zmePb8TmKuZWWoV>T@UPKY(hqozkNB$e@vKtfaZlb64zR3j z?sSu2W^QBq$9EC2jz>y=|HKkT)8|8cnWvTkk!%rF+cWaeRJzQap=>Wl3n;uap`ymA7Ea8hxS7biMZN-^d8Mfey21x(+HaAEfV0000Em0VU@!!inu~A8I0Xl_Bqf@&K(J6^i?FLS# za~EnVokBFCQD`J~XvD{UPqBR*gjqAQqwpk?OlIDdXMN53PhbX1+R?{BX5Lg4b})yv zmcl!np;9=~QuIQux#TO47xsjNiU!=AyGzsSsNBP$U;;V?7r+loqsfrW@z$Kw!O+a+t*!8j&b z3VRs+@elv^3rp7U7MB=p>3YCjl`wIZnVT(TuT)KG7poDm91+vQ5LS(F5-ZP_h&aVg zNwR-M-Ayx(ji$0DLIx*KohW-p2ebH7qs;@hB0gpGQD*L!2>ZTI_>Xk4_{F07*qoM6N<$f?i#^6951J literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-eject.png b/Z/src/nglwidgets/icons/32x32/media-eject.png new file mode 100755 index 0000000000000000000000000000000000000000..96f7ea9bbddc64c802e223bfe5146e13b17366ea GIT binary patch literal 1197 zcmV;e1XBBnP)kdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000CmNklEXYG@4WtTcieUOLZZHf>cU~ixmG=CQwP!Bu-{B@7?Ri zc@Ik&$@{qT-kp2ScfR-TJ?FSU=k->}A9Q1kFeE@-SPG}3bFa2KZ9532hQb8T`)a@w z$c>25*kHy@j@Ne}nCuSY9P^cgHZ8VEMS`4Tij?T0K-6H`O-(fam*Dlm@Kva#H2H@} z+J~vq1Db7cl{#LtZjreKcjS$g4ubKA!WlojO+y6x*voBnTTG;5TiD`fF6zIE)I?X^ zp{dKa5WF@RF8bjn>kP1;-P|t8&H#Z_NTg(iGpy1l8d25NwJ@V4_9*+Eo2)LV|O$@m+T+((ma)LGee#v}BA;k8L?l%HI zQt(5m1oqKovV$4b`Pz1Ui%rqCadLT&J&a@ort?k`*}EYTcs=x*e2cG`$NAfmsVRyz z-6M*kncxKdMiB`EmTG<|3JAG4G!j0Lf>l=dohvMB6IV@z*Zp|*F>~u+h(bMRvYFEa z=J<`GptPY^DK(&|eR?ia;#WR}+-@zSs26-a+~+h+@Iv4yFR;^<63p_N5%_u(mLL{) zTT9-S!w&9R&Fz-trTJ1JoC+_-EZe3eIl(a+w1hT^W{yIBj8E8VX16E;%}y1TC;%y=UlfPHeSluM!g)VbTi9XLY7yG5*N~HrdMGJ~enl zYG~Wamb6}xwL(tIlS0-E7>#RXzQZw^Iowjz@~UXj&nhp<$bCUxH;d}CDyqS1@*bUo zVTwX_xXEgwxnEN)TDH3ER8(hg7FDBASr5YrEg6sTgv{bRwL`Aydp^fm(#!qO?B$Ne z^2{J=EZ&6nC|w`mF7A-abwyqjHm%@^a)BdrosGpPthI%TeKI@TAul6V=mcl2ZLYaP zbA8&HYp4cuHUb-hHP@3nG}oIXrErijHxlyp?&`{z)9&2KR;TU1R|o($|5oix00000 LNkvXXu0mjfH6JeA literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-play-backward.png b/Z/src/nglwidgets/icons/32x32/media-play-backward.png new file mode 100755 index 0000000000000000000000000000000000000000..83c9d8f53e96332cc47f76f241759a4050bd42db GIT binary patch literal 1138 zcmV-&1daQNP)kdg00001b5ch_0Itp) z=>Px#32;bRa{vGXb^rhab^(3Wg3JH_00(qQO+^RV3keP@D$@M&#{d8X1W80eR7l5# z)lZ0BXBo%w&-L#rlH(eA#a3=`jLJ>g) zap6LcuKd?1XuA+xlnxTpO`B9HgrZHGH1?luO}z8(-rRfUob$SvGt)awsn7O(f8Y1v zd7k(8gyhz!y^>yX!=_F2_1)%f9}U_2+zsyqY&xGV8A}>FXF(M7+~Z{Ee-NN@K0RZi zvSp%FYY=4$T^+fu`epA@8g(z5z8@qs z8ns;Ju!swSYgW=10+Ds+l!k6|(tZQ zJJ2+8U5gI8rsH|}n`#puYZDBu{DMc_(1^AqnPTc!BtywvUNqxP`9Q65psjciZ1}am znwV%%2?}K^-=2w}V?m`hkPkF!`$bU@{LN$DFf=k&i@L^!ZoE7DqA1r_YYgPugSt~B zXw*uZ)~s0*?6YX!6kw;M+se3460Ax{_@p0LZZAb0oi?+bNUd~Jkn9r|B*A|)8cD*u zZ~CqS3O#*&JstV3JZUs4tAb=fJc!Ic)Eae*-~nfS$((uf=JeVwY?rW6+wzJG2gQ3O znHSWmDFBOpv7kWw$ytNi@xXk4w{wP)JvtetmumFmy4V^TF4}i8Y`8m_du5Y)Th-d zrPA2C-y>5vbCk&9)zdOvSFE^cVq#0JR%==-ne~V*6B9RWI_EWAnbQ`pwvKcrTuPVC zcmk)?t^4da(vG2(#x|{Z%8bl0XTp@Jt{(Z$mFr3)$9&E03VG{^+P;@cultREnN>L8 zhesE$?y>b((~n(OnMl6kGp!?qws^IXr~OIPl{?_uJ{)dYEUQO;a^)qB(pcYd$K7s8 za>F}b@J~ZMh3IbIYG1!)wQYGk{n=QpwzWGGL6o;X+4DsYhRz2q*TJbjKJ~OwJCkYZ z|IK>9L!Vz-`9IrvJCjT4Id2#kV9Am@eabz1UfzlS0k0vj7Y8mp)c^nh07*qoM6N<$ Ef|n>G-T(jq literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-play-faster.png b/Z/src/nglwidgets/icons/32x32/media-play-faster.png new file mode 100755 index 0000000000000000000000000000000000000000..41fad66da5b6299f710b3e52dd53cfb6d6abfdd2 GIT binary patch literal 2335 zcmV+)3E=jLP)500004b3#c}2nYxW zdhoH;XJAG}M}H{vuLX|yZtr}_W(f4+0R^BqP+xRSvbW2LXfCkPWZ3UB~q z0Z{P)UE#~wLgR}N7Igi305^eQIT#j!U|b4<3&I2l0{~9I^ZpGWzfh>l!W1E5;Jg)# zZUaFu#+bo5*EC(zG{%^wG4g%#eInoYd{-$&L<9y2V#lCV4}jF=pnepFF($yZJHc2p z2tiW_LzpHPLKG>cW=z+0c%BCUAR_p_Pf|*+APcT6NCk#0h%UP-;a(hTcPVZlu|5}O6l{hJR(A&P|zkPC+CgPbsZ0G?Lfzttq24HhA<2P z#+m_KGYw|S72XO$&<+I6+L{`4KD7&+a}W^{iG;a#@7|@~e*3MZl$w<^uIsXsCr{c3 z4<4)-8X6Mw0ddap#Eu=f?%Hb+3ZR4#c=z4YmMj1`j>EtF^2^09yzoN(v17-g z>2!M9l=!~S(&@A~di3a$=bwN6XUC5p4`s7iZI0E7U*B^t;_*0yX>t$*bbU2rjFp_Z zi80265c>L-7I4mI{UahmKA+dmoH-MH`Q?}EKlX0!a%sZ-bN-o1PI zkt0W9sZ@&31TqW*EzQjkLg>XQ`gv)Z7#LPe)f$a8uUj|Em2xqq6dM{Evb(yv>bkqT zs}qTYSt5UwP$~`U3|JR3?*2F=GqC`sNmBn#K&yIT+OgU{e+_EYi5H zF~+cR<;r}iLI1kBO@chef##+3=a=mn>TMBuC1*t z=(C>lUAAa~@VcD`}iC8SAgb)Y>0&pCM0U$6YH58Bo00L1i zmxGk^R`^+iF$T-By!!h3%q_RvazO~;%@t$Ywpz1h&BTTc8%9H+kOu%#O5}1m5QqRU z5D5;z0pR(*PXI77I*Pj5+694x!(sR4n{U3**48$ZNF*#>*QYHTP16vI#R`p$jico` z0|29AV*r4nt_!95IRFAEyx>9z;n&vIPPVtVe|PJxx2B`fsG521={tNF zzVDN(lmg)_04lxYI1!PQ(mT}G2iJAy1hFj3TeWIcYTLGLgLmC^*ZHcdDz{vOF@|6; zsMfAsdvW{r?E{UCjT19L06-~)-b05VrSysitP=phiHI0u|AL`QSty8PGRgP9{~jLL zeE&3eY};0=SFfJv=;-*qp`jsbS(ab^yQXOriA3a$H{LkW-rhb`S67!8Ld>d|M1%t$ ze1M_hA;>~Ofk8rfUl9>8A}Uqwc7Se=MWc3IU7hyNBS#Sqhe1R*ckZ0k)6-MY+S+=) zrlzLAIiDsXrDP{goCtmM%{RfOrl#@g>S{S(&N+^Q+nX9OFfiaxq*4yRK7&&Get;=j zycmYwDYy}iM5BR+Iv&Kcot@yELn*}^$I&8@h&Pu=@yx5auFGuOo-?L2J%9Mq4!pH@ zFH-4L&UM{1T<_0BG!9HZTwMfFpLAWB%jMiRySwm4*PHM>51ey~Mx*nJFveh-rXLE0 z=8f?@4{vsN;q7~v7cN{~ zM>zvZfNSf)*m@9x!W7&Trm@goTNVncAf;REwfms_Pp-Jvp2MXmIRE8U+(LW|VB)H7 zA?ARxpzAl_()~3~nfDpj<*R zAo_sBOMo5Ju&M-LDWz2)U}0GnT5FWjV-(`!`#!Gg z;y4Z^r!J62@viUkHjoq%Z^9r-DGT_LF??HK4iGfPsBk#U)TU;ZuUO8~yO+}1+Dc<% z698AQ4sq$yCEh>wK1YrmVQ6p=J8$E8o&ZG!J)XzkfQusH-WEhDWns~-;UR=3rId+8 zA}m_8h({mYMrY?*qLJveh-f_)5#Rq$M6%foU0q%5es(u!&U{2JmqSE66hl6|fXkU1 zVXgyFV{x9XEgnT^)>`X^h6Z-*c#H?W^B{F~bp!%|aZ_1oB7*C>BoYZ;eCY*t?RuKw z;bDB=_fZV^E_;CUBI5rSNan&9%+Xq#SuU4`<_ztcrLqvc=-ZXf`qii7KHUmsbE7xgZb@mey8ugd#SN) z+wwe58DnJn^y!8A`g+$GGvOMM&*#~{{~aFr!NUv<4Iv^$6#IRby&{so22x5%n>PFy zsEx&9di}Z$&66iju8GIv;e0-?0aaC1 zYc+G`OgcN)dMj71>ai?Kve~TJxpQYEkw{dH2U08+^`S$DYP-9;qX2DfZMpU9*N=q5 zVLz2hnSJ~A)nB=CC1i}DqoX6WY}waGTU%S@?AcG0@B2|>nD2QUvj8J74={m1fP3y) zO*9&nhK7bBKq8S4t@X`Ivr-a`M!lm)kJhJBsbF1QU7@9=rO@8qo;`8mM9tp4duL>` zS*x+JF~55C>XAq!!kRT}=;=8}p-?FM{-*|%Ks}%>%c5gZ2bN_`IQPL|P&zs~GE0^$ zN%+36u3o(w-n(~i^QWJF8hPcFSDF)vL=a%rs#U{nZEbca6p{)bT3`yGEI?_PB%rj` zOl@wyRxKxLwY9b0z4zWbbne`_SZ{A{^@ksRSeHtr0zExF)c^|?EEwImabvuurpEI; zuhNHBFiRjX77<05QcbI=sbQi8t8B&?X>DySY}vBqN-P$0Y}>Xz`|PtC$8q$ODN_nt zw{HEssj10PN->TP4TuIr2{w#1%v37HortBf1%p9<@#4jq_V)Hs%d&jeb+s`@mMmE^ zGJpR3oMlvHP!DO}g3P$+2IwskI-)0Gi&97pBzd2QRac3t;ce3Qwf zdF{2=ng$04!%8Wl(WoOLoIiiQ`i(cTM! zCr_T7bo%t^Sa)}K^wg`cg+jrIh;kf99Y21&{(}!bs0)Qc-u?IAe`(sZ zX@&m&{;F4BeYGW>P6xu_u)A^N#({O~){P{S$-tX$zS)vUB!Vx${PMIJGiKyJ{`gGc z!i5X?zAr%5^EeB5y3~d~J2W&Ddh4xyb#rBaqs zN@mZVoo{Pv%Nt{)SS+gU?(XpA%a^Nc+g9(sd)WEQ3(sfL>9jD`eg6RTiim$xJ<{0N zsGi-uN3C7Ej!-CcQy8taIF6%4M3vuFY8BUYRVI^B2M+9K`wzECJRXV464#lCP$(4S@Zo>RlTZGP;o)IK#8Zks zZ%ow}%4ct@S*J{y!j2t}@!$gwQCC-oWmyxdypH3LNF;dauP?G|*VDw~@rh~H3Yc+K ze0%#swr|@`XJ;qTXzbQ1K9{Ad>mYmfJj?0Rr|(?FUk5YZToVe@G<7N~R;*yz(q+t; zG2^LhX%0i|6#7FfGJOU-$Yo+wMkE@Kp=3NNzX;ZublJ_`!0Xy zPA9zznDXq~q%ArTzQ&lWoXG5(22T1O2Y^Ao=c pfR9Vt0Q+_TcLZ_+(EnvW@^7I+uHxD8-4Xx*002ovPDHLkV1g?|RiXd@ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-play-normal.svg b/Z/src/nglwidgets/icons/32x32/media-play-normal.svg new file mode 100755 index 000000000..e69de29bb diff --git a/Z/src/nglwidgets/icons/32x32/media-play-slower.png b/Z/src/nglwidgets/icons/32x32/media-play-slower.png new file mode 100755 index 0000000000000000000000000000000000000000..3a2512672d2618af21a47833c6d705cb671a8661 GIT binary patch literal 2298 zcmV500004b3#c}2nYxW zdCv;PY?z|$io7V1;B*| z{D3c~+4>hCOsMJ-0FQ&v1i~CJ^gB*)z(|3S0PrO|?_U6NvxT}ZOaUSWO?wK&tHBUN zM7pMFilQotLPUx}?ECEd%)amWj_bP2%pgcG4ZwB(0bu-oQ2!H#hy*m{Nf5Pw5j2F* zg<)tyhyumrj;X2&&+`BP%naZ6SxV{UW!{l_>4K02a}Qje2%%P2Rbk!Qb!cv0j|B@BAYK#MMLsy?wpt>+eT$bQDrbFKcI| zBOM7~2(GsuKzh0?-2+2J1Os#7slNtL7Yc>UKp>#cYiPi0ufB@so_Q8R2o$q&r=BOX zQv8)tqT_=P@Rxn>Vq|0lwrx9>W#s_efa3iP68|X&nhqukP5nI)#lzunz%)&D+lyPV z0 z35F{w)ZIIGVcXWNP*ru-5as519`+x254-p5fn`}TOjr%s)!YHx3E7#J9+N~Ka-sgLJ*^zFCb8YfPisA+3!YdClATr8W-DvF|TMMVYP zc>Q(gLMVn1I*5M^AOHZ9UoKT$0)`NVq1Df=$1|HZ-*se*=DIE=5(%@jv$M9dv$OuI zufB@paydm+RW9|peED*qqoX6<)zwvh?b@}l<2a-!lj|lT{OsB15Rb@lb5g04;rl*x{Z5a}WHRb!pM4hT>gtLQ4i3h$*{n8Gt05w6Y}tTAhYypk zX_|E84*<|)3J7x)O;v~p3l}b&f+-g2C!c&0>+bHZyL9PNbh;p;qoexJ&`{{qsZ({= zu3Zb~^LeElpd6+cN6}OT4n>PFAuu#WQ3wEPYig!IMn*0zX}!O{zb27LR9wG)Jy5=NGg)12EdZbpSBIu8)LJMQGj(-!wyx{`Y+~06-zG1J}Kx0bqc~eb);xGp<~@g2s9CKt#oryX)7lza5LkobK*!r}Q)xt-89} zS-Em$y0*4f&gL`~<1jOP*Yg3~2EdarObN$zt9{?+p1xjMzi!=K_myxs?5$e0DieuB zyl6D)eER99)yZViEDaV8hrKmx)}&&wn0x&Aap#LKzNk#4QpQX$ef|CLeV-lIb-}n= zgaLr_%={xMrPtfnr@h^}2ZnL?dkn+ySFBiJMIsTms;Wx%_xIP1j*gn8KEYtnf8vQJ zGO<|9t*WY$XV0Fku`EkRnYpfup59(aDZRo4>q`JonHjrx?z|0EX(oo|xUTl-qmN+4 z^5yrm1VvFWXU-hAv9U2{nx;E3F`-seRCtRQFShFI>!qryP!t7~m6h)N`SWdE*S$<8 zqgGZ{I!l%;nW(L;bpYV#v12&ec??<0lAiC`aJ?hU?38xx7Xe-qi$+89=g(LEdFCv_ z;qZ)m{{MFETrS6J)~!V%ktlZUkKnq0XJ($dhY(Q}bhTAzdN>k|243F&685&XPTQx7 z!5qgS*L6wLG}d*U%QIQ(Qvl`P{ozd2cd}oHQKoPt1H9xchQ72IfBLIMTLl z=U{sq4zwMdk|5)0`>6KU!g=d#p7|j@#<^%`IarS)=ft{ zkKx^Y`|$7K;k$K{>irdYT)(ewngW_ZQPxyfqouhS8(KDCK~ocIYHAP;hmjf|$H;v16lEEdfTnB&(MB+W!VsDv41Km*Tjuj_UP`B+wfo@uCm&dA zPm`r6H0|k!m_mFAAoWmFh-siqsOnPOna{+gna|uVna>R3`<&0r05uu;M1&07*qoM6N<$f?32o_y7O^ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-play-slower.svg b/Z/src/nglwidgets/icons/32x32/media-play-slower.svg new file mode 100755 index 000000000..e69de29bb diff --git a/Z/src/nglwidgets/icons/32x32/media-play-slower.svg.png b/Z/src/nglwidgets/icons/32x32/media-play-slower.svg.png new file mode 100755 index 0000000000000000000000000000000000000000..f73310a0ec368aa5f8cd7353d8d24ee6c8f79679 GIT binary patch literal 2414 zcmV-!36b`RP)lyV9;D*^(?F$ySXaW{e9>z>FvL z)X6YqxM(N2Ai2q9{zr!2k_(2($B;}CI_}VTrr>F62TUO}7%&pDW7(34WUcl?yZgSq zC{}F}l1$s@a(6Z7Jde)vaY#yu=Yxpo!i5X0(P-#F5DcoSS^zM@7%KxP5>bkX3?hn1 zDSauWC8hjcO1UAWtN^Hbp0^Q;#dZ>jg!{n<9|-v)K=k}GBBHsuIW-cA3<@C*6VXY| z`AJn(4;zM&j>qE(RaJFGQKF17CWH_{5cE9HbGqH`u4P#b&+{IIVR#F`3K6aOzW;P# zVZnQzzya`!7ca7fg@qXBe1wQjDT*>{7{;%Y$>hlJ@bEw`mx~M!53@ufL9tkj6h%Q0 z1aKTjwpuN@y}d0qH#hz5?d|r?&Q8s7oZG(dUzbuYhhg|+Zf?$g@4ffL9-gu};vBAU~6{q=M@eY{*Qr;i>z8ZDR0ES*l1VHnUf4UtF$j4=oy5Cj3au8U5m!<)^f zQmItb)z#HxwOY+Lo6Vx@y4f%c7ry%Ht5qVhq?DqcIT5i}Uwt*MY1#y1?7U$Zzb}w$z&4IXcU}t5YZ2GBBewahUoQrXti3X)oSw2ojc(--+a@q)oR~% zI-PkT#8uaIzrAteMpsHH6e6OTnHiOHUS^EFZkpz~a=AQt`t)hz#EBEUP$(c4i-B_v zAp~sO1_0=~4$k?0t$;CxAPAtUD#pgfD3M4gi9{l~w6t`5ZEcM@osP>ncV}j19ukqu z=jP@V0J%sc^1FCE{>RbL(W&X_>BQ;Nr+KMV>I3(BJ>0u@4=XDxa9tOvR0`2(^g#C8 z+uK-LT0*5#K_Zbrp-{lUzyJdf?Q}YZWm$R<1Z^p0eQa#3%a0v9W&k)IjYj{F&*#s) z^2#ei)6>(uR4PH&buh-@I1ZMUmhk@j?_+Us5t&Q|oMZ{t;=(v}`+JTJo-d)YM2sdBkIG&MEF3xxtS zO#>03)oNjJaS@j;UBdkQJhIs=T-OC-3;^K!KJMSYkIz2)3?F^;5h|4m&Ye340AP$k z(=;49bO=*ZQ+#`Sd$8SZPx-$8vgdgfMM_zWL?S2C>2&d>mtKmNN+pWLVgP_zt%hsY zuHnNEKg5k2H_&ReaOlvXzS{RH^6|$X;7F~jFoj=|5YxRGe<{9St5~u@B4W0-~m4W{BvBnas_wp+<|S|V2mLW ziGYaEXf&|0vVu#OF5$~Bzr@zo7NnHmoP#lTpd%P#NF)*%9UW!4T+Xc5>*ZdrS5`RZ zWy3Ji`FvhUr_<Riw6X^SNgHB zG0e`+VtjlYsZ^>jxcyoFk_svS>@W;{*L7tO1Ox!8s^a+Z<47ix$mMbeTFv);NGXxY zWN`NEStJq(WV6|RtA%0s!b*f;2-kIG7=}Fn9Yspn>h*eVr_+(1=i%9+0TH28D&dVc z-as~+MJkoT{QNwEAb{(-@O>YqX<}w(27`lx$mMeVA>(--!Z17lETx3!dFXUH()WEw zO8LDarL1?m-A<#?$aK41J~%koS1$l0lS#bx+G{XP6Uk%}^?Dtera_2*ujNQ2g2~BA zB$LTL!AvI82iz;a5CWEEq0wlFZntXz*i^zWtXP)Stk>%!J3Bj(;o;#QtW90lF+Dwv zfq?;3t5xLlc__+%Ay%29{+t!!WEU zLWqjvIF)+6exzEhs)a&hYtflf2r(`Y&MJ8*;%-*i~VgYgh0F9MzvZM z^?JSIIL>1sL`5N@b>H`IH=E644<0-)M@B|8!!XD&j2|eLa}L8WUM$~dr1le&Qo^=v z)M_<(|Ni}6v)NqteSd|B*7?N5MCkiI6GG&|Fw94z(O4>#V)1w!ilY2aLq|#p*L6{= z)v&z09NxWqx6y1i{}u$npHx+S$cx2d7zBY2AmaOe*7yA(MNw4KG->Zz`ELjaA>g_$ zzWeSweEs#;;^xhp?Tw9%JC5UA?e%&~LWrllQmM#7q0l2DM@q?E*G)T)lOUpqrfE#m zv_64fLSpZh>vp@S)oQqP>sGkDylg#r^5mc0ZuhG1`wKx3tY5!=-RDwDy!-CEqF5~2 zoO8?feX?!a+}+(Z9LI?g5pmAx=LkqC`!ir?X9o`-K9oyKOX1C%H`~=}^`2!}^FoL} z`@a8hadFX+QcC674+Rl*&!0bk-*FsiS(g3y@#EJ!ozC&i&CLU+vuT>pG!2TP^iOBs z_wnp>#?H=;tW+vub#=8@sZ^THX7jG&IDZL(U_saQ)oa(Tb@xtZWgl~K@!~~mVPWCh zFbr+mwzoGoH-Fn|wN9+Bua~mfY$Bh}N3z*0OD2<~>w4cb*tRX(?Y7+7+7k78-QU{U z+HJL3Pb|y&M-T*ml~OJPcyi{<8T*SbzUZ5VpR`L-$}s>ZIp@E5W|uPYczoa|>{8pZ ztmZSjv?8TkVT?WcMRsXFfeRNduy(tx*|t6O%qWf$QJIJeFEWY%)`bui08c#6+fWqc gX(p3#USt&i1yf=BYOD%qs{jB107*qoM6N<$f}3od?EnA( literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-playback-pause.png b/Z/src/nglwidgets/icons/32x32/media-playback-pause.png new file mode 100755 index 0000000000000000000000000000000000000000..5c7d128ee8728707a6193eb41af32b4e28890533 GIT binary patch literal 1145 zcmV-<1cv*GP)kdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000B{Nkl^Bw_qq@)F2oWehM>5RxKr%Hm6}!%+eJ5;P+bTi3lS*+iMTL0p`m}$nM`IT^X~QY zaG4NCay|}k4)2`reDBVC=eR(>eVF$r-4qj)1*i$D;c~M0PMbdKBbY0P8D8 zNRZe0(#=lS4j`Bv4AY$T#V)(F>5$@qgbX?I43H&hGVkVQTK`M%-dOl9R8v}PlTfBY zi6Kx_XPp{e(V)oOvODwsMjyfSW8sRgbZCm;7>{s>LF)-A9bt!GSz(YOIg)jEYVNmv z1n0)Wim$Y|!zjl&!d>KX1_-1=S4uXx!c9g*BZ^}mZ1f1;9t>A~RnmD}-Nz`9B_lW? z0AARoLt71gX2l*QS$4-iYC!^!PWx(`EtOXpXIQuMLe5;j%?k_(ck>KSD6@^PrqfZu zTjj9UEjB3e5=Y{bXGp9+X2H-k6+2RKUOr5==^p;LmOwhwEw*SeNk!$kNFa(HGKK-u zRZ!`3w1jRkodNeoK5Xumws?wX8B=*yiC?HsOV_htc8-SPJfF~|t$W)nvB)6?>h9je zpGZp`B~LIKJ2`?1ZgB&mdA7LD28rp&2~X$v@KS(GB*rNxdAP4PAj zxg#Mfs#4O^iJuSw4-k|P?C3C|O?k9NW=@#Snlh&M2Y27mKA zEr?d9!3_>$)>9G;NvH)J4GS>GWR~PWe;o5}V-&T-|4X2-ix-T>&Ur*`wm-HEFKilt zuO(p>asSD#JyU84ISQ2I(R#6!$GlZj6jqaPDd^{#{VCl@kf+FqJX$X{f|z$rRf;Yp zVTpQ%9ad=4p(}V53{#Rv>&23686AG2DFW(Y$pv2iG`yw>$eTRG5QX?gI{s@akKaO# zckR=1pMCXu0%0~Z#l`}6XweZQ5l`4(Y|?dCIiC~I12n@dB=B{O`HcAf;wlaCw*?)k z!5dP8Cbjkdfj`KLfO%Dt1z?WJOtrxGI3}@zeM2oyMbus8-%>#3%c|NNsxNA&2Aj$E z^C}f`g1y`TNQISea-KDt%T7aeVQ;7!g~ocQ=#cPC@ifIam82kQ`jKyNcEl<_wXkoj zo4qiG7K=BbLmcH%?&C0yTk3pGXxP9Lkdg00001b5ch_0Itp) z=>Px#0%A)?L;(MXkIcUS000SaNLh0L00VXa00VXbebs`@00007bV*G`2igk?3I!_6 zNBr3U00cQnL_t(Y$A#73i`-Wk$MM%W-}$vOJ57wi?#QOqqS!@xQ;e&D){^9^Xc|HK zgWz8v6si|eSvGcEEQ+-#c%!%3lC~;sE^^Z!Y7r%_H&ViaM0(-EtfpwPyE8lU-T8ix z7yHdNX+k}>&w1YGoacO==M$3K*YnNtL^x$mPY->4Yw1FK>)G+`d&7qT%e}PdOxaCJ zH)25)#4RgfX`%lSfTdPi@J!jB*fo|bl!!77O?5SK=*6(SIJzU?>`Zzs%@;-nqMlh@ z9Sm$)*H`Lj$%ISc^m7}x0Tv!e7t7h)(8y7rb3jX74TW58$KR}KX={k<;nC%HZvlL7 zCaspUBbyF+#61pb3W9*7P?#9laM6F55oG%ut z8+@miu1wn7x}I`R_43Rc9@eSqlO)N+uH3iKvuRpw7(VktKT<4C+9M+;&1z{>fGf`V zyC{k>nM_?%6Pz|OGHDl!#HX9ZncS9R?lYw>Q^K>(o z$BS;RZqA|Vq`m5o>=^p9v;KOM9y4&aFR9BF-ST)W9xIF;aZpoDl!*eyb_@;u%TN8> z<~{Khu^vE!%9B{w^wW>F76f{)oh^e0h+Z86=vL&jkixvEsA9$!LVsdQ{(XW;L z^x5E=iBef%pr)>cq^04oXRBoByW3SkQubq7BlDhJg;KGPXlUu^>gxEam#Xx=*p$MW z3~4Q<*OSZ@V};30fGHi*y6*Ke&pWu^6>wPLvP_a*kLhh&nH{T!aubtk7PfUv`gI`KAX_%JCzV92`zi!8egZI@PkyTpwf=2bRNvTwt$mNdXkJ@Vd z`1}QGduHHdHb3PJ!AYe;am!GR|QQqVLd#0{@vS*<%t=u zrTJ2Bq~m^{_X!^t{MS{NUAC>IAqtnAetF}L*7igzEqEri3x(Z%MFdezeXk}%FNWop zM;~FXkN47|GpYMQbA_t4!j_e=^h*E#xHCN7OedTQbE&fT&`)bFgtuO~gT4O`d3xUG Te#5CK00000NkvXXu0mjfBQj3; literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-playback-start.png b/Z/src/nglwidgets/icons/32x32/media-playback-start.png new file mode 100755 index 0000000000000000000000000000000000000000..71906857cf42f082c70e96737cd9f80ec35bd43f GIT binary patch literal 1177 zcmV;K1ZMk*P)kdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000CSNkl%Nv2I}kqk^*6{QX0LZL=0)zW5F zG%W~zP+W)@OF>cx&K0dd`VED0c(U%)kWw4u_Y$9)GLP|r__>~#*6vz_Yb_d6P zTV?QWUzqXbIty%JAKU3Ahch6MiYCj%fIgz!k-)(o%EjIHUPbxCO52VAb z4Bjq<8_mKJMP6lltMZsjJSzdVg3+`rYAkSCyN68GJ$$kfK|0bb)TuK_S@LYl;06=? zL1e_n2Ft5U(if?VW+5Gc_)gA$x{_Pq85OWu@{9swiGE~>U-*lM$O5hnKpyyAac<|= zry{>UEjIMg&lY0C8Fgw@`GI5n-04TlBP*WLPc>T6?~l?$DGA%`AD6L^2nQs{K>W=q zK4PJ5kr7!6JV-)HdMNV!GT;FM%i1Qk)vz3vjc<92pD+s%lhNK~2EIS?B{c~fQAMN# z3o-+t93-!ac|PD{7BK_MbE{M`C}n)flhR}9cg}}DNvK=%cw%eeYuw}rkK-(I3z8#) zfM_KL9fMok%H~?+Aw}=MU z6dl82xDrhyVKO4eH_XuxRtiA|C6059-c|C{Zsb3FAw@)(oJb-FqoEoDQ!G$NCYIvU zoMaEH#X4Km`GkN9sD@F9;PVROu^ex4l_hEZ!kQZZFC=H4)7-GR>@-xT zIz!bgG}c48X}v$hUWLW2t8Mj*?>L9EOE3Assnug0;N?E_uy{+fn_WE0{oIG+U*@?k zmaHdbInCiSYabS~u%|5)>`&J22q%#ZI^pbTJ5yihaec`i*HG+SE@xZV<9c?T$F*aU r3kMi-{h{@|yGoelg1dY+Va@sv%NF!G!=KTL00000NkvXXu0mjfS=|gw literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-playback-stop.png b/Z/src/nglwidgets/icons/32x32/media-playback-stop.png new file mode 100755 index 0000000000000000000000000000000000000000..650874f67f0ccb1b39591de96691b61f3c3bf98d GIT binary patch literal 1165 zcmV;81akX{P)kdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000CGNklrkmC6Jy9WesR^^K8P&yuG_6BOq91w;O z0FIbYMal#}U|XkRx6FwT6Tku#*>#;1HyPf+y_n^2g($1BtyaSfaR;8k6ZA~sI(gSC zc%vyhSu{W$FX5Pt^Vi%%4psu)qlr?gpwL-XKAv1R_HEJ~1I0WF4?Jpm~W5GYEj ztH#jhkPumvF9GJYitJ75H}MpnMT6lX9Y15XR54~N2ULy4d;0$f``E+=_o>u3cZcqz ztB)Df#=OsD0F^qVjg&%)$pL|--KDEznj~;+%&Pn%Kky?%Ctk&nW;j|!4e%6}nAfZ3nxTO315g7c|Bk-L zfaG<;pbU5l8X*cRv9L2JXw=|y1iD;xnjS1dKkxTfK@nT`F9Ew5D9F>4bh~(rnSG8{ z9IwEKi+b)Ufs3v5z@c9-(K+Snz+2!?KjqVA*sc&7?)`d7C_O6|h0Pt^l*|)UbjczO zpHqs6{c1tr{jM{Ly^B^h(GM`fHiqD-BOIzeI|&rCUIitq#~4@XO$B|~3_nj_UbE*a z_zsUE(wSO(Of&e;r{TG7?{D~uDlKGfEwz9w%aCkX=Os-r_7})Orh+paP4EeXiDW3t zT2Q`-u^N!^S6smWBcueERN)jwd!i#FYW(a`Q(s>b2 zBl1;=3cRN8@g?$5rZwm&>RT`nX;=;&DABsmLiTnzs1o-Ne$v fC9`oMo%a0)Lk#jiOZi|800000NkvXXu0mjfdhQk9 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-record.png b/Z/src/nglwidgets/icons/32x32/media-record.png new file mode 100755 index 0000000000000000000000000000000000000000..f926a8f27f85ef68165ae570e0237c53aabe19a9 GIT binary patch literal 1843 zcmV-32h8}1P)lUEc!{aPp#3JQ)<`D13Lv)N_>h<(9s;-2Q_ zc+qG;l5J#}ye#g?=tMywWZBd$S+)lRkr9X?WFwinEWq?ZW{{XD22Dsb+oUx%LH?B% zXuI>f>G^W0aS(5Ma_@J0@A>`Cx#!+{t|b ztgp{7jQ%4>j)YgEcSQnCO-(KyQ^(CpCg8+)t|@UI6C(zedWO3?x!rK|=uzKG5ol~| zOyU2&;^tunbSy0`(c7p-5vo}5l6rKP12%G}%>&CJZu#KZ*od_Lu!^z?K^ z#%i@<-c6Q@IXM~L_?Jn%f8xZ6yDubg^5jWaJ`8Xunx39kfL^bc3JVKq&6+i2 zx7%TnDJakZ5)dp6Nc;VMx_b30O-)TvMn(q62#He0@jpkPuC5Mi{wITb01lUL-MW>w zZQDkmIJziJpXmxX+9$!M0EhiU_|`RojWN% zKOf)-Af14aNEGyoU_2~^!0pQY6%`dqH!y$&Oki8N)6T3rxYG`%rKP3H{cG2*1-Q7> z1cu#Hm#FT_xGQ%ac4P; z6F~!zEnBuwR#uj7k*O>?`HXyDe?viDPYb)(2rp2K=Y=PHH23=-^sJ|s3V-;Xl5$@K zfOrEQR!idXcvMg_7XEj#lp75G5f4Bo0#3G?oMg)^_n-ZaLcGUqOeP6pSSZwa_`wPS*uUZd z5K$uiL^Ho#NhDx;bKSaiz!Cy38-uvyhC{T9>&1F0f%Xov!815aQaOm2Xp)T;$D*{v z@et+cw#u$Y z6{9g8#DX?ND~bAaOoKsv0xWAUu175;t)v(#2wgnd#0#?$)cEF~`aiX}NXOUp;gr=+ zPak5yCjo~)<(`M=WHLYefFf8b7FfK*vcRZe7S#AgKmK>}SREW9Is<_Ku%u5B7{fpW z$fHM(^Z-F^DtM*l6LP%cr6q1JGN;8ja5$of;9K?Ey*nuT(~ouVW%};lzpt=RfNgO7 zD+_`T1Z0cA6FLDbAief;JEeHN3>G!P!y1X?9c5I|(XPho1ay559y~Df2w+=_i;Mr^ zL0=G)M-1S=z&(KNn7AXX8BWTst|EgoBDD;B{KnEa^I@yAzC28M=e|{AP{i#3#-)UN z;M%ooG&(wp`$6)?T6G)N)YSaQ_2+U~)YjJ0#*G_sD`K#mj3$v4iVhBsLMKu+q3ym-<7!nFM0!GkI-XUT^$SOLYmckiaMvNEwmPtWwV zhp6T2?d`>X2sjW%Tczb49UXU9e3(>LR_1ag4-Bt=iG-&4fjeP hxBD+$y0oh2`F|miFh-s2`rH5j002ovPDHLkV1mqrSN#A0 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-seek-backward.png b/Z/src/nglwidgets/icons/32x32/media-seek-backward.png new file mode 100755 index 0000000000000000000000000000000000000000..644d3e2d091e2b58a91a4c834f1978ca31dac542 GIT binary patch literal 1207 zcmV;o1W5adP)kdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000CwNklWn4C*nXxott=h z@1sH|Xtlr`CuB5*C4OU?cFGj-SKRjT zi?;~8+Y_flU!5Ctvy~03rGzs;Bok6OnPrk|tdWc)wtO(lioo0L@mv^?bv7$|4;>Up z1Sdow2+K5SD8Wxm+gALP+xk%*JU})Q1{(Y;`T*uMSb4r7oo9Y!s4frEqY$bc4s(EQ3Xn+w%Mu_*yv!0nE)Q9>f7C4g9V+ zxAD{`K5WY>O)dKA&NDf~c_z6@jg|2gC-CN@C_JiP9kfc==Cd6c4c6O-D_DrPy`QFL zz{Ugzxo$_gAQUNczgYUbJACMu0QV7trBQhfJD?i&^SdvHroaHzRqQ?~h^LZDk;$5!h;cubIJrcUgbxB;67&a_Uhz1|45vMSd(R_-hwHEA+ zd#!e$XFJ|D^0;|SqUwVQ%##v?NEBt4z3EQ6%=R$*L|;cGr$>vNGl5X`aRw6pWZCwV zS-^9=Lc8b{5dmK0b-G!L(et<&u^`U)cruc3**;2|3&0*;Gl5QQ$io|}0v2~kEUiu! z;#n4w$|BPY**!>chJBi!QDSB6rEKO?p~(emO29%q>kl>JVXwe%nWZV%R?NlAysDtp z@eHzVH}Wc9is6Ze4>df*u~{%>8dfJ)P$Z zoLzd+w;#FK(paAFL5(Gt(M~q;5O;H@DA$$wlCWq6Pm)vYJlfh=Ou|}QEZZw1CFIx4 zV}(v|*4mENZ_`|NS#yn*Xk-(xDOhtocAMt9DpHDr47>iAw|7^KGfcQM#~QSZ{{Zo( V^WP{4oRkdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000C-NklxciUL8 zXrPv^rKf(j0gwW)_DEbRD~*Y%L-zZKfvyg+Mq|gjt{WKYscxqu>+b<6z)$wZ^|CUx zX^+S3vrAu+B!nz$ZQF3k2Ocm`-A;#oz5yxl!$Djvt5e$!I%KZ}9kp7L1d3v=F|+Ay z*DV^TuBFF*Ii-TUR#s>3IcU{GmJIau_4M@&^bPbaShQ%jM}5{kGi5ceK?*+@#jSR@ zW!YEkGtkvht0W0;dQ=FZHP_g&>3N%$bSCN3zZzHM)9r9->aZ09JzX8OTBTBX%T={n zt*ftZ!IGy(n)-u&d12n)^mzyE*3;4Tu8&I+c*Eb#?Uy7;0t5U*SK9yQUsvVv zyxizIV2@g@mb~L{0CsG<;15VDwXU9?&*^I9lu_1tKv$9l zlBsPI7bRabGqt7F_kymcCACWJV_I1nb;_v7mUL7q3B2vD@Ss<8H8$Nb_kfNIdY+V2 zDtlx_8FfMkBnb(8=s)h-XX>7RdEfhbdRhe}BuNONig8G`gg}5w$Aa3|9FtVKYDse3 zmkThzELqg^Eyoc;QQVP)GOpq#wSSw-iY$ahyZp$v zLC=C^OTOpp2q7!7n`*?(Dqan>TV}FW7Q(XcI0;y=XxS+zK?qqZyP+21)hb?hzqaGL ziAJkcobXiuLrcEvBnU;T)p*N9&HZ@2dT|!#Dt(u2Xf)=sBLcwCH+=(yBAaXc&nx;W zaqh)gMVyIAjq^55H5#p~2=Hac5sIwUXiWV^sKq4CQ1Q~(*;?O!UA1M$%*kike3;rrOtjMyCS}jRJ$g);r>asstP;<>XqyW$Ejq9<} znD~U}tmx_Ks8paRT8%rNcgs*ux}6T4-+&Z=XCH}6vC^6;j{1V3TCI|VBFoWeSFM&N&ZhMXQvgx`0FIC1v=gx$0)d1iN%x&gXI>ry04V?faJ(N+IGPT`$Oz*! ij+kdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000C!Nkl1v7XOj6zCec48xRV% z6+x@wzAgky7ox;eLr_FZR^m^(60B_%v0Y@LwzNfr7&oPsAf&ozWhz12WRl7J+ z50?-f>GyCZ=gfTX``vSL`HnL>VEQa2`x^D1l-p=@8JvtAn`Tzy8WP}q2 zc+sXsQw4rtE^H;5b=%%;Km?GC`Qau@k`Hq`z2wP>?l3eDqdc#T80C$Ch;G86un@gau-*@g+~O%(O-?*}A*uP&I;NJT5k9FiJ)8?$kgQ>tq5K zc%PpsNcuDl5f_tja4+XFZ_Omf+e5&1hS%1J9tDNQ({dCpbty#a_ zms+Yi$fi)IspJ*?-55V{m_^!nx#WGY;e$b>af?(5t}FwuNiTYQ;rNALS>j%u_l#t1QP=uU zmPyEm3>PvtY3=dltRVm=&@ftDmSK}WRDDV4GoacMk>)8g5Lwl5tfV#;(n=Z+@g_s- z$q_pLP@gpKI>DkE`F{+wjPb(48TXL`+3e#0o5MGGdPQC)CcIb-2EH2EJY@KdcGy#* zl!By12rN22ar=9Wqhqg~0kXN`{35E2Hbo@8I z=dcP*YgBoIF6Ft8j=U6sO;}xS9A%jXEfI%(+6J-V8Q~C*(o)VR7#XZ?6A;1YRi-lX zyUdyJ&NqdQG~f~GysfHx_4{{RA}0f;q$CT#B%_((0^i~oO$8g8+Im-1b;-Y?faJ4G zZfL4|)l@C?)qMDTc`j4002ovPDHLkV1mmrHkdg00002b3#c}2nbc| zMg#x=010qNS#tmY19kua19ky@)q>0b000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S* zE^l&Yo9;Xs000CyNklF*k_h zeSj(z(62g|sNwaiB$%6W2R@iz2N=1}PWyp2O#z0un;uHxOh{=^S_R4Y-U2=QJ zFRTH)*JsmyAZC$Xc5*A5DB^;^NTozh<~hw(x`h#9=%e`+z&j;7=Z9sT2N7?L0=GET3SBm^*l!GXGs~(O^k?pX&1lXE{R; zg}S>r^1IS%Tl7JC!#OQtrTot4Tv!9}Tw`7;&>=mnzira0-xa0%Qx$CuFD_4{?KmK= z@Fic-SOK(kZbQmT9hBvtekN_v4@U)eyRY8__oq(w2eE?i1!Al~lxCEF!JJ`ZOb^wHD->opoOP2${*CLxm+<#;+#Vd6C zsZfNWsmN%m;!%jwa zmU@mQrfJe9QA&j_p5*wNasjkkRU}fIUug8=(?b|JtZ8E)z;`t!aw1;j z91WhLKnp$6Adi%NSErVibz_K!+4AHvnEzIhQ%iT4A*DFaJ8yokO5FgVYnXKV7RVAing15ZqTyv?rJv6DR<^ri*@T? XW>@+Kxuv$c00000NkvXXu0mjfp&%!d literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-vcr-nopause.png b/Z/src/nglwidgets/icons/32x32/media-vcr-nopause.png new file mode 100755 index 0000000000000000000000000000000000000000..db19b548dae04b7bcf67450551afa0d9f50e2df0 GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^+Ca>~!3HD~QrRMa6icy_X9x!n)NrJ90QsB+9+AaB z_18g|(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWIYXPZ!4! zi{8DL4EdT3c-$VQKXOTZcg4GK*}ItL*M{Pbmr4|7p8C7hf!XcM z`bibVdTU>t4iM||4>Ep!laYCnNL$O*5=r>a)})crbtZLY}5Is0W!ghXGw qcm1AQ=C!);z?N@Z9|UI4mk%|RGJ1LI&@`YM7(8A5T-G@yGywnwJy_EK literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-vcr-normal.png b/Z/src/nglwidgets/icons/32x32/media-vcr-normal.png new file mode 100755 index 0000000000000000000000000000000000000000..4609d13cb78a4382989938c3aec1377b77ed9121 GIT binary patch literal 503 zcmV=f2Zwygv2-`#0-%IvoIM+^a%*t4QqB9|KNr&eC=^D9|_dJOW#! tG@@-k0bgvFTi4Y5Ox*Q7uL{3w{01=3sgFP=)an2L002ovPDHLkV1kCv+L!Ur1u?m6#r za>1SKv-bY3y?<-3wQppmJ}e?OVI!8YoS9c9`44)6242G3h&pxwpW}39ULTz^(+9ZP z=q9$}U3?G`kJaG*7w{cp#sa%=81qedpWqEGK^?^XHzMjWxn^;~ zW-j*z9uvqWyoX2Cgu``wgwuT<^(xEE%N26584va#rUH*<=mh%{CzN9zg6F3KN5n?V zM#Q9KYTDTb7`9+;UEqiqU@zXpLv8+966minpRRTW*Q|XO2e4a*t5_v@V9ck*){dkzTdqxJu0+IHrJcQ^-09iA!DCxnJ-(ln z2l+82ae956t=Utn?!PO#e~O>_gts>H%=`x@aRlG@1@6@9s_tj7h<|a9b#|;#Tlc#< tBDO2>O69sX?q6V6`wt?#+pt@U8)pCj002ovPDHLkV1im7hBg2I literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/media-vcr-withpause.png b/Z/src/nglwidgets/icons/32x32/media-vcr-withpause.png new file mode 100755 index 0000000000000000000000000000000000000000..8c9be9728d31e54b0b50aaf232113b2c87258882 GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^hCs~2!3HExSA^yRDaPU;cPEB*=VV?2Ic!PZ?k)`f zL2$v|<&%LToCO|{#S9GG!XV7ZFl&wkP>{XE)7O>#7B?54vKGgL>xw`j+02lL66gHf z+|;}hAeVu`xhOTUBsE2$JhLQ2!QIn0AVn{g9VmX=)5S5wn1F`xzL4x%OZ~3xCkDc*0u1Z*SXOTzy%472Hcm=Nh;H@?K b|7+E}-zSZiKI91B2lBtCtDnm{r-UW|96Ou- literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/service_message.png b/Z/src/nglwidgets/icons/32x32/service_message.png new file mode 100755 index 0000000000000000000000000000000000000000..3ab475b0f256db5944f7017aec19a1da65e9b4ba GIT binary patch literal 3209 zcmV;440iL0P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipV< z2?#sI#9;CO01OF9L_t(o!>w3pc$C%IzMu0hvt%ZFLWV2^NFZc0Kmb9?2eK%!rqGB* z)>;Ir)bDbo<&z7E3stbv%Y{@HDebD#UXm^g7F{#{I(GzkFkZP$(+JJ#~e?=L;OciHeC1OdS0$&(XJCX*>GEv@DB>C>ru_wKz= zR8%xqRn_-xHe2U`0|!u2QZj7Mo;^n=PoA9N_xqczR%=>KO-=ukCr|z*B_(A=US8f) z`}XbQZ{GZ&=|k^V{LRaR?8;OHgE>5;WP(@ix9N>P9-s4FfeHXGMCLxzm*?(UwdC`#6W0|x*Ajg5`J0D#)s+APB`lw-$^Jr*AyKc1Ok7{+ZqAZO3` zaqk6XgV#M+>S)${=YFT5J5v#01_2}hA{IhICHL(Agi!?m5)%_g`h32!_V)IXKA%r@ zxmrb3GQQgteF}|gx zWy{8m8&Ur3ubp|h16%BINxeOtjfJXU=(-@2RfA#{&~!mQA3%l=#d)bSMigbLgL6}B zk5xA~|6fKUj70nW{<@BijzgNJ#RP-FvYMKjuZXAs0II60NL5u^V`Jn0hC-oJ&CSj8 zIyyQ|c|4xW$B!SMp{nW&05Es%TmZoI`!s8mUSDX|C2koOjj~xuSoCNTmMwSSsi#wL z_q_>FbY`<`9-w+_R+~Z%pZ|PX!OsEUfoWr|50r?ImzQ@iKRC;mYinztNJ~pQIe-5AlGUqMm&eA&o^!k1<9cqm zaz$yz-~p|_R~7%jg%782*}c)o%~4>t0ij?B(lBsqv4$s?I7n(L1ejInbXYPi6acVm*RJc% zdfjVf1B$ZFzt=y*oo6utH5Y(h$qb8$z~FH0GJ!!5LgJH8LU?~$3rsoz%p8J+^rYem zFRk0N@8O@`g;(GD;OeTsS@G(s(uWHM>aRFbb6C}MYHDgid~_#l76U$S3yfeV;_U5+ zin4-PqUw_Xc5iQmt`nGAlL|$wzdb7qO3Yg zR>9B!p`o#{9;vo%NY*zX$+8Er_RC-pNCGySz{HXmNEQGQBHV(6AeXcKs`{bI_kK{B z>1Z3@-eo`4)DpF@bk6caz!+Zj+z;{O(%t_S?E9PVn~<7#=IyLLZilJ@(qIq)U;%)j zs1lG2$vq(GN)1;X31Q#>6JC720r4>kq?GWwLhvJY+nSxVKe=k@1yNISyo4jMJtsBU zQ+ecr$9JyZIepoaOShi-PPEFlrGxsq9VEg6Bm^LYgf#pd2oPOrl3)=BlQ{u~6liQ{ zgr<0r)mO)av1WL@Aq*KFgF(4E+S^0e|ED$%vbp*i9bNzWJo})`uXg42Ya1&R1H@pb zN5$VxB)t3AV|^E`e)X+R066mbLEKt={axdg7fNRJPxFowLTW5@f49H?sQkjx+}Z{Y zh7BLhot@qE;fEh#+_?WjQPB_>h5=%rbaEWltVo8?xHljFD2EqKjp0Ql!I$eO>!U)3+zlcCmDyVBRd5@m3z7idG|4U_a9%u!CC38y$ zgSl|xl<7OVyI!9=dRW&hx+ZbCQ$d?&Bn(`tPjK>{l(+6?7APH0Xnxuao>RVOfl02}D&lJEwi5b%be zs1iv@I^yFL{Ik}ECzd+V%Vr?n6!g6OhnlDZd$wb2$+UlU_>AovCKab7c^3zQl#-U* zd25;@sJY#MP#7jHEG3Mv&PB`x3jtzgbae}GK;<*lX2f=85wXPX%Lz_<@>%=*Ddzzw z;2vq}`6L0MNI2aBzxlWn^<61|^AfDp?_%BVI-Q7u*W_sVuV!G{yuF|Qp!D#) zIdn8-QA3mB*UfrRQ`C?IN#?NY0VwQ$2#_4!qND8+aY+G6>g^*2Q18=mR!O!G55(f* z?P+LiP$8uPDG7!ogbcvrVf^D$3x2mT6OBe5%(00uXAI`9L31#3+MW45;2!(geb;wS zpZp#ebw5xz?(M|vxP!eidS9@P9d3+tB)Lb%#RdlG3g=rbe%)#g^U4u=iGb5zTESZAP=%xF6m8^7FTG>xYLk@;Z^8A#i$sFKkxsLRzQ=WtOvm zAbh=h_XL9g=wMW|_k}mL5Rw!)YW87PYBzjF#O*P&Du_( ztLC%n1TFo1;PfE;?T@`t<4b2PHi^@Gbx z(Vya>UvH=ZF!#=-YkE8E))Q*;>BQuC6V5lgVX%ZW448BkX$etbt|B?xrbI(V_$5dv z#9(4{d3^{bT|)XWCvHhq5DWsFDr};zu@~Ji&}A?D_DVZh3k=jc+Y+bQ&H+M2pJX+> zj6`tzLI@fRO$q00NJ=80L5a*r49o&tsVWx)gv|CfD93&3_?=`MwbTaH|3AQTO+}@3rhpADTV2w_S;qVCD#$-yV!_iq#dc vU=SoiQT31GSH{DC;$Hdam7`fghqVJ00000NkvXXu0mjf26h&j literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/showhide.png b/Z/src/nglwidgets/icons/32x32/showhide.png new file mode 100755 index 0000000000000000000000000000000000000000..9a92e2c1b1e469aa16fbe42b79307f2f98457ddd GIT binary patch literal 3079 zcmV+i4EXbjP)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000U( zX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHz3$DNjUR8-d%htIutdZEoQ0#b(FyTAa_ zdy`&8VVD_UC<6{NG_fI~0ue<-nj%P0#DLLIBvwSR5EN9f2P6n6F&ITuEN@2Ei>|D^ z_ww@lRz|vC zuzLs)$;-`!o*{AqUjza0dRV*yaMRE;fKCVhpQKsoe1Yhg01=zBIT!&C1$=TK@rP|Ibo3vKKm@PqnO#LJhq6%Ij6Hz*<$V$@wQAMN5qJ)hzm2h zoGcOF60t^#FqJFfH{#e-4l@G)6iI9sa9D{VHW4w29}?su;^hF~NC{tY+*d5%WDCTX za!E_i;d2ub1#}&jF5T4HnnCyEWTkKf0>c0%E1Ah>(_PY1)0w;+02c53Su*0<(nUqK zG_|(0G&D0Z{i;y^b@OjZ+}lNZ8Th$p5Uu}MTtq^NHl*T1?CO*}7&0ztZsv2j*bmJyf3G7=Z`5B*PvzoDiKdLpOAxi2$L0#SX*@cY z_n(^h55xYX#km%V()bZjV~l{*bt*u9?FT3d5g^g~#a;iSZ@&02Abxq_DwB(I|L-^b zXThc7C4-yrInE_0gw7K3GZ**7&k~>k0Z0NWkO#^@9q0fwx1%qj zZ=)yBuQ3=54Wo^*!gyjLF-e%Um=erBOdIALW)L%unZshS@>qSW9o8Sq#0s#5*edK% z>{;v(b^`kbN5rY%%y90wC>#%$kE_5P!JWYk;U;klcqzOl-UjcFXXA75rT9jCH~u<) z0>40zCTJ7v2qAyk54cquI@7b&LHdZ`+zlTss6bJ7%PQ)z$cROu4wBhpu-r)01) zS~6}jY?%U?gEALn#wiFzo#H}aQ8rT=DHkadR18&{>P1bW7E`~Y4p3)hWn`DhhRJ5j z*2tcg9i<^OEt(fCg;q*CP8+7ZTcWhYX$fb^_9d-LhL+6BEtPYWVlfKTBusSTASKKb%HuWJzl+By+?gkLq)?+BTu761 zjmyXF)a;mc^>(B7bo*HQ1NNg1st!zt28YLv>W*y3CdWx9U8f|cqfXDAO`Q48?auQq zHZJR2&bcD49Ip>EY~kKEPV6Wm+eXFV)D)_R=tM0@&p?(!V*Qu1PXHG9o^ zTY0bZ?)4%01p8F`JoeS|<@=<@RE7GY07EYX@lwd>4oW|Yi!o+Su@M`;WuSK z8LKk71XR(_RKHM1xJ5XYX`fk>`6eqY>qNG6HZQwBM=xi4&Sb88?zd}EYguc1@>KIS z<&CX#T35dwS|7K*XM_5Nf(;WJJvJWRMA($P>8E^?{IdL4o5MGE7bq2MEEwP7v8AO@ zqL5!WvekBL-8R%V?zVyL=G&{be=K4bT`e{#t|)$A!YaA?jp;X)-+bB;zhj`(vULAW z%ue3U;av{94wp%n<(7@__S@Z2PA@Mif3+uO&y|X06?J#oSi8M;ejj_^(0<4Lt#wLu#dYrva1Y$6_o(k^&}yhSh&h;f@JVA>W8b%o zZ=0JGnu?n~9O4}sJsfnnx7n(>`H13?(iXTy*fM=I`sj`CT)*pTHEgYKqqP+u1IL8N zo_-(u{qS+0<2@%BCt82d{Gqm;(q7a7b>wu+b|!X?c13m#p7cK1({0<`{-e>4hfb-U zsyQuty7Ua;Ou?B?XLHZaol8GAb3Wnxcu!2v{R_`T4=x`(GvqLI{-*2AOSimk zUAw*F_TX^n@STz9kDQ z$NC=!KfXWC8h`dn#xL(D3Z9UkR7|Q&Hcy#Notk!^zVUSB(}`#4&lYA1f0h2V_PNgU zAAWQEt$#LRcH#y9#i!p(Udq2b^lI6wp1FXzN3T;~FU%Lck$-deE#qz9yYP3D3t8{6 z?<+s(e(3(_^YOu_)K8!O1p}D#{JO;G(*OVf32;bRa{vGf5dZ)S5dnW>Uy%R+02y>e zSaefwW^{L9a%BKeVQFr3E>1;MAa*k@H7+G5`Po6%`dJDJcK|02CAyDJdxw6ci~bDJdx_GBPqUGBPkQ zFexc1DJdx{D=RH6EiW%GFfcIE($ZM3qc{Kn02g#pPE!C64-XL$5iBe$JUl!=O-*la zsi>UdcM|Hu66k{>o)-sZ zSdb9?Q})Bqm%k)&<3G$}5R&9+4KP@fXbCV_l4uSJ9?VJ9jng!CxPT;alQ(Vq&M`oe zVsn3HV`fj1q4>pMOFC`vJa8eaoqJ^%AW5;gKaGFUdy@2ZZ}B*ALD{OZ3Iim`sxN@e VH|V3VzC{24002ovPDHLkV1i;MoP+=X literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/32x32/wireless.png b/Z/src/nglwidgets/icons/32x32/wireless.png new file mode 100755 index 0000000000000000000000000000000000000000..6919108791f74fff0311b78d6432ef921b8464d8 GIT binary patch literal 3651 zcmV-J4!rS+P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000AONkl~4A4^6Fn%NpD8Qttf5p_{PSd9Og4=LSj45@-KaFkJicRdqLu!{5<5eIAMOos_nT`|&*P z9tYUn*n)5I1$N;e{)tj3p&Ju}nPy`V=3;Q1_5L{?!S-q&F2atCGqNA+a3dx+*oT&2 zIDlt~eGp449o>P$8Gif~?nhq%EH@dqVsnN(M)BC#4_A~eb<)_2hpW|KL3VqTWg3td zCg8#pN%0zX~2o533K`a)`y zCqJ>;7oQEP>Q8Vq1y6=3%e!Hnz^k|@A@-zbYVRc_KW4oN&xc}VitfDovAhQDcGtrS z!x@+=@9}yTm76A~r$=XAo&n@&bmdP&KKv17QHoWa5nXsF_E%2^pPO-C$dbD3o(wa! z4{JlU_GUbT%)z4>rTN-M8cH{wNpO4!PvG1J{P*C2pw%QLIyH~ZSPA08XjXaIc~SF~ z$@ko#E5NdM{W@d=-P^j3EyptcZn^QLYz1R>^;Y2XkDE^L3{XQPV z#Wnm~kF%S7v#~PH16e8Z_gK+st-h8Sz();m{SI8$s^t3{IChqgQ@FMjH*-hvW)2gv z2|qN#^Yz-l_&C_&hKkRQ$Bo<8D3c@6=b!oxfDV8TfR@^S0{}8t0Hzu> V1a$xa002ovPDHLkV1hF?G&jg?)c61Z literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/LICENSE b/Z/src/nglwidgets/icons/LICENSE new file mode 100755 index 000000000..82f24a630 --- /dev/null +++ b/Z/src/nglwidgets/icons/LICENSE @@ -0,0 +1,24 @@ +Icon theme + +Oxygen icon theme is dual licensed. You may copy it under the Creative Common +Attribution-ShareAlike 3.0 License or the GNU Library General Public License. + +Creative Common Attribution-ShareAlike 3.0 License (short form): + +You are free: + + * to Share — to copy, distribute and transmit the work + * to Remix — to adapt the work + +Under the following conditions: + + * Attribution. You must attribute the work in the manner specified by the + author or licensor (but not in any way that suggests that they endorse + you or your use of the work). + + * Share Alike. If you alter, transform, or build upon this work, you may + distribute the resulting work only under the same, similar or a + compatible license. + +See also http://creativecommons.org/licenses/by-sa/3.0/ and +http://creativecommons.org/licenses/by-sa/3.0/legalcode diff --git a/Z/src/nglwidgets/icons/png/add.png b/Z/src/nglwidgets/icons/png/add.png new file mode 100755 index 0000000000000000000000000000000000000000..983618794020da0693dce6e2ae258f8f16b76de8 GIT binary patch literal 1312 zcmbVMZD<>19KSBx66)$)5ozm7kK2%eYwjg4mphtdX)f2MHeK694ESNY+&yV-ZSKyy zt4TX&w+V`)w1T>!g>@i`WjLu5E$V2-aC9m-5%$5s5-QArvUbCjIMn!D+tht1`{2Rd z^ZcLZ|NH&l?~R`B_PW}pS_DDrq8(fxTpO&{u@!zxIe!^0jbtaPU>l7>HzgPi58LY5~!DSk}fw*(|b^gAPJnHaFS{vY1T!t1c9zS7__EK zX||8!*K9$_k7Z0#V{tr}%QghkB*QQk2Sv3&jTU2AF@=1KV(hFkaKI3CSux|J>M6+ei#+0Ph2a zI;4xR9_gJ`FwEV94OxoN8+M;A!=ea-oGK1wfnr8EKL&4{k}R=2L-Qm_y9t^iygrg- zs5Tf%GOC7#;~q37h_YhIR(V#V<$x}~1SDQpv*=2G zS$PBdM94?nA2$qv4Z63G(U3E}gTVnYg#Q4%)pr|z znEGw@=EYPxb#M=MEEsJb9oZKC{@S(2KRNYFdh!Q}ve%yJl@2hprUHpDfKHDe}N{xpu1a43ln%+?shiKDN12 zAkhyTogW_GJI(~Yx#1d{X)HZku%qokspiXncGa9LFMONXdw#P0JM3O^X=*u8-uL;I zF7D4#rSkFVtM>Zqq0j0vO(gNik@uci$fQnpN!=Z|!?w8rdF$`_8oT!JdF!7QjdXKo I+YTK27i|#ASpWb4 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/add_disabled.png b/Z/src/nglwidgets/icons/png/add_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..f83b1c272d674179fc810d7f6529964d44d8cb9b GIT binary patch literal 1173 zcmbVMUufKP9M4rLvvato>AIJY(g$^y{C>H+q{%MU+~v|8n)bLJdMi_xCcpOLHTk8< zuU@VU99A4d@MS*uQV>KzVVi@Y58@^WGJWu+P(;c$Una=Lgo%H)G5n>ys|sZg29n?J z_x*i8pYQ*is!dMp85$m97-moPuu-S$6Y0BakbbXqv_I*xpH!M;8qblA9U(?{@hoDi zzCDlX$acGn-=ZSJJk;_UP13ZUR~_v0cB;cCen`;_Qyfo1+i4@h&Z2oQ(70P)T;f>I z)wmZ67O=uHYI%p3BQ(7{*>INIj^c9T&#=Wrr35}AHkc2kA4 zHEzqPrd4ChI6`cJ2U!P5fR!K*b9q^o53(YFKmeiu#VnN7oTvi8_8yK}i`+T2ZkRn= z^rUeuLPAv#I-L&R$?-Uv7oegjDTgR#sYW*L2E1Ht#xxHh$8Qb+%|v7>g}=!QtBqZltm4z0)BNFPjd z_h3V*BK1a{iac5rd%?iYl8*vXH8hUi@UG{orXrgV%6TA*KpKNk5lf&V0nwCzj$iwe|5T`$Obu8*w-F|h*&_3e7pZVxLx5UZ9WWD^`U zFka|)K&^!dj$1fn%hLrOvXa&5hjsr?)&%N|khaIa+NCd|J(zB{o1Y%G#|H&;W+FNqzuo>YM+fWcs-ZWM zA2;6BhX&xIm9_I%F0bxhGWHhFfn87W8(rpczIf7_Sz8?8=30Lp7=QDt3#${;_d8FH z-WfdwKVMz{<>qa@U46^6%HIz>e0}4hAMHDKL+iFre_H!^Fw^`lb3{7v6Z6f$z;PpU zd}ZS1fus13FMt2++Jd+~H4~pRUw!0*Bd@R26el(k=H%qv;a_i^eeB@VH{SXAxy2u{ zADzyaD~I;`7sfAh8$6aqqxr?g$W+uA=ze|1P~R4_cz_y$NO>xmi06=IHG$D0wRkoL#Ol@aF%_oP z7A$PUL^PULt}ZE+OjXVnYH&SU?Y3cC^hOFzqlu&zqgs=Pkw7*!UuO`5U3K*!pwo)M z6s{6h8l$mXT}&Z?B^JgdX$tc+0xc+&03wT!BG6-`8nEc|4JM&Q3_jx(Qgin<1Om@Y z$UHIlTvVzu0f@#44B)b1mImg*01sg!oSA$+e+GcU2n@j}grF>hFXW&?7zTzPkn%=o zbA&3HV%Qh85`(!UX%s?`*=%N;Ic%Jm4gDh$zgs@>quXo4w%-Te%u$MAkX>Cd> zFk+AjGvSK}4Rs$mp(9`_cdvKkHl)-D;|U#gDe8O~u34nV3}mcK3{od-txhXc2>1#F z;m?HmD9j5-5CIwm%Xu)W;K{f$RIV7|cokO8m7_=`AAvan8G^`>a1Jjj5)~kkXk;Xp zAITZP#u`kd+MvNk{OTyb!&vyWSYb4QsY#qj!twl(3P{MsN!*l+8-eIVE*k-qYK_j| z-f>^h^LS+#q5A~WDhON;Jj<|9_X-8ke3VPc4M*XZkyE;Pe3*|2W^(!9Fjo72vIbFN zAa{BEr(8z1s2X%nUlc#Jc+ozXf$AB8YK~oLf(EMRzKfMbCRwgzKXJLFUMvq^WKCdD z(A1?HMdM06dZq)#K1U&+J6?jVD`P%A!Oy6!I0iN1y*_irr+uc(sDd`0X?e5lT*Lgs6*b!(`2mK+{nbNH2LJjox#ToG>wTgBSa5w_< zXi&DRHojQ6EM;q1X*^>h*b;7Wb%@t2w==Do2PHjC8@;REmWF97qBi}!E$3jm|8!{; zd-lDjnJWrr1Fc>5db+iE$Z0X%+EQt=S+BP_+Rypr`Bqfa@uz2=mVM3KanpYsKDzZ( z!k~Xl$P|XkTg5oJI^ByvDQ>&Y~=9nAOoC zSQTF;!4EVSF1}p%dl%%nyV*0Fp}p9^8hF?ac|FXuID00?%o{z;UOuZN?)sOd8!q=u zeKeQHl-gEpTdVEtvt107h+X6jN9*xKCaaL}{3gVHh(4-fCB0?gQUm8*#5mS?GB|be z?S&?yv1q7owWF#1TRISY)O&Tw&1H8j>$%^5yHf3OwyiQE|88nFbIYDk-GrL)=DW34 z`(BCt@o$e55AVM*&abuPXrg(FlD4zdV}Tb&pOZiFmxwjX>gk`K{d{NZj(Z&$jxQdh z+^lJ9t0@nZSO-XFV`cjVTTQ`e|8*%J*f(#WkH7j@+&Ooejb^JRwhWV; z2QGCF{-oNs`A%3}{626q__bl)X~nT}zht{>@ub~skFVaFR@cizI4I`?(TIo!AARBI zIDk*@tQCLky6@=kT7d?ai^8^Nf0Yl^PDoi1QZ8yJsp)@5UV3$^G;8@~df#E`s`?1% z+S5_L&Wlq@j;Plrj`9s~9C>u6UP|vjcn!1k+z@0)3&$N8blz>3@a80kZEAVg6@PeB zMt4VFSJBy>Z-&TD^s#o+_BM|hbIw^^akA>D HtmXd#*_`~O literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/add_tactical_sign_act_disabled.png b/Z/src/nglwidgets/icons/png/add_tactical_sign_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..4266b9898f2a837da54aa0299162d56bf07e9879 GIT binary patch literal 1514 zcmbVMZA=qq9KTX6Z?cuhCZLYX!IVwgd%?ckNu}3b3oKMSsIyB<^x7VBgWi?vVPBSM z0Y7wRZY63QEXJ4lp)Ap5(`*jiSWSs@n;GnbL1$7!7N^^MgD_Df?uyj;f%svU+&$0# zdH%oO|NY*#udgl0E6oD{prF2vYLwRE^qZrQzSjbVDQPJYEl#nCZx#czzyPF&cQIhS zm)^!SGPEbueu1e50C_X(aEeY_1L5YqYC5f>4tjkO8UU(mfwMM7Ytp+g!MPLMjQA~yEh$@Ug5OD5+ zBx{1FnP{Y}bG9VO0JVsskAUGoAfOIZsd-@=jN&++=D;wOq@nVMIFSyjIDdJDfnxk_ zf%S21xSsNeEt_&GwX-^UozpN*NraeK4vU!-@5j0g`Ui9@axxah(-K zb!!kEhG_LDieo0kqD3&PmeNp|#hT%m4{NsSEN0S*Ayqhqq83zNr8SWlj*=KjYII~( z23ybhMVfOn8M~}xcMgj_7fYB0h8B6j!SijI4zRcIBJXeEeW1BX1KMae%cbRXd7eZ| zF#@}t@mK}k3(n@3VCS)q;CkfQxb>9DM4={JirIqV8Vxju_57cl!ICp@x;dU{mdugV zf$8nj)|Z5*!^3dW#0b)8pu|4|0FYH$Pmzw`71yK3k89*A*<$$~*=sMiWsg0!_qBXq z*QT7AnO<@t*4x|LgM_?DdwPwaqW zx2U1y$qfzEaLMiN)ZoswZ{i)qkp&~aY#AJRX)`b;z8bpOw5ws@{@wnPSYK{Zp`S>6 zo*Fbxl`E%#d&@yBFt%5B`|6<=lSfC_bS24gu){tXIQ%ei{fHA7m*up^E4hWgUNLT# zCsUnzS(M*$cKfQbXo6i#bx(oq@kfDp*c;!mPbsS%znQ;@?7i`6f9F>~LssRA>|^0h z{esuUlIY5;_I1j?OhcD|cGR9KuXyj;qTC|)uJZ}_XZ_a5J9&oipIMdXR+tM8%J+Y# zNPcsvSus64dE}FYxkpojiQ@9(%MBM5MLLBG|G2bLac>Vfej_}5(baW%H#hO&%=yio zt^<+N`O#1$h$@$w*jM6Hp%@{Sff4~!u~c`9$jO_|H7<+p^Y~}3{{4~hLAz0N@^C`& zM&FspqeEGSbv0G^V~g=ylkv0s=-!^8&TwJ>jr(OE zbS*lj58dlKUUZ;j_3)QFvSZ_iU2mW2{=L-ebUgIPB7ht)+--s?4h}fdf8Tn`dg_E} GYuCSki5@us literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/add_text_act.png b/Z/src/nglwidgets/icons/png/add_text_act.png new file mode 100755 index 0000000000000000000000000000000000000000..4eecaaac2830ec83699b96863788205078fe1050 GIT binary patch literal 1385 zcmbVMZA=?w96z@3B7;o>LD-17983JLwf9omqbH@5UJFeq657m46ned0=>hGP>tPF$ zmEwXf&dg=Wu!%;Qe86SmW}+V)N$IAJ3Cs~gW|j=L7=y+bmQ6wjjQSi<<_EG5UUK)m z{eQpz@Bi}L$;O7-{M>`N5Cr90>gXmg7Rzr=7Wm!^>5^b5kxUNBCU~R}BXW?zEx0(? z;$zylCXR9Ublu=8A!x6cw>u<YGA(NHL)45^fY*oNX-tybnB2nDcE1bh4v6IS?xWoZVQ3$h{~ zka)ol%Z!Xm=$3Q{P`VX@FJQIq5c`AMi2^A@!%P6hl^E*t$#HF32c;(Nsf=B%gZ7>P zhc^o*B5;F-##CAw$4z*JN>gJXw77vV7}TUemBw29 zL5cCRT-q-W{BC27&%{zjkz*u5vrY+i+nxF8tNs7s>0)_!eI6vK36B{O#rC%!b8ODv`{Oou0`HmyYX>WP5TB>0RF!(KnC$ z-AC7-_+|d%o>w}A7KEde!N1&fFN%;I=QTZarFi|C=gD*2wu$ k=f-OEi?i=u%!D$spsdn@=T(_CLHXxrF*VR*HO_&50oN4xUH||9 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/add_text_act_disabled.png b/Z/src/nglwidgets/icons/png/add_text_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..f0f25074184e781abbcb71e689074a6a3b54b7cc GIT binary patch literal 1270 zcmbVMZD`bH9FKi*TQ`eLp<2%oa&<8Ak|(*BT*94Q?sBIGO+D|-F$nRD zCJ(_JluP4dzrq-XHJ8;w(J4wjykcmi?CFqI%|vJni*;8`Ss8&2J_v_YJx)Bm`Xhm> zr8x0%SOSungv09I2@B>YdJD?Lh{BbK?%jB-$|C{|Ix=3>Ms=I7#))NK9__tjiolmu zoRK)O;#5(};z`4Tc$fqM1w;TIp-DOzVp(<<&Hx%vfT3t6K(l<1;Q_$w4}q*%r81ur z({)=&iW9?*WAYT`x-RJkNy8eVXpZAN4u%OJjetF_J90Ik+x`ZF2yMkuO-D6!++&mn zjfxW|kf$plXr?5s66P_1eB(EaV=}xP7eO(#+ur8VcdjN4%$Y=Qcyk0 z{stK3?)8Q|MdS^?&r(rQd zFl^oX8Br)yf4_U+R@)TVTv5~e?>_BX626PKF727ges(Llu|?SUtW{X*-7j6@v`ytl zT9P{;MR&c1Ocv|T!y{bc&$Z;-ch26V7CKLypL_R4@tD}ta(#2pdmTyN#pcAB zYyJUp>-YWP+tHow;ZS0(y6b3HU*emlJ{e`15^J3FE*@| literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/address_book.png b/Z/src/nglwidgets/icons/png/address_book.png new file mode 100755 index 0000000000000000000000000000000000000000..54869ace79dfc899547ef227e98f2747497a3b03 GIT binary patch literal 575 zcmV-F0>J%=P)lqfc)^d&%`aV*~=P*R~d7b8S)n}FzCEZ-sk2`K&`&Zj3tKpR{RTcethNF;Z7wbwX^FsR>`FC1gwQBF66PYAbI@Zdw4T2_2SE=~U}7m)=E0J|i>M&*SLy4J=Vm3;ZRQ zOi)y!QVEKU>;Es2Kg=-vTVt3+z9)AERtyf}g+_nz+fvLv{kFUcFaXK~pFrEhwEqAA N002ovPDHLkV1lC73o!ry literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/big_letters_act.png b/Z/src/nglwidgets/icons/png/big_letters_act.png new file mode 100755 index 0000000000000000000000000000000000000000..1228a8bd6465f5c3d6375f0d917e8c52527b2ad6 GIT binary patch literal 1610 zcmbVMdrT8|9KTW##g&JK*EZoeU_!LLN9i*Z=o1(eN@0<)#c{MJRBW$aul8W5*lmho zF2ayySwu|C79T_Ra5`lW+;osx29qGcL{yewm=EwV86e#isqPQsAG_r4_xgT5-_Q5) zyFG^dEMD-d!2kg8ac8vDD%a*d=>n_DKJH*i161s@oNV{-~0F-93oB(sIcm-i3 zaC7yRULp+uxRsXT61qg6CpVE+0q(OAFjhN@27t5-#*Uk+2pTLWDl9eybnjdj1X|1r zXuU{}=%{GUeQ9uj4a(3?9h9Pjl zgsxIRPeqmJ4WOE&2v8(I_$EY*fMQgD3R5K#$vO~2Py|LW7{&OgL@vbS2m&rX5bKRH zZRK1RHpbkYilRr)jpt6i^uMr?B|CW=iN%;0ty6(F$H>Wgc^+CdwM=Q3Vs?I^Cc z6R?qRkWR|P)?;IWAI#?N<&J!YtQvU%WnqhgZ`P0|rW=ulLW zibya-EJaZnrb4u01k;H%A`Pb1`8i&M)rypuR;5A_p-h9KT2v|&tCW}wRbon|NTL+_ zu{kyejoVCw->-%ByNE?zij}J=0;fr;m?Ss*JHSv$(xju3w1es*kpKntxXEJk?f44x zG+qrsS+){p9YtEfg$&CrFHoSCU?Nto6hodz&gvFR5D6+v6-l5)toi?B4Q9o_zV`S} zyZE=*9`sG0H9xy}c6|sNduJ&2a(oaQ=>UKLCP$+zW=6{Ayxt5hpRfJHa+Za8<3|FH&0ZWHOx7IdrL>%C*^?DnTl=v0d_;FuXSXled@vEp0)zKVhJ`|jQ2)}h>t z0`E0o%zI^SoMTkC1ZJMdtI`Hb8U2ba&oHgE0?#!>)<3VZQ>r`97*a8Xlp3B;Jh%{*|0;X3W)_DEv-NJH9D^_0&wyLrxM?H>eKl9G$u)&71R#UU_A!bEy5y&4AAWn{Lmn zyVd=G*Rw=>G^qZ`SoiN9K1JlyFy97>cH#vwuVd{@pWSo9hVK zs@T*jeShG7>p+%@XiV$*tzbU=!xgpDv#lJ(ngp())e!O)B~#qFy#ai@@(|eMuK7H1 zQhoOeQUCbJtwxVKGHnh#;qJIJ89FiZ*E!};On z?;k~{qGdd&FePaDo%P<*$D7dRP+y{{bLh%j)%SrU31@yc{?Uhxjdj5X{){& z-wrlaT&{5L-jW#;-26>HFNo7NOqOjrJO5YTy#w}NfmOTC9y}^I8FJ(NNg%ntkWvW; zg=tFft{W>KIRE^mE#lbDCUZ>V+HGw~XDdZf-K7otVlT#z9tD;mzyDFFNdJ?s1T~vYW>gAoGhAH-Nuv@6@Z4I@`|Lwa!tGj*Ygd6WJi9UxQM_) z#E!gZ@ne3)#WxDxHkA*yRfV{=CXR|A6;H$ENg5D{yvD*wF($?7q#ar1rNLa^MiF?` zL~F7mYfjbrt6`U{^038(m2#LBgRQs;H9TjhL3ZqplE_D z!8#*bFE?v;1bDg@f~ffY8^lt4Jy9TKXp&V>+=QW`sK>Qx9oGWaOur7~U0nk?jRfv3+XVYus$iSu@c9p zbOoThjIQDqTc z%`Yu%qK{EF?B2L-jMK^BP71{A#wm*hS;t2HPtH)_45~NBJ7V_S}0Cy#V1 ze;NKU43Ce^!uf+%W0qKQ_}ta4@8mG@n0eyCgBdjiUDKm=Z)Fut>^1lIE%|8Z zExc#!zPNlQdno;bS3h^0cp_&qV;euywY}gFbM*3D;ox}lzpWFF+T^&9ZL=F@->_@)pJKg`sf&DK$x+e|m z%*{PfX}HsI%{@|B-h6t*E979EcYmxEy02}$S<@08JntPceQ|;5vi0noyt4<2{?ePj z{dRB84fwYsb)hGJy>+>G`0LU6yqYg-dOHI}`-aAYGX=@$=v*GVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc00v@9M??VT0K@)3mB{sxDIDTEU;0lUS-in>ou?pauG%1MM9e+6&{ioOp3cemPxCaH_5fn+C_w}>x7Z#Vvd%BSI^sy66sc-qb=P+{a&N7}(WIQ}Wf#VIIb#)-?E|Vjq+`a4s zZe@tixZ06X+mWS7NU0`v0+)S|&o~bvt+pZKY(tvV2}d_Ofhxb^(~ef86aqHj!Vr*Nc+ejO7m*UtIrAABR3;py|`5E+OH{~&0g_pF*ezV*klvp zI*mlqgqXCN^nJwE3R!%7eba(T@x`9sf*DcUUY%G4QCq|RHN|qvRqMyK?g{87>%_ww z3*rGpth)%i5nX1b4p_{v2?N`wfo2@jvGvZOblgw6p*K002ovPDHLkV1jn6 BPUQdq literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/camera_arrow_left.png b/Z/src/nglwidgets/icons/png/camera_arrow_left.png new file mode 100755 index 0000000000000000000000000000000000000000..ccde9a388224893176625873b61d7cd5bb624e86 GIT binary patch literal 791 zcmV+y1L*vTP)p0b~4w%_07*ni0%Mimm8>_KGp06#=f%n-@NFJxGr= zAuDV{THJ-fp*M^XEd#iQFZ-tX9Z0#i5WrSs2p}sq!zVmsW$_W~_YAO#G{^?MPuQUR zlnwizvti|>>BZ}}%t~4Wj0_JnOZGG61lNG1YoiXx=m0Zj#O;`oS}^OiAn)6Wyni?5 z{H-Vk_MjMS!+fX%rSLwe5+6+junB1$ z&{T6!1>__PW@Rh#G65*9C@40}*8u8x4G^J#9#jaR96b$Y^uu*II?_lEUxzqP0DJ>d z3jm?&fJT&~0NsI=-2P`kJ8`fVYJ@uILS+H)dn2{ojmdea9MzrFhxw-x|lJk;3>9&vu zHX|-{V6ISPjOe#rB=WbXh%uQA%h zg`{bG#E8aadA$Orl$O^=##;gRjFKq$ecWGPFW zs{w+ip+NRQE;Pb(%)N`v5VR1B%MwRu>kcp=cm|5pSt!y5$TPQ|Rw9P2s~|*AYO70D z1;nR2;m1rDEZcTNVs`GX6^gv?n7_2xoz`A-N={^N1uMRRkJ>>kofJ?>^=|l$t z;3wS=rSJe0qc_-cbXYB(18PD5?34g@i2&BI57;>+B9|dQOpM5BHdg5g z4Me}H;G0zqi_}V zBsv&3eO$M22c6vN6a{sVC;O{u>gI!%2krT*cWAxBfDX|C?tlvn@;rIju-0{fo{gJi zN$4OO7@~1Rjl5erXm=Z~wVw6s-{1~*wEJH6gM%GxX}9?%f6@LWp8pcjFB5xcl~#l_ QL;wH)07*qoM6N<$f}62URsaA1 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/camera_arrow_up.png b/Z/src/nglwidgets/icons/png/camera_arrow_up.png new file mode 100755 index 0000000000000000000000000000000000000000..7d79b2afddd9910a52bee7e3df8fc89208201edd GIT binary patch literal 756 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc00v@9M??VT0K@N)@GG)UYzd4J$P!E(mU1XkwyU<1cXS!iAD(q9ht)To5am0;L7YM`xHBN^3w` zX{TS)X=~egy;B-!EQK-5;>mmNnVa+E%%uQOYLI;Qp8fK^`K0D<=^a(WbN(Jf&ettx z{XOurulxT;vZElsWUb2hZwonZCvr_EcX zCy=^IjbvMa=zDl2!&~u(Z!aUl-T$^LLDJj1FS*z&Ww;9{gSQ~fSrFsyJl;uCaf2A& zH<)JIkX|^C%~a|lq@QBjWr@9J-A=NlK;RzSNHJ|lEu2G&Q82G(;Y?~J3z#7?of4@l zK6;rzqD|Ftx;rj0CTu{HTA@NO!F2KD`~IyqDHFu#tB+#z^?cmZg#>*OA{m_Yv=nLH zOu8AO(kGepG$Y}$yeGNmU&)rgD4WevVp5_)LX=uw4N~!W3&eRN;Y<-DLi0B-k#h~9 z`sKi2#kW)?h|Zajm^+2Utb(DCD|7vZfx$1-tG6GiT?-;JXAz${iTEs`kWE-}Khr=Dmh2u~Xkoo*l;N7PLq>2kcQ)og>%S(}+&qI`Ef;C4S z)*J_m)L~_;QCq?9@miGf({9jK5FD#PDgGZCZxFES5U?LWU{pyR_+g{A8}K70nHx6A m?DtlgwYAFAL*264NB#@t0%(=xKrXrf0000?N3o^XLNlsZa27SnwRbI-(z|j!q$Lh) zeMb{;yZPU@V!y39}xyAXLfMKjGL>*SrRZ3jFSYdKHNjv zNt_5(c9A&%5MNG}I5>x`Q0HQN3S6{N1bu!14FEX{f_~iPB{|SZdMH{id+_Zk8AuU& z*;17aw)stDIaN@@lEpO(OI$TxmzIz%$OUtPI)T7PayS_DRnP%lP%j(j)d_QP8d z!mYDomI+_NN-rztIKK{ps;jFN)k+1!dLTrr)ruS_Di@AfQzO4 z9L3O}$cQ_cDo!sGls*Z;=eOCO64QZ+L_{{e)aVwmlu#7B0%KfNK9c6Fm|iBFC7?m-s zl@4$??IL4-DZ%dq7JeaCXJSd5W7ragsfcwzQ8~jgfpW$Vnu=8l1hnBUiWYao0zHWr zBUx%SNmy9M2aac0M?FV@NrS2cx!EZEEOJ4&S_5kkZI((So4^wPCu@)(1`^xjKkX9R z5_(XaK5c$s@$~wTv~Xuw;c_VAyaNC*$!W!mCBduC`d4o!)>h8FfA7y0#j%Wx3@+Sw zm*@H9fwKCQ^-}Pd!TrX(!Hwwg)-?9!b$t)d&(cNnKU*)^+-Jy|zOk*ZE%~KglhNU` zEjQ*R&-8RX8a***D05rpW&ZkO+HRU0B+FIeXoy+kZ)p z@?~q5rxvDql$n8ON-8w8m9mAT4(Fcy+f6M^fuI`tW%AJ;(H6z*4_z8J~X=5 zc2C;%@&J!VK3SaI`h$FtJ@0aQPgVPJ;4G*#xWnBET}UKBDwST@H`f?vgI*`2va(#Y zDy2Dhq-*o}7Q@zenpX8OZJwHgj{TVzw)M0Qluixt?U(i^?*t<0(Z7cqzD$pf4L5b< zj*M=)XvDmk(S1i##>PhTcT7IAts{}}7HRiiOV~Y{bSr*?@2!e+pW4jM`XxgL4u99Q zrEJ&GZ#{;c-NESnesb30O*4#NOWmjA4>z9aRruUH8m8f&&rxO6p6s9GITak{kL3Tf zcW%)t7(N~G{O)X;Z>^mEebSrF(*B04w}1_OMz=C7Sw$4P4~^#DdcYLycszK8fA523 zKyN&HrexTc)>-I3PVZs97<^QEkUzg24i7z?(&27ifA?LwW2N&z;YZ7g#k7M;foa7r zAJ^Wyf_Ly>&WZ3o>9W*t#5NgA#p71U3!u*A#?aE$)E<0VI+2+3)%!!!y8Ud^{Lb9n i_H!2!&{RTgSQ`h7Jfh8)#=uhXKW;TI#17?^Mg9fiR#x2r literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/center_object_in_map_act_disabled.png b/Z/src/nglwidgets/icons/png/center_object_in_map_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..d8426a852aa1fae0e490254273dce42c53b31f05 GIT binary patch literal 1412 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+114msL|QL*wV$&(AChw*v!e% z$kNc!$kEZ%+|d}O*E6rUBrz{J6=rWH&|ausC%k&CoQqNuOY)0C^7C_GDIg#tza+mn zBfmhwIoMReH!(Rg55xyW55%`FsYRJ(sVQzn`MC<<@U_asV!wfHfYNX4zBAHTors|(1pJ*rViQ(*u9|Gzw|^I4{uClCL4{r&x69v&Vu9)SRcBf^p% zENgUh3ckI!um99|g+=2#$L0I`|6gM^WESyfcvPdYo6l25|KG>Y;j$-86z1}qGOKN$ zC-`Kk{{4O8j8Cg4%50VHh;5uP(Zl}_`y*M0H;pP`#||I8$-C{r&UU;-^?gEAMgs`i|s~OmWrGu8v zWj%7#;g4`f|AO!r79Y;9a5z7w`+DA9rcHYnCizWYfB)af9SKj&xdcw>5`}f;9?BVa&+)!a9U_7Dgq7L)SiF~G)g%u7kWR-I(z75`( Q3@R5rUHx3vIVCg!06OjYa{vGU literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/clear_plan_act.png b/Z/src/nglwidgets/icons/png/clear_plan_act.png new file mode 100755 index 0000000000000000000000000000000000000000..1b381dde0a6e2541438c7b82aa4955b6fceab3af GIT binary patch literal 2189 zcmbVOc~lek77ijjq*51XWqUXV6lBRv0!c^!Z6H8X5=1r;q%|Z1iI~MnFkulQI~J@I zid#z*kK%$NPywNAS_K6`1bsjO1D^7VARrYY6zrQQ*#6<^A8*c?`EB?6?sxC+-g73) z&)3^P-&7xi!5A<;r~9L$vF6p&MZYSU+iP?%k$Q$m14NNh85@ByG_EKD1{eZ%6zmVP zxv>ZC!LAsLHjf_|A`M|NsT`32$JW^3^VTI0O!e^9|(0MRO=z?DlPdtDK4w2w*82kPG$;B~-Z^_AM_Joolv1 zEb!Ju8tsOCCn|*H2Y84O7$D*x2M$Dn01_UDcXT3?$@TyN!b2cL0PzF|Jelf9ph6I^ z^k7kM2se`IPxo5#g|6JNJgHPn1wolihLbtsL`W2fr%)&w4g$dewQ!Kc3Z-nhgHU3* z%s_`F9E2~H@G!^n;h#Yo+-sM2>K2*fPbdt#wvDN$(3Ksj3s;&Bit5NP6hYb}xb z!+**6ptU40Rt$swutXGtaM1gRv|I+Gx%+2F8beeKbqB&nFNM9IF5<)pV4;*jcf+D5 zI4++{^`ely@OZKlL?%EaXFQ%laECle5W$N?C(;R?UdtRG!g>-(WE#Pp0y$FXc)Tax z*^%Tj}A6SU?41zYtZd?f3sVi$4bXuUi zFTWt(FEGfwxudu4kBHqCV-xqg6tK?l=KFTM^@qDJci)NIe*5Ov??KW?!5G4X}`8DjI@9MN3C*l zQkK{d-+p-YZN+!1_1Le>PF@Pz_r-LF*rsZ&p0=WC!rYvsstbP>aQSj&tvcgX^`|$V z=kkXlR_G1qfIfP;`{xfmy;8i`tgBpMG*{Z7+>R;w43mb%ENC~C+_vP63+BQGZm!qD zm3JRLCrVm(!R$e#d8*nz7ckP%ayLHH6nve!vtiuM?)a#6dHAPYj|#Ueu8bSm2 zvV(0bdn-EEfp@y-^^(wM0Zs$X2Pl@lxhZpgfpc$u*a}+R$?B>K4|;Obx}^QlRHG`# zeb4M)7oT|PJDcrUol<3Z{orZrbf)i>(O0$#mAlqPJM*6^>IhC} zKm+J#GbqPgPtoF*x_1DOtM5gZ{Jh1gzGmx&hO@z&b*5iV9{C;T>^*Hjmd)-Nx@MGC zb^;kYj$1ESsc=dj+}2z*o!N8Zbq@d+Hz5X1VSZD#Pq0%x+O>Hf`4n!b_o3XyusT~$ z3GWW1{ql1`%VT;W^H$eJ*w!~#Rrf~v zr7tZ`dtM1LP=%T?h(*6$wb(*hGXZ`)67@K7uAiO#{JWh$M)!VMY@({^-dozY7&p(} zaJIggKDhjV% zyW_GpL0rFP)_K0gF33#%bLq*g*dOAQD%%^ixL^xIaCke@)VQ2f7t6a~!BV?*a`oDW zelMF@g~*B?5K;@iS=o9rc=EZav0+Y0&K93n^Cm%^E)~1hMH_kU0F9=&KxyecyO`eQ z@Ed~J0Q;84HY0nYZSsw*)>y<$Tx0x#{9tN6UX-S^YP0QXdUmv9wR3Nds^aU)giNMi zT=CXXtXZgbZ~tS(S$>?q zkV#i$`1={%WOeL-us!Ki%t6UWihlZm4we>a*NPtVRSJ6?bh6Du9b|YlFVtPV*N8dU zS6|PxHNF30yljt+o%Q8)3#I4xrNI{->R64werg4KTNgGzRI%Soml&)=T82}`910BA z=WbCC<=^Bq|7%wHFnR`gpvbB=yp(@>c5p1;Pm~)79(@vf*{v=UH8TicFWuhjZC+siwSy2vjuqVo@ zd254fbnYt|95~|(+Q-MW-;5Pi#t%h}lTsFMcL;W^P3ZY=Sj)l-(?!F=lmTsn8Q0b? xQ#*Bf0fue*(DomFe!-D{JC%@=AY8C)#K5#{vp)yOUYZ{ShNmz6n)}}5{{cBIj?(}D literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/clear_plan_act_disabled.png b/Z/src/nglwidgets/icons/png/clear_plan_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..6d7b027a0ede50c0f594b7e0bd849315f7ff80b1 GIT binary patch literal 1573 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+0DSo*v-V*z}V8o(9qS;!r08o z(a6%!(a6!!)ZEb+rq?sCxFj(zITdDaCeU7}UMIYIt(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe!8b8EGY`ZEMGwTcE~!PCWvMA{Mftf3;PAD|#A3gJrG){qzb#yxoLmf@ zEP;M@HMBG}Rf6hGAt%iAfsWA!B@U#-0uutJKoAq2^no0B=1I*1=9nU2*7zBqf0%)R zDb&-&F{I+wlxguUDTN}(m%rTSqT{X7HECMdtCc*0s*B#-GKqe*aN3pNQF6`^?{-Nzrxu~)N|9Tc`}cjU-vGF^YYI@{{m3YMf@dEzlmd5vDu^1%hJ zng!+ZTZJRo^ljd~2??%UCGECM-X~2kCdWxLVFjy~W4zeG=MI~z*sEqaOtolMyU4Cv zlgHpMs_3-GOym56SHIN027Gt0oUeaCU+B>}AH#=Id)Pk*g?cr9K7IdLt{z9h(K1ot zEmJZTEgqGZo)S6QlQQ$11&jD<)yD}eHH<$G#7D)51acpdW3f7zF|9r7{M<8PQ>Olz zz;7(GDX#f+lGs62)9?fdpT_cM;+ahB?#Eekmf1`{sK4WvYS)}l`}GD>n5x+YEw8*^ za3r-L^QYp51E0P&?+F+vc51jH7pc-QqS~@tD(un(fW?lB`Sz zc~?%`K1cJe$fR>~*y=65TU!b(iaBDl+K2D!k-XJXVfQB*Z8%dhQ&uLi@4Q6LjABo* z50^EkOSye+X!c+F^zGB=7{^4wRVx?x?hunFWkGHD|fqIwA=giv$g%!+Ud%zch~&#y?*-1 d-+D$ih9%c_Yd_x?_ykmNd%F6$taD0e0sxa#NJIbt literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/copy_exercise.png b/Z/src/nglwidgets/icons/png/copy_exercise.png new file mode 100755 index 0000000000000000000000000000000000000000..f74eda6592ffbbf907f6f5578ff2667cb9c5c621 GIT binary patch literal 1589 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+`!qy+{Dz$!otza(9qS$!ra2b z($d(`*uc%r&Ct~prq?sCxFj(zITdDaCeU7}UPruot(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe!8b8EGY`ZEMGwTcE~!PCWvMA{Mftf3;PAD|#A3gJqlE#ozkyzGadCEa zF*k8?aWOSAQG)7CAt%iAfsWA!B@U#-0uutJKoAq2^no0B=1I*1=9nU2);MbuI*EaS z2^eCIAr-flO!dtWb`&{&|4rVc)?*y4P4Wttl3e%BdL&+_cyzM5{x=0j*CXGe1h#Bp zXLa1O@%xa2eawyDGC|%b)cc-{#+NcdqX?=Kh=gGr!ON zUT>Vw@mwaPSKv~8%9{&E9QN&BAoaXbPQbf*?~6Yx&imEv(fnifq}%Jk6cbUbJ9}Qu0T^9lN;G^frIXb7HeGXJ#{!p0L$f zU9o7w>>a`mvn?niC*@WXRVpq3}TE4MSu4!<~US7O;7cZ z2YZjMw~ORm7KW=03;Z=E&Pm@8;ZW516dRuudGJm6e8rQ` zES$?qQ*@zVfncM>@~lo5p1|iS+XC2xI2}qRG5_ym)bQH4ZC0~^@|=UyO7b3_SAWeq zJ#{g+Gk@aC)92GqKX+L8@%HlO_VvCuinq>;D*e0PYw0GHUHO4eJ#R4mG}zqx{>|^T z8X8t9Ro}XHN8bOC{ou#*;zv<6%O{=fbxAPM6Y5j@mZty{o?QBA1o6*oKJB t%jSy3oLaJ*`OLYA>Oqfp6#i$CU=W=+`^Ch|W*(q|+|$+1Wt~$(69CFDNb>*y literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/copy_exercise_disabled.png b/Z/src/nglwidgets/icons/png/copy_exercise_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..d0b567b5161d5135c7475cbdba92da3dbcd510ef GIT binary patch literal 1224 zcmbVMO>Em#9JjWWbrnM@>VXbQJr50SBDS9s$F)f)c5SZ_OIoGbNKx0}*sqOg?dRFf zl9mHwqrl*R24dS`6H>YCuuMW?5-8F>x&zyB(uAh1o2r5Y2gHYff)Elsw@m@5+5t=U zd++~#|KI=H#|LwJwzh3+BM4$^reDqD^|9z}eF%RSs_EbH(iv*Sa0rcsRl|pbY@re) zGmbG1^U$!S4&8t$g4kHL3&pUQ-7A^Mp^XSb*BlRP6GW=F<{9P$49OB4x7{@LL*p_< z+E$u+kc^n@u|RPS?SswQCq2Zjb&b0*zDs->xAUJ36bF+-8d zkZ>YRtvFT84w8Myha^w4F_TTQWD?LIo)84#8IofG%di{+xEK(mI47|zx%yDpns1Fs zc~xJvg->a!9EP66Fx6_6uEuHPk263N#fXFBVi*w%rrgk|#oS;=lR<@n>DyjtBbSUA zjS{MaX$pI~5`yDpvung|u$m~GGNxvD44_%YaiX}E(LtDp|G2R(Iw(wekjcXUReTfI zV{AuL8Rzc7h9V&LMjG&KTohwcMP|i;ZkSQi6uzM?+mduq&;bwf^J|7w(@(Tz}HalRjj6xKYkw^9o@iZW_hH1NzBr4EKyejnV!_d-w_7v|Vd{d{`SF=;E32@o;qP zeDxY0tfh=97ixFr_chw)*p6&TKHKry_4>l>!s5a}>*8R?3(23JePU$O(^o&rzkBSx z`KRtb|JLm7H|Dy2xnjGDJ1~&5XD*&>@y4!^Cw?w5)l*#Ae5q%oNW7wW^UQ(czs}XS z9Q@$s&eNawzjJYa+n4V56|d2Iv@7v=W%S!1Cyj0Oh>%!UD;P8RPk(1?5hshsD zyT54PMcim@e|>|#`^Y12x18%refYjM)16F>QG5`Po literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/delete.png b/Z/src/nglwidgets/icons/png/delete.png new file mode 100755 index 0000000000000000000000000000000000000000..7fdce4dc927c9507f5c31f2c58911a850fbd1cde GIT binary patch literal 2507 zcmbVOc{o&U8y})Xk~d{Z*Lw`n!pxb$Y>ahgGBTDSQK&IpJIo?&rCGzk9!~bJ*E&tFoe&A`Avo zrrMF{(p6*ORah$hz7`RurHiJJ>>+gJ`3Xe~J_NI7@q8hG%3=6Jbcn$chcrRvFxV15 zwws60gXTbB@;C^_f({~#6D&o;VCI%#!3<^~Bm{gRe>Rs0AC=U=0XB;W-(gAvX~DKo z0NXB{54narx-r88nRpi5(gH9KBS;B2kdOg{ae}x4LKqSLotGfpFB~J`z;_j4AQAq< zDG!=6V9Vn}fGGkrVuBbDz@QK)V-qYEYY3o06o>@TNEF%#g(VoH2_OjkeBe@Re3l=9 zPNMv@C6$Qq0HH9LfJBN!B812o!Q=ZQQFuIlfdh>;l4=+U#9SdG%!n({U1T6Z0w$jw zEM)Vzzyc$~mlrA|!lj=62!Rt!qx~Z03VtR^nlfYlEhr{EI zt&Kqng@PiRE@G)%fsnyvLW_3UQoBE~q<_T{Z21sF$m6^5ctMLD;2gjc@&p0AV8GVZ z6reGfZ0>@*P@W&rk{~{NAH<^Yc^u$-ehKW~*axj~;6LM*hCm|Ol1W$-8xqMBZ36#^ zW&J-nLrR@NE;PqKnq~1w+JOt(U#%|{ehm-Al}-#_IvPtRYKCAi`B^H-+AZvPin}-{ zldN`jbatvb{PBeo#KGhA=X9W6%gYv*q^zth3(N4YKp(!%3kJUlBvF7D7j#Jvs$su8HK5P z@kc&R$esK&q(3p~bPZ!7dNwSotzOnJJ--1qmZ?!u*gs1P+|f=;+N~36)|vkzW|gwi z%IOjr8^tv?XgnNVpjy-+jvgx8fAd4 zlK3u`DdVFt5nQ<@`XQBGbd;`nSH?azaazyhY7%&r5XIv!qk`|*HC4zY6rtA0zXy`+T)w@VOUpHj=3HJPk+|AiPC$f) z(1V(?XYjiU`j5$;cg{aNIOwf;sQR12y-D4kNHpv0cFF#?im6XBn`fgQG+o#CS(RQJ z(mC6nH5@LvGA*xN-6RJ-Q|g$>2ptyHwR4sY|Ho?G=tRE4uIQfno9@@{QDaB!D!=yW z&0P`O`znuy=p?+U9MbwY5_p}KBPSdGvG=hynCX7v!iM89oW4#&nLh+y;xDl$Xphyy z5TpD&ynQ*Es9y*h-q0O)e|^I3iF!s^(mQcyfGFCVw?5F*t9O4x|G3ZJ*|1~T5q|`3 zIpJhiN=MDu z&aO>nt>q!t|Gsms`rB8Lk65LVD1=?YJfxNtEN6}x#*JsPWEvXeRF9S$*uwlo2TbRD zOO)>=eFLUYr`VodEJ7c%Tc-yfL(jp~scbL0S(}ps`h+2-JPfqE%lAh^b@O?CSx}a^~RNCFDRl69KDt0c8xsv_d@++rad5T&+}_Bx=uhn6+6JwtQ{WKxnO5~V(uIT1Ib&uSg4jwMM6PZgx4CKJ@ zEy~&353MM>*%;_{!RnZH!u{uiV?EEA+P&>#l^G>3oGpgDBsG;|tK0mx?@3v=a^T97 zwKEVgQmffwZ=dD7*GQ4I=JW9Fsjk27NWSo1+sf_xxTzi?+7|x#SfN}i z{ha-%9@sfu}3N*&?0mw`IDu-U04@nzA)L__-m+fq&W81Bt^K4;gL ziV0D8Dz4pj`V=-X%YuZHN~8d)hL$i%({)j_X-zRws(7QssSct=g=wO0{vy uy8mc-V~_JW|73MbPpgDF8Oxw~1rT;)!a4Yyx*&hy_lin(Bwe-H6Z>E0Y9GV^ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/delete_disabled.png b/Z/src/nglwidgets/icons/png/delete_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..c3c9f91be34b541b37100789d1d997ebafd9a3ac GIT binary patch literal 1539 zcmbVMeM}Q)7(X;@h6VY|5U1=s*wlsg-n-J4UMQs3YoTJ979wm;$I-h&h3j?K!xkKj ziO!GB3E7$yjf-(C>f!*uaH4Sw>in32IU>Rct`6OnECz!ZB`Volq|QHxf9#UG_kG^? z`Td^n+qR-0H#%y56oMepmORD=*Lk6L&P(tc^y(kNC0RC=$c3Uq_OcR>7&x(vM=b(d z&f9pFtNGv(pM@Z^9nPW>xx~7hvWtR}4e2O-f*Ya{BrC_~X6=={jF$1`PM01VJ@o^I zIypU7thNHH+sIcq^J*o&u(qJcUR!C`aac|^n&qP)fxycw>JzG59?GZ3rg$m14;|we zI;A34>anLzl~`AxMp5EXwGt@oKm$+>p(IopTCFx6B>@3&K;i_cAheWv_&Bi2^#6U&=XyeW1$(&&Qp~&@@BPIvBHw(5cnfG?x26Im4kdc&Is^YnJd4?7-0W zS?fdL+3@f#I583&ja32(=XI9K!WfEtzqR_W<|nS4cfNf`z#JdH%@k*PxHl#{aeHJ` zzGYQKRDAN>xf4lq==O=kaeQ8M!SL3+WqD_509KA0T2q)W!Lr0=aJj!_VXt=BKX||X z=&9Nu*f3iE*W>l0JssT->LQYUj0pzbef`|^V9LPW<8FOBlJZI2z~-R`s|((_W?0i+ zYCJbG6vO6lNj=GQvOn5;|5hWpXw%(N%Zf>K*Rn;DT1^uo~>}dLRMyx?@JIq#_U4icpDnyGFdMCVH2KBm1A1X%uy665aiyZ+SjVv| zhE0z4f4WbqI@`8HHl69grQBxQ+LiS;{-m&o)QS>nb^ItZ{BKAl~$FRi+i42bkyB3wWxz5`z>v!^Vb|darau+{FXS7 zLG}1oYs-oksLy6E4m78iy17Gzk$t^`>((9ccJB`Givs=)$m~(`;8_1|BG-H7Vn-}@ zOBuX96xaE3lQ57Ua11GyN{M7cS~@I6^WY<|_)+Z3 lv0ZH=w&)zX_`}?W2xO!!*?)T0--V&yvc*)uw9%y-{{`S!IdA{~ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/delete_exercise.png b/Z/src/nglwidgets/icons/png/delete_exercise.png new file mode 100755 index 0000000000000000000000000000000000000000..27f32d9acc043cb33648cd162e8520944631e12e GIT binary patch literal 2115 zcmbVNeNYo;8V>~IOQaPTgL1ML@_J6spj{I8u*_h1#2|pn{+X)`Fk{1tnx}qu})qr+?he?7q+YzR&OX ze9sm}?fk^vcB3tUK(G%F<45Bw$@E&U!M~%Kfs6R!f`-PSF>n%^DN;j(U@0tyfN+IK z21P?6sW$x<6hI&lljOoUG%hlND}fbMkx7TDQK)b)f2nEEDOs)(h&wQ;X z19E8~Io3B4j8ug{$?~u)H58MzQz*$wm2jkF-c}$$!^H^{5Gn#RiZms{)dZ5?@^W$6 zbW9@yZ&lFLK=M1M;v%Df5LgWXzEsd#0IF{7p&OAcY)+&6jgC)w9L#*YNihrR?BE~4u@mnU@*LK4R1uNL`52J zCE~uyz=sftTCPInuo5saio|dR8c4=HeHVg46&d-SSc$A83QrkLBT~`mRFI}nnBsb? zjiAxc|J?YXHX_ujAX+qpz!_=@UXLXARWP2r-!^1Y#J%C}Qp@q8h|>75Btroy(Qtks z8NZ=QC5)>3ue*j zp$tD<;&6O|eL#UgKo9j@#fB>pRHT$Zt9IqM-4!hBH?iChH6%h|wGf8WRy!an8Af3w z8CC%yF}^^gNFrC7_NMZ@i!EGq>^i zz6>UL1uOl3az?|Qp_!WFSIx3|gm<7xeBb)`=Kb(MN_=9}_-K&k3(gP-7DzZhSg5%# zHeeW!$Vik*|7I3#8)P7OE*v>*ofqrytvP9pd5Ktd`^Kr~9s|Se!u5IC&Qfg}$+|5i zU}}4Cmg|pBV|m#gPFkn#YA-u|`?$_f?f3$VIrOqAk=W-{clFPkyW1Zuf6=IGo5&$P z(~j((8{8EeXmd~G6-7&N;>2rMoJtlr($&8(Gvl`Am!$#z)1w_%W|5Ww;&^3V5nOLs zeDJ_$d&AD2j`tWFo}9vr%g|_+CMGHUi0qT~juPjnnvWZvvg|w!wucMY=Jv8qE4u62 zTw`KlS7w4Vzchiu-bA7N=fot~eeOt>U`r~c+-Krtykj+PBc#F2LmyS!p`;D| zd%dHEQ$KTXD!MQiT`|2sgtU$rw4-8Xzhg4eo;*IDC?R&(diF9YLzF+nCw%pj+Z|N_ zhDFUA7W=PfEmVaSmWW0l$DG=k$NaXU$mYJXWuRe90^Pk{6;ZK=WTeQmYtf0UCMK^r zv7uh`2(!9U39dbwfAm1^RNKQ0`M-MH^y~6&*gSzkb3|J&d#|gqzv?YobJn4+HbSp! zH6F5N7va3&SZzpUjrV?!k(yR7&#`VT!s}6(x zP=ps}&;HnBJ>rsoFn%Z>T6%?iKK!r=(VcPm>yPFY9zSRAoA6Kj^bMz?^2--4Mnlic zUnUM+oHw(#vb??bc+}0)rOkIAJgh0HPWYJymW*}RlgSe&`^$maB9YHA%i_uQb5-uahZ+f3Q^&n=17BeRq zyUJRXeGi&P^da6IB_gwifZkTd+_9LG=MCCf2IXSJ5og1jo7Xk7CxXsY2aol*@pNW= zZ|vHhY#uVN%S-v9wS33vvXtTPCpQebyj{qb0db(7OB zuP)sqUS?7{@9XqBI;eXMjHW2b9BgRbu@1-@)aU5nYg=SiKJG+zXK}7!2|NF||7c@Z zv)wvJ6!TOfEo4G8M8UvuS-XEr_!Gc7%oOa9Mo&}}W^ji-P L-O0bWEiwPU1O{`| literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/delete_exercise_disabled.png b/Z/src/nglwidgets/icons/png/delete_exercise_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..52c58e8242e1a367b4537561d3a889a1d77d2e88 GIT binary patch literal 1568 zcmbVMdrT8|9KSvQAEk7PSbX5+(5Z{`?)sz$rLw#<`hHaFHPrx+_w*CB{E?$=&bw`~JS4 z&-Z<;r6p^V=Pa5706=n4AzsF>^4L2ok^c?{4CDNg&RHtCa;BOK5G)Cp+>Db1i@Zb) zSw<4>hAo3+E&zyXDMuw&X)nfHj8{R#bQD3ak4FPQt}*B%Ty-P|I>{P}Hb4(P>w`eb zZGb8?cEs*0AZw|@MwTpZEOEFR>s)#_WXuC|gBVZXB{>2NdOfrs3mTwlUX0(z#4rR- zt8jG&=&4hc_ENBbVM$Pu#6_>%#uJ5WGIS{TVUspGg#-GB`;1U{ry?UT-X}X>C7OM*ic*bG7}B z1|JERk$z??>*DKCof!x7xqGppm?G~Dww|TQR%@WYXwN zsyMcY_HzX7BI9-`-tG+6^g=9Fz>);Vunvat#5|>rkuNgsN30y&Bcx7H9_R{y$lRd1v5Qd;F_i z;v&8WW7}uV&mW$R4@vVg!}7z?{l~3g01%cG;U-7$2j_S+Y7|MLkDnY#Z>a!AH-dM? z&P1pelNkk(CGJ1-7^I9fMepwKFLrxP4*zcIa@vIluF0)WFpVSBRxNz65Q;}mgwhRqVp%EZ9gZ4DpPk~ zP-f8G^p(GsTkd?}cf+cY6`4`Se0b(bXd>N;ETjxED!q5j*u*RMW% zva)L9rzusy<>tkKjL@q6D;9@`wmSwij?{_k303>`ebGt5t9_xN4{+Nn;qxg+#UCZ~ zMf*EI+wb9_1udPkVe7&lPMxS3>e`iapmWc}k~8)_y>EPce|UEF=?c;6Yf10XV`)p}X`b7D@uqN+ zXj7=;P|Nw&vHISs#B-Z}*(+L*U!Nne!(Enh3iaosRSy@Y{x+2%Ju0tYZq64bFWNS& zk>voRnpMX3S+)z?*Oj*$-E)}*NSLfO4MWai7vaC1HB_Cd%;_AJ# z^v1~CY)NbL_bcwTdxVke_rRV_BZV8!H@2xinJ8cRoo_>XD0yGXqsKcBq}=TpS}r(? zFM4ad3Oe-iwS#BCf%%z}O~hA&(W&U$f_IB4Xv1DfyQ%!)4JJpcdz literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/delete_graphic_eass.png b/Z/src/nglwidgets/icons/png/delete_graphic_eass.png new file mode 100755 index 0000000000000000000000000000000000000000..43c32de1ddd75f9f62d8f53a991ebc5e5d0c682e GIT binary patch literal 1594 zcmbVMeM}Q)7_TT`3k-FNIybr15a+PHkCtA0p_an6Qlxy;syH=pZ4WqTd!@Zf!6|-h zI$;LgaAYc>er(x{bFwY!tg}-jgSnI$_MvkQRMaJGq5~}ow7Vj8{$c!Mm)yPY^S;mT z_k7>>yqv{xyq9fW|_U zkUEkuRaJD5sT|J4VoG1Y6lk+CBW)29AswO1Vq?)9PO8FXBaG!F0~p8>$|~pgd%S#r zGRgTXQnZlPmO++Mnbmf3X?2d?SY2+EnfQuDK&lI42`nT-04|H!>cCub{unRD?nB2Q z9~e_%%H{mWP8DeLfDGDB0x3dBV1y(PAc2LjNQ|QBLI8na2!s$2Mg%a5i4Y8efboaV zTC^Whyy_ctcJi*Wn~DL!0MP6X23~@ z(N5VIinanFM#4Zl89ATz^l=Cln^yaT*y8Mc6=C2!R$$D6TPW2cskZbK{xX z4tJ&Nar!EElHZz!b5dV}TKDYhtt8K;d-3u$FExSY@42u+j;Q_D~_ z45MNQMIeb3hGj@Pq>@00T7swGh)Nyicor6gREScHq)Vkr2@ISM9d$@n*LADK-L*B)ErMW zOZbTGz|i(d>$Ad>;UTT;#Ms%I)jP4grlIpp-mCnby&>mQ!oe^MCJ z{`;ndz6gF`^yKKab3Me6-~R_~zCI-;FluyPig>v=ZQ;<8$e6(OmY)7@@AOr7{ooDT z@t)4Y+83w(7#o$kXlS63w<~)9FdT4B$-f-^?VI;+|MQu5Z{g`c(DzHj<+`RF+qacf z-0eeKzuUw0o|60(SU{!RDJ zRdd`2J7UFInYGQo-q35ZF5rp7dv?zUS4VOWm#C3PfnczCQ^61Iceiw1=-P^YT-CX@ zt-J8f>@NcM?j46(5_+!%Fwsv3-wU=T!`+c{lKqP6idfSG&vswUa!r2JD+dG*{d<)g zZ#N%l+Hp2`i7HvUe)PfLZzXlbFHVk|(cg)FerE6rbL7EbU;TXLes1j+Psh)}+ahSB zJNFIjRQx$N6dc~TOFJ@LpXd#&#)kXAInmL{=uA=Tm0ZQFPdL5%^u5#WOve@8n;-do zE8m@e=d{PywxsG}pY0IF*q^+X50b69@_b+&zU2FPkK0RE@&CAZHYZi^{YYbey z+OcVs^1eJN;WYuT;zLKw?)lo4U!5uFE%+>pQYF_gV)Bw(b10KDSUu zZzve;>-WZ_wKS)V1lsBq3g2nhx|?173dMwoSdRP4GLO3l-w^tnYg9S-(e$Ft{{k>) BXZipD literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/delete_graphic_eass_disabled.png b/Z/src/nglwidgets/icons/png/delete_graphic_eass_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..8f8597b9030e5496c1ec9611abad91b9121d1703 GIT binary patch literal 1359 zcmbVMZA{!`94{~1@PvVxMld6G#bg_D*O%k2w8sJM^$t!s2FFEFnOb^MOEC2wc`OBD~v1XcY%0}Zm6LsG)mMq;{qgTuIdX!apfC|fXJm?qM z20qBM;nr6!@Pz=76cIu-dQG65)BeNN#9;cmx84 zup4^T5kLZphmQzlZ7N^gRuSUbnm8g16&HbpG14Fqd7TAgVzZ=?F*mf#OB#Dq3`5{D zL~n9KD^Aq}DnXB|@}R?pSUJRrfKJqg+VgQ7&jT?8MPLMjQOt_sq#Yv>1YCU}!Oa*OVU3{O`=5S2h+jabrF6J?|fjq zi^>`GsLzQj8@ao`ArokLL+(-qqbO`MBXcbxFX?{94H-AKun;DF1nxsoJRiX^#94r% z1V$rXCxZE$jDx|vzBtEvx-{x^7C0~pu@el6deH*Alcq2Nr7((e;FLYC>z6d0l{h|b zS1|0-sDs8mi08h#q(|jhT~5FJbX#uO4-a1) zqEeD~Dyf#|)zt1U`dG96_ zd(&gRKezWD%A2_S6&+4v+be&?Pm|YxwHJjr&QNoV&CT4CueT$a9c8O zKJuHR_Qvssge%C#sV*tCb<^GBuE^Zoz9_QbQWVDe%ff!~?cr7?Fy6h?b>!TMuO~01 zJcmE{UjN~1jp@Cox$kC&=ueiC{`mNT&!0Lu;_8`x=7WxLWHILXvFOyEzcO;6GgMd6 zorAm6;KuRn@Hz>D%o?$Hir??~jQIoC+ubYO7;KL18meib<1QakgZGP{MYz9J2TI)EH&LY<$|t@m-8_8kPdzC1y-;$m^wk6)Yod1|sdx!8 Oe{p_q1#^mix%+RC{M|(W literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/deleteall.png b/Z/src/nglwidgets/icons/png/deleteall.png new file mode 100755 index 0000000000000000000000000000000000000000..99cbb675a8637addc2151631ca14c3637ca5ebf6 GIT binary patch literal 935 zcmV;Y16cftP)sz_#!@}NtR-mp=tiXQqS}5 z_Vn~__jd1gr{C{x7bLvf)qxND-P!s5ncvLLFeH9E2owO>>bnzIq?B@G7mZP$X+SRE z0Bk@qV0BKkJU)<{Qi1~({`fy1t89A$QUpSP0C)ip1Pvq#P}Fea_=UP_g=NKs_LJ#p zmK>Xv&9Yg|4l4d2MBa#vWOE3Ue1e2Td7T#`+*Tm$nVj}cyzQAEZ-4WvAA-!q3vfBO z(AbsC`ZFmyqmUd817e(%l2ojOVKWIYWq2|Q+v_1f|4zfr!1DL8;SUuh<|boR4XJDr z5_Xf}k;prESxQu*!|GyYk-fEbb@7+u&7fdqyzzy@ZY$o4cg`nFA1ZCTi^nd)gNXj+}BIr}KrmIQ|r>DHVot=0J63RIZYK7Nb0EN7-EML2y$ zp|MPLbTD9bI*4M6L?T_}&ZTPb(}Jfn(1pi1P-D^pYy>Q;GL20?xo_e!6jNUbPQjC@F$BSy9Y{Vt+H0YlI0|2XY3{3$7)E58%002ov JPDHLkV1kp=v(5kj literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/download.png b/Z/src/nglwidgets/icons/png/download.png new file mode 100755 index 0000000000000000000000000000000000000000..89eb2fdfb3e09b4f216c1cdce56c4fa548e62df1 GIT binary patch literal 637 zcmV-@0)qXCP)7!h8%r-1gqiJ zvNkCEXE&a&S(LM+4ru0eTo&*#vM@RrHS1-ui?F+s5)|KGeBW@s_Hr|jc^%mYOvs9W z5}*G6`G4Ya`}LVWKmI%m3L0YY_qRU|U+uWL5Lz~UM+rh~r76%SvV8KqR?0aFb)@T>4yDP+oaGqEyBVJ$*_{=0i`^26%S zkG>oOn)4W|IRt`MRoFzxRw`1wkCB;?A0;^d{D1R!!L#BIS3ZJLz&%_BFcYxg-S=nT ze=z=MddQ{B;ryTBKQqY3|Ns8~{$j)H@^@$69|a{#d&E27ynBC-H5+RU4!V-vp2qj=bGLQ(#gvmgHTo&-g zq9{_qwQhk5?v}D(t!!PnN{@6&l~VDtLJ=aO?27dQh!iMxqT=?4XMc3gnfY$-^SsY{ z`ObVQiwJdbTJMCz;antQVH7s5v%Sk5v9Hy{pT!0@R1}9s!zrjqi9k4k8cv4D5}h&? zih`8t>s=O17;C{<|?N=}ASwR%3~X=^8i ztX1tZOa>1C z$ZsDC<_%G&@S=nvZ+&4aK1G9~1|FSmGMQ*5CJjbX=^&TOwQ(>QRLp{E%+{kyGgWWg zw8S8Uj4DKHK((-*Y-3a=!9yg3ch7z9ZHf-zEx68QrWj&_NnN*Xe9=y|y-@ zQP7Vv-fL})$u>arD98wBA}XvNDVvtSSnht>k9G$fsZ@ zG__XE3*mA?K#=1La2NpF4+Oc4AV99${3Mnaj6g~hMq*$%eW?Rv8W@F*8rVP% zj%Lw7vQ(+k>TNr=0=2qD@mNF9Q}I`Zob^R(|#5X@n)Fu8sV;K#@@-E0oP0lB^` z4&^OY{r_Z*j)|e$+T(xPWoZlRLEH3Q^J9y5*9X#LcLu>O$E$835r-pqN`!(K^WcdJ zU3m1ab>G7O{P=m%fzp1dqO#D%PaD6?jYxMVI(7$MzNBU*3{|?udqiJb#q5pyvrqh; z;_`gu&I{D_zn!nKpvN!yTxgLv#_srCL1l+x(2}sit}B+_{&FthF7*<%=7A)i-#-5N z_(Gp?m~@J~d^M=NqY*ym0tNC%pG?@149;lJpY$0wounZIKT|$+vDz{0e7>Vc=!+MH zwblet)`XPjqXYPJKl@N|U_Sik#>vUi( zBlU8dJT%Me-16>U?kKx+&T2pF53Y~5&dg1CS>_sI8#_0e2ak}3v$co3>g=-qxFWv_ zav(X6g_i}aaDUv_-O{w!C8w55jTU~hYgf1+rnW!B+PZtgeb2Z%k=%b5PI8i0Q)?5` zDC}16`H;_fp^e|&{NnL>OU{jwioHqOx-;ZkfTGAV zCna4yYgT57Nv`;t&H=&M4#%8tH8)4@wfGT7QUVJ-pH{?l7X@k@{X5+aHQiIk23?!J zUDX>oJva9SO?ukPKf&KSyrtLlN#G41@u$T_<9!8SjY9=7$Mvr|iQWM}`!kJ4PGCyI zGM0kbUeeU?bm7^#{=Dw$d)szy#dogFaE=xdMx9sUh&{OR#1DQQdw2&y&}q)mRWz*;hvCt7r;221uVej{Csh{u$oW_w@4&A*Hyz#Zb?mcxkAbo}^l!3X zctmc~_QgQ;P8WCQw%((S|#<(qkwhoy!vzF=~C zF}Q8wdgbKCF4KqkT~6uy;e%=a8u*M*d}>}_KEN(WOeQTKn9eJCRFzl7ySO>;IQ_;+ zvz#<>^^*6iHGltRC$KL!{1NLPj$cU{4%E*cUy;QB;aJZ>Je?p97;ax>B#gE;%P(Fd yP^bRT#J@n>o>)J=urT)hz30r@fO+1BL;yFmR$X(-SK@5@7fVDD!loca(SHHlqTL`^e>nc=&g_2Q`+e{8y!UK!pw!1| z#-bS{63I&9D-0sm1*UiURO0)Wo;yM;3vrPQ4@RSKy&OYGJS7^501~x48VN$=%7iUV zh$o3;9;FJA;WB?ejsjIv-R z^4AKG7?p1#h6E={LllXz3bqpT_5wT&9D+cN;BvsAj??Hk1}-?x%OUorV=4%YtKhL* z@SRgK|3E;1VhF&XKyC_%2?0!)0@K}DES4)kgJ6gX(Wo%Z4Q6rZG!6s-6AwsO!<12+ zAfb4|79nxL7#!Dfs8qdPPtnsUC>BkH*=)9ngGO^BG~9Fv8eDF0)9A>P3_?Vwz*JgX zg=zp3qdXGbigQ82({~}Lwf_F^i8Z>3L=h>Y8su6kOo6CswJEM~Z5yh+wLCL@CBlH87rEj_M=!A+`tfVcZ@LU!u#PtG{nSU#Arxd4{snQZk|NQ3o+cx>)7TymuFY^e5j3A_-Fn3 z^!}fcoH)?z6x%Xa7t1urSWuf(=WI!arh`j<23#@ zn`1ULkzsxn%^VMR+kiIGiqVR+H?#h*I5Vc*QIJ}n@dey=Ct~?OUeJOn6Xo zd-T4AUt!*Y`;9$q)K!YZrc=KWK`x{3T-!Z z73;E!TxK`eHDndMDf^Nd*SFn~$vE2!R6U$>+F7msI@YTHv`a!gG!z|DJ?G%%{d-5( zza%?Umk!rC25gSsSnP4EBcW&bn2Yqp&Wrm_R41>-)?2BK)<(y5F)J5x#w_ucAe3jf zC?~%*8S)P1&aeD?Y4rDnX-8X2{0{skw9S5$TT|A(17Gr4`69=Y4U3lpPaV|Lo=p$y zm6;76^%)SnPPK3{#+Rl&s`@24Ue*@c{nEAF>8j`!JETt9()*2FiiIqypBHhR=@nLX zhcTGc%nkoBqpQp^b4mFR=SrTu{d~w%@-idWqi>2WW9W)8+xT2`Wc8-zrH5LYoA7D9 zO*hIn)VQ0Idur#5^hj?D!ixGHSKobGd`C>)M7AGV7QSLv&Z>L+kMWK_aGr5p4`eyd zOx#s>=tu&v4!0SMTod@UO>cIx)$6Y26TcQ%TrL`XGUhyF+}HF9DIc^Rh<&@Fj#Pa2 VjL$0dsdUqyM literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/draw_line.png b/Z/src/nglwidgets/icons/png/draw_line.png new file mode 100755 index 0000000000000000000000000000000000000000..59fee973f214b931a013656b76ba184a0cc8229e GIT binary patch literal 560 zcmV-00?+-4P)N2bPDNB8 zb~7$DE-^4L^m3s900FE?L_t(YOJn%||33pw!KeiUgLgED22~IV09~U4#413{PS9nT z3V4A++CXdu#BxB)1XcoyWF{6S9g|F>!uY+>o5R)wFOaj54FyWcl3RvJSMVd>{}GRZ{v=IPK6LWCvE zLaIUz@u#AW2S4=v?e);*f9&J%|DMy``aotgunVx6h3yX7V0F*Zq)xZgpL*$k}wEc*7Vt>?fD2hrYF4gas+ zruYBlY0dw?Z|mU2A1-SC-?mxnf6zq(xC23E*zdGj3o@I5m6t_G#9TPW?25rdkc7o; z!*6=qHPXV#|L4v;2gyJk1$j;);j$tqqD^m+yun=y ziO{VJKS7D_xYjQbwvdQm@C6YCfzqNtC0b0Vn2ZC?JuO0O^?X5ZH)nOY-1GaL z3x{)wnQ@*W&Xw*9e8GPSb(;`T7=Qs_4Pe5|?!SPD=puj=fC~V=1DG>u-CZmeKf2xS3nDsU=E)i1huLiQs8A@}kHuoC;c$4;Y&N?@^qzEGPnxFrpj<9L zbzS#>h&;z}K2<7}N2Af`6*F)4z?F15eW%fAJPCzDH>H$nAP|6MS5a=FBKJO%&=A+Tkv*XuW>Qt6>8gm7oGnH>&?cSWA( zK}xyH_qGWl_T7Bj?j>UVnArTpd zVO*`(>(zKXew&C6nAsZ)25%KbnGiFBh%(7!^15l7mu=hr+3WQ_Z#J6`%xs_9{vXL< zCX>05&*zVHU5{Co^{(IVTdURT<5oZbt^v3Nzya`unZKR|{+C3 zh)_p|nGO^R#W6fg5Jirzme<~v{Pt$@UXp_wA&euU@zq2oqD3iu8J>&+;VMLqMxlr- zEA3Y_kV3ImU@>t-oJ7o(;wl{Ka7MqRWJ2-I^)11gk20KH17)^YVb>Zn~VIk#-nslX_N zNaa!Ai;9y(0wK5-1(-C@Ukb87fCbSYMgW`5_5)xL0_h-3hhTq*&1Jw`5Cp~^D(Out zTg{CUh{k-8D;`xr5E?F>o|&0R%Vf}St(*>VI2?-&81^R-{<#YAYG-h#5Ic65mD$z8J|S! zVzM+SJqp#~=~^jyAFF4NlgZqD-jM}Js^KoxV&tVDN&zlSSD|VmT)?A}Co~x*xB+@qIz|+=6fcKStkkymVDqG~(KRt<0P{ zGcUHG*k?{Pb^`{7o!17{yW{cfQm?*0?42&tocyH41PY`(7j_8weH-;f-JL=d$a`cg zbLaNA6Y_qgLHFl750mWbi8p84HuZB%uYY>i+@H0}+;Zqzzcj;Kla%qQW~EttVYlvW zW%3qoYuh9d11P+bU*c=;QETsJSm)9q^eY9rZD{99w(Tfe{3CwINf)633Sows27-aPLxvHP<}Ki{+I>9y$!D&J6*bv~C;n&dRS z=#E6Ko#JZ6>DA@l8W`N@Q`~o~(&>xDX@ZBiExooTuQ2uN*e05Fe^SKsH=g->I~@<4 z=rQFu%w2zV-bsPc;VF3WHDj~){;7%|?ElH{_Km5T;5UJ(cq*@ZVg|6olY*49^~Wpd zti$JrnhdQC>NbM1Q?^@hCBAlkch~cZS&r8qtvh8KVO0Qcp0#RO&!CmtJ{Rn9PW85h zbLzL!-P(K(EQ(aGIqh*LsCh-}W1n&{tK2WDGIH0B#NhZB3Pa(Qy*9~5ZaD8o zD&vQ*@0>y`o9j9;{A}G#ngoDEeqp?8gMJwqP{PT%mQsasRk$TJg9PKKmoJx2{V~?|Ol9Q0+O87s z@C2>6sH&hIGK=F=vfYg0%krX}O)W!B?MF)#qQG-0O#{zUyUJ|le4l7rc6-{zU_9Wv zIG2g$Jr~-{fzJ8I(lW%Mw>>cZQbECR-0hc#ZXz=}FI?MR4VfG=2g^@(GHibvBqpyl zq;X!A4)#~imF?;5Ik&C{z1N_~lB>Sb-|{rAjH_@>aeuVO4R&XhZS_qo^;i?&#b%Xx zW-JgK%h|j&$~m5za=(ud=5-+7{&JVS^BluYA`LPfrC3uQ9O-efec>gx{Gh^x5rQMZ HNo)TFk-@<8 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/draw_polygon_act_disabled.png b/Z/src/nglwidgets/icons/png/draw_polygon_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..351e1013b3b2f191bf0a3f865d7a3fd8de5ceafc GIT binary patch literal 1589 zcmbVMdrT8|9KT)#9SU>~MTzKnIHy8;kJ8uK0)5a?rP{Tqbs>Rkd!>!`?s`3JVLB<* zq(0)5O%k0UjG4J*kH|DEn`F!hiw`p0=3Hmkz{fHYlOdWo9E!Ulb^c-eW0&0he&65k z`}us|x68KX)y#~%3;+N!Efprau+B@qGt!0cP*^u6Ec5wtC+}dqe3;}YK<{B(6l4jI zb(EbVJq^KglokNQUVoL7cUmh6HxrPNNgY`vzzS#p(3VD6(!Gh|As1EWr*-hisU8^e zdvx#yg%!23M#|@}XyhnIEOpsIjuIx$Z!;-kfBmHszf0rCd1^#DwV1T!ch!GP#nQ~x1#gJ8oL?vkx!J_H>jMT0qnK4XN zjH+-{sm3r3Za~YGC~j7o6ehgfoZ@&E)@WAB)rw*qm1|5GR*tFVN`oHPV0v7ySE%&z z6xKqAc#?KgDZ75b?i3b#E|xHI6v;DO6~k;!b%4#s@Jz_Zu#nNAfUKn3PbcMMc^*e= zqB#E+%46o305q9j!v75Ws78%G9k<$KFqkldMu@o_(9a)t=bAj#%m(2Vc{qLPcj8`ElQS>=1=yJ_ie&?xI!TY% zwNAOdHSCm*-McZp@{{~{Vc8b2Qz;o-TpP`h)TFtTP}}!?rw{D>x%pzv*Bym_0oPZ- zv14iRkM)Z)dzW@=2XfJ($luor;#a}m-)$RiiAKY)v^GY}y7^6k0esLkZ*KS2yH^(G zwavQ34z6-7IR%c&maTlf+7y{T(0uG-4JQ7zt|`%UHr@yP*y4ghtp>-C1G)n2-bO}` zwh#JkXY_h|8QlgRcBCKGwlA0DymD}_YD6mmaa!CdDYmaXi&a}UF035izwL4L=YIS;h!-=LUQ1Y%Qm^;&+J`P&FIimc`gFS!B2FKF=xD(rI6MJ?T zZvZ*DKP~SZ>izOUdqr2&dl_U`5L@qPiv~&zp%I5YvrD0xb|_Ze&jWocPJcA4S~5`9 zI^6ti<~#e&1$CE>m_NJ*P4DXPoXj78tHBt;6Z-ZAmX7=Bm%68&cl@w$-}(!-qD1#C zN#kpyU_2}is-m#*#rPZ1#O(OXWm$LYPsDQP6tN=@MaMn>eXSd!E}Q3^D43CT=Foe6 zv5b~P(38f_oG2@b?C9Gs(as(2n4eYn_HpO!+#_jk>K!f1S`Pnm{OX*XqrQ_s@tFF+ z<@YZys+=)%;xtQ0wnslN1%nwa3y6ss>mKEw?|Gq@auy!BU#MKXXOH2`M9Ik&OQw~T i>|ee2_NiSmk)#%|w7Go4-fCI$M{X%!WBSZc+x#!^>M_dz literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/draw_rectangle_act.png b/Z/src/nglwidgets/icons/png/draw_rectangle_act.png new file mode 100755 index 0000000000000000000000000000000000000000..724020d804368c38b5717072d2314c70ad15c17a GIT binary patch literal 1723 zcmbVNYfuwc7!5w6C_11}1sz;gEBGMUT}YNhLX0FK5yB%x10s)*EM$db!)B3ykBW*& zA5g8RD54{UQJJxY*aBm%uUgP51$CrKE03xOwy033MUZX~v_BkwbZ2(&-Mi5(bvWhGAI@CYsG)_zNv2jWz|NfJ7`AHwwU~XU~HG zt`mT2jsjAc0x>-<%ObJJtWcFUD@DuGfx-a5-@>N_3>c*WEQVC0nQsw*qq=;0Zd+!9 zz$k=D5rD5vMJd98K!U^o4h!kd^S5HBZHOU!y?FJHq7JkY#IpSO(VR`nMO)u@iv+ljw^^U zvzEk76iyfco1!L>NT&oK?eujD29rYZM%ZW`D->NawnbxN!z_qxFxc`MMVl!l_SVKb z(PmYq31cfUGm%be>HSDrI8LT(_x?aOAnk@9M&k6QXi~+5Hr;?3DY;kx(qC9QT*sI4 zP$>+fz7UE)Tt67*A*&z>7eb_5F-MF@q~jXz;z~GyG=|HAe0X9QmcV{K+*Klk2a6Dq zh=YoJ#<_B%nbH`w*mzu=jyuNndoPzCNMag_AXNmBI^F@{dV(U%dcp(*Msip%pwMV> zqiw~uL9g=_V%CL@>;pbjG?~5}es+-+6E@q8*JM9$a;;K* z%&NM7Chn-F9JT8A8iT7}Tf-4_!NY!e!;|xn4_LiU&{c?A8f&$zIK$ z-tX*e>k64g9n??#q`j=~kD}sN4O@cqoM;z7?#9R(-Cr#ibiO^S=UWmoE$ZU0Kz zyR$HVV!(n^j*qV&4()M=S5(GV1@q8HYDoyv=EvIZQoVe?tI2;(tAi|W?SUobu9o5D&+3U|UQEJqj@7|5 z^RL~4fgFdgbFHG3#yj8Nn1^hq;-BYS&(=gUd8BXXR#9nbyW8OpxP3Jn_g+3!TXHLG z-Qw1ovt_eAj(J1relxM8R32I?bMVBuh zFB$npg;cHSbha+CNS8)5Ro(lEwTBxYqx>bMM&fz1$cgD>8Tss=N0kH5U*7Iu4F)ku zVLe_2V+YDN2Ul!85AIpJ$^AwAOaAc82kx50=XLoN$qq+CCU?&X=%|>`F70K=RtQUa b)!XbC(*9ag^S;aq+wVj!2^F7Sm9YI^Xz-HE literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/draw_rectangle_act_disabled.png b/Z/src/nglwidgets/icons/png/draw_rectangle_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..7ed72056ee7ce141422db2a32fd99760109ca046 GIT binary patch literal 1362 zcmbVMZ%i9y7{5}b7D31~*+#PMau7pw?fofjxf?CCy>@h3Af-{ZndtTUmY%eC$Mvv< zL|`mSs#!w)uqC(|2-BGmqbymnWm5)(nCV=ipV*8u9hjKuGGuHS+Ua}`DDDH<2QRsM z-{*aw-|zW<@3l7XEi0)kK@g=?K=~MC;QGBuD_2L(_@4m}JrpY?YURd+iv< z&{Y++(}Ary)gEX?J(2=YtC=wIgpELLq?xqT+U@q;C`FJ2PEa^WnMgZhp%{Wd*B=a8 zQzB6&$okf8LCJx|R8?khJe5kBQx>zNbl@aS(;5dwnV^O#*(0i4+9W2c3Jfer@`@m< zf+V6EBNvvsRR;z=T?-*02Lc4TAsN*i<_i>X88+ z1WBn|;bA?ZRRu82-IEPziqIRTMG;_8xHv2E-3cJ7e%67(8*@a6Fh1JuBT0KLVW$XN z9ZAxZoABBQ%4cJ(EamkTI5xw2d^Ss+wbn*hXqF_sWSzz4c2P9xqFgSk-DN3Y{bEw( zL>?6E3efI4*7`&&<52*oN=itQ;)M=qjY+DMj7c);X|tjMju%8t*2=RMEejOk9T4#; zQUYDgFC%PXpP=iA$K$SJ-ENk2(=cW)Nn5ShIyUlua)v`^aIHBWYnH+h>_Bb1(fUx> z7#<+PiBaHayg}c*jv%^0KkEvme+)l-^r%5^(k*1q4H)9S7aY`pc%*2d4uW*3`?le;osjM3)I@Nkdg%E+bu=d+~-oe}MO<;eF& z!@)oD4@Oe8CI8Ibj>k)nF8f zCvwd5n(^l3r|t5smHg1hGxw@0PUyRys~y~0y|?(}j-AJxjRQKwJMv-Q*&$xi{&IeA LGyA#wt-*f*<2v5= literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/draw_spline.png b/Z/src/nglwidgets/icons/png/draw_spline.png new file mode 100755 index 0000000000000000000000000000000000000000..d629944291586ae93a24782bf0be2d964edbb076 GIT binary patch literal 1749 zcmbVNc~BE~6b=IdLQoD-p$IV`;2_CvLK2cDV9X)WhFgmn5SC98pmqvkgVB(%@(Ufg7sVK=KS2BPGMBN;Qu>cHwt2NvYtG zzh+1QsYU>&DZ_G6I3_ndR-T(7XDi5|AtbJzgA=G=3?k`OnQARZ&m&Lqa`3r%n@T24 znP3?_@_SKn(nyj3L17Yu0tCtdCO~3>6p$XoVzHKyXaERM0U8yg1%fONoyGwG()2^d zy`hQ}PP9-w?F(P=$Y~g+;ZUhMosOcTQxG(j3bNU3GY5?ph+70|bJQ554^(TtXBdRA zR*ot)m=aNw%#2Vnl8y1mxYG9_s5DaP2V%8$I#GDasCr041t|bkr837gWv#`c;g2#t zX|0XT(ZJMbSc_z%a{NA0yl238?mq9xY>2DjM4(FiQlLyBBF|RAYD^;Jk?|9XLaE@0 z*(@;#vVs5>4PXX?Ae*)V5HSIom?>lkX(I6q$EUC&h7bht9K#~-a zE7j&5^98++R|uoZ4X{FtA}Z2UhB?YlC=jq{3|ww74fq&2uA9jMSRgxy!6Hv%75^t| zR9pW{e!S-_B|?6zzGr05#;}+ukLHes zvikCBUU^lOpmn9Af2k-s&qw&WZHH~4kL`r_h{503KRL`#9th>n+qZD3?~(EAm*?3n zt=$iOf2_AB+tl5ct~I>w8Pz>GP`%se<;=HfEI-h1nhY5n(X}`1brd$YsM zFo|8P_(O+RTbY(Kg9A4AZ6adbE^}p8>n>dpB@molJ4YMG&mNZ@_@&hZ)}?Jh4;YvlG#i3QCyMRk+&^NtOmuPVQ|UQtiCxMfI& z8WQGI>&6}j9LIj{GVlamZ@&yl^}2Z$_FZBv;2$Bm`Ue%~j(MIsVQ~CBC5 zaX(r%&RcW2J*r|Cr1#nDly<3=d^>O9W5r0D=g##TiG%qSl#7!uZrE;mbKTToAKrg& z7}*oQD`VTD9j+#!$w;j+NM`Nxd{*B;Uq6%|g_NvaQnSEKYSjvcIgXzmNw~w?T6T3$ zt}O88x!i+~;<$$3`J-NRmtmiMyy3-$S5>ZMRehYqzgw2mkB(}8E3c&xZ;6u(E4fd5 ziK%};#?$w(N?Af>yWGEhL7U%1*Q%tRv)0>LwX!?CrI2HP{}D=&kr;VDH$vF?bm#5t zkXYA;9=o2gI)?KqL(da^@_U&1YM+)I-@n|~HcO1@RRwcuv03TcLcpP%h(pkch|Jse z@4U-8qIl1M zyRz*@E|O%Nt$R*sYBO;?wk>i@E}d)rav42;HF5t@r+~rB#NDZSKi;5+tCfYQusN8b zewb0n8^}ICf9Omos3|@f+c)y|&=24E*)DGC9I@eEdlp#Ql3x9Gy+I3F){wt@+7`~q ziq|@v+Wlg<@*Mi@){>=QZ2cuYx8V?kT*8*q|7!0{{;~U5>dGD)QY71 Fe*rd1rvm^0 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/draw_spline_disabled.png b/Z/src/nglwidgets/icons/png/draw_spline_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..8064ab1711a411f7dda3929cec5ab57120d994b8 GIT binary patch literal 1378 zcmbVMZA=?w96wrEkpW`F7YNStn8}vVdn)Z$lSQM+LNvxLBC+E30h!TdamFxej4_!nGjW-Q7oP))`#|==OYWZM z|2+TS@BemJ%Z>&e!nn< zzyjw)_M1a^NcQqEAuy=$ZG){*cCeSVb4bf>*pa3HL4sEqIGu=#Nh<9`R(UC~*N!m+ zUR6-Fv4!PYaAqL1RBQVfT%KQqnK9^2kn)LaL9GhXieyh*x_PKGBohAq$VKZ4gZqiP;Nw?c!ha1z;Con>}U|c~30mRd_~~l&B=diyaV-Nvf2LNiythGs7W<6+}(e%Ci0(xNw({CKV`dwqB>Y=H{9T#g6EGH+g< zEa}@>^Pc`z2>xy6tt}VIGRupJlE~G7=j6~G^DE>N@UwJbPFGNCvLhpPQ)Tm?uB5Ba zZVyzxGzCw(E78{KkKwJBiI&XL;nD8tN8pEt>UH{kL+$m)R%&NH>zzKnUve+A{s&R7 zsiCxDD7~{8?HsCm{xN^e51GZL(!l#$3KOo2_l=#*9_cIHddcvKtD!7^-qm2pAAg8{ zNA8f9ZZDaxeEYT`e{HNX6XxcRzI*MP=rj3k^v~$Ltc%RJE}kj=R) zIRD%qOJB}a?3jG@gyU+-hdJGMI=SXo=b@*{E}hZmZ(pfp%V#^!LZ|9-H-0h{vaZ(( z@!o@mo7u-(GG7@YmhgzfRayA{bZq+2xrNH`=XoeXaBdp3dQa0Z7f)_5c6? literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/eass_line.png b/Z/src/nglwidgets/icons/png/eass_line.png new file mode 100755 index 0000000000000000000000000000000000000000..199e8856f86e820c4fd21fc35ca300aba91c3b41 GIT binary patch literal 1553 zcmbVMZBWx@9M6VhPQ~puPlTbDMcwHRnwQeINMUW$YMn(^i`F+Jv?-*Jq$a@@5YK_A zod|Qsp=>&jEBLnIoeCS9BIp!{uRFKt4NyV3eeis#6CL81OOZN1cz#&!lIQt9&;R%P zzsH}JIy-7i>=*z5qRev$tF%rEy`v+gZ;w|yAT2SX(Jn6FT%wocDM07svMA8ZklB=# zBAo>*JE$Z8h;Y$1yJ)w}!yOzWBSSheALEhG0Fad8^N@~QN(8g0Y?{?VcMrEhAnnvb zixd{b;xSM;^qfMTT2Pp3a}?$}G)^cb8BFrw5&=VrBql*6ICizJcuDE0wWlVVhN}Umt#1BfFlniS>v59 z+)9{6Y)O(9$`M5m4#QrrSLT(=I6fOjH5yHb1H%#|jRc{96-i$LD@+YD5R~BHX^%*A zEEr-Wv$%Xw3rU_n4T14kEYFBpVI)yf%3vSqfl(O(GfXJ1VQoRQQvbQ}LT$lT;GtkE zC2;w?L#l^sY8Wi#?&XF;ijp_@e4dtyLgo>iBcGvI(M)I|=|<+How!M(GNGs{5m8}? zQjMY-Oph3q2xd|e3Ia2l!W=Kcst`h_)ELxiwN8nmMog_zt2G+APL7yNCe)}1W6i7} zlB|OY+odJDBUlOX5-e`uDN^Kk8^`5^J0LBG6FDJ=^MHm03eZA2Xf`B=%JVc@g5v2_ zl+(m>3^<%$oPL3QM5jick6UtsAPh!Am8d5O1(pbnV4eRbXRzc99BPi|nk9TBbzo@w zto0?~+3--TG%>t18bix>PXK^db!I|m^L1{&w89yui)*`gE@PdipMK-Lennrce(B1= z%67WLu&&x&_VuNc-|j7%TR-<&#b+BfF0A~e`SXW$vHFZ9gH;=LrJK|5+bXR3(Y>Qd z@8cc)-zk3YzH^=$*w$4eZ{1OI?cB22Z;e`LXV*+R)W}b~fPMm3>k4N5eaHS~L&~1a zFJ_KAzPa&~JG~+@Selk%>bpNFt^r=?22z5C>CWJ&} z+m@5Qc~1@;i@AJ&y3O?@W@M^do43|qP+W=VbZ=PP_vq?`-;!PLysdxG+FnDzx@tvBOJ{9NY2(%7vHJsWwgy)G zlzw5>%}irtB~!BO#Pub;LTM+~<|>+2wy6AJ2Y>nJP3i6NU3^?sQvk9|E&>~d*p|E9 zXO7V~lVY3mx9u9&dT`B?uIgJq_>1F@Z@D$L>&N^>LxJ+||AN;ZDSlU;w$FOldOza9 z*1i+P!Tcl6QKD5d$@Q z0{$ttvictfcD}yLd(i*>%|9QFkKG%c+MQBbMRm5jyQBXZg8)JG(DiTXPwx!FuRsH|~ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/eass_line_disabled.png b/Z/src/nglwidgets/icons/png/eass_line_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..e99f2554e49775cbee0a26688a2ee5fce3899c16 GIT binary patch literal 1616 zcmbVMeM}Q)81E*OA)=F+38>5MFgj80qo4FfVJ&R|waB0-%G4g$7dWB4(jN3sK}#cs z1sxOEbTTx~Os4{(WEsPc>E;x_fT)O~0VNYRzqTpJKyg>3ZcB`R?2^0peV_OF{hseD zNr;c}9~(SYAQ1S+#cC4yHPHROA>_Z^4&?y91hLu_Hi=1R9i$BiR3;`3KyhX=10({{ zl%LZKA_RglnY1B=P0`OMD8`JCZXJX(TY0oV5D~>$Nh%AlP#VafElT)7(@_|rO-gu? zRFCPc(IAtKU1Wph(nApwhRt7IC?4ya|Q-*S+6~z$@HJjaWjcD81MDULrFV(gi@~r?( z1a>CZM)CDX5AlHc+`Zb6TaovMSYV_1qLA4dhRQVq3md0V!u$COe58Zv^o#R%dl!(B9qD`(U@4F!Er4fE|#fPA_cAzsZ>(AO6!{xY6t->W@l|q8cG+KBRYx+M~LwRRVcYFM+T|6Sb z2i@Bj&CefRj1REzGh^e27nE=9Ztn ztru;Xm6S6SBEy4AI=B83U)ol2VA)dma9~d3{3{h8q-MvY=1GfIlHI>3vhOtc7^lj36&xtFNS} zf;vAL%>nx#HBH~+eb$8e`HN&o6q*xTIuO z?YKhZ$%>-E8O_*DK$O=%?lzXyr<%=FUUSQDc_M6BB~JLNDzb@~U=&a=nw4?bWaM zoHbrNlhV0y;blk1C4;VOcF>=<<_vm?&owq|b1iXRPYq4|$$R15zO{Ye+YJx9F)qLq z@vPQ5G4z}Bw|X~m9sZWndVk;0c|N~FKKrluO5xm{!L!@8UaQ7Fojn*Zbxdl?JtY5+ z-!@eBOzW?|A-sFxHLQM3S2f%a;G7z}cKE7dRhP zclrbGWNaFWY%SP%rzYcI)8lTsO7<|g!8P8xCAIwh{3oqf_UBDYKEOhC?di~m+x)UG z_asf|2`{T1axDp6%`9(eOFQMaE8wK6L>_t~%3E8fMSLnh4tl(<67;nUgbmF6L6Gq7 U5iR4&^K<{>?r*8l(j literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/eass_polygon.png b/Z/src/nglwidgets/icons/png/eass_polygon.png new file mode 100755 index 0000000000000000000000000000000000000000..b88323d7632288ad73f35aa05422971f21200408 GIT binary patch literal 1707 zcmbVNYfuwc6po6BjwmW1Skxs7J}}Ad2C_*Y&?K8kpotKXm*5zZg+xd;BpVXYVxfRC z7Nu${&{0&BO0iZd;y`t@3Z>H4(h36d5|pBj6)BdAD0G8h{o(kdJF|Q5x%YhEdC%sC z$kyA>Su%%0q1a0TQ8~G~SYJC^@_Wb3dqysgJw+C5ef@UXIwGGfMQ0a zL8B)$xDK!~D&lYx!K0F%z6wFBmr7p~>x`3$B2&h&DD(`74l=Y_Yg`lBMnaDL=f+#L zjbW*Jj3LL2xXGX->k+?V3QXqi-G;1+q&M6R1`SyhMG}fDO2ZcrADUP>c5fJ6GI6@(t&1XT72xcQ}HiyIHGeNOf z42gWEuo9h-Q0SD{lwA#JcM>ajCzdNTUWJ(>>-Kf)lfvua!F1%r7|79(Z>{O1P^Py_P=1)@_UX?O1H<@^^#ix5Hhc%W zjI#@D5~B(u_m{dhIG2`{m8}%a4_#TZ%W32!nD2iuMwrS^e!%F~Bp&v#@j@9!!!jxqZ?3ag#>)t3~u4`y5he|GFpCs&3imaE;z zxc2)(r`NPjPk3B(RF>aeyeKHVPrvjJcddt@He2YlE;_&Y(S68oq`=fj849tD&Bz)` zJ7-qVgD`&Ws-EO4bLU=Ly({Nd6AP(Y&}-QKZB@a``@y!W?v`x*m^hW4_;lCvUw~1Q z*v->+@Ac82D(4{|()>QZ;&cSd9@$pc+cIlVyS^r7ZMuswdZZ<|xX!#7GnED`ZvV6` z_Rh@<_Ds9xpjKP>0quqV7tCwpYfIgzF2yf5AOB?d+WvTY(}?Yzr-%KI*>+{xI6q$$ z;c;eG1-1tc+-|z>>3M9`mjS=I)fOC77FBe6wS_(l&PDM9=FFz>`sgj`{A9fA{XPJljHw!BY`)YH~DZ8$?op4}khNFl! zQFmu(R`q;cb?EwE(@irM)<dv%{!Dod|^q72XDG=(3OJ2wVg2y=ZYJKI>*g4TYO zba8yq*>dy9a>t$J1&xPBWx+Cl_E%Nxybbn_WkYf#{Xs%qkhyL7G+W9H_j5Ot4^p(& O--kpbL(d4dX8sG2nw2O3 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/eass_polygon_disabled.png b/Z/src/nglwidgets/icons/png/eass_polygon_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..ee1869e6e5f482b4f9798002fd42fdd8a5752a20 GIT binary patch literal 1681 zcmbVNdrT8|9Pc*55C@7+P@KmhFva%n`a0TBwWXAoz`8Ap523hmYFVGC+dP$r5R zacqvsgh@aVLBt{A6yzbW3`HXv&@ziU(Kv^SlOW=*JlvKT|JWsWzu)is`+h#(cP=M9 zG{C`rfjxu4a0m*NM$)UZ^|iC5zjuwIVR~_){1sFbkw_Ua5@(22L;?;3X|W_c630|& z8#{1c2ICX8CR#x$7@FPeZ;IUw)66V7IA7LRJE{dYd0XB@l5X^=UHWNXG9JUaKfyoD?t&yrk zVWdd@=|l)xyyhX_1*UWNVMA6$+8bdQsiBL4rAP^7sutH#K~fP&->_5~l~5)?We9?D zVU!K?eGo*zmcagem@VT=c~Z8&Y>MN3SP8=A^H3fPa|BWZ@ke|(e2JJXK*VgZn1_lv zQ`jJ#fx>i3e9EqdwmX64%07q{`jI$B5o9z$q)c@{xSF5{gPPC-eo;IY0?09?MrV~+ z3p5e06el&CaFvWCw7__Vg_`$xAVdEfxetoSBw~ci5ev8oU+ND|VpabqYY^=WWNnXs zwab)6}=ANHC54s;1935?P zTsQqj=B}_=8JiKHHnCw#LqL()bY(|e`<~fG=XEn}(62*2U%gG>IzOMwd0jJ;drCHx z+LU@vuxJA|Cv#9if(bS8^9q``CQE9Z|9aE5x@vgu!kf3GL)zAJmhuRD@1aJA{=U|4 za)alzXWx=XfgDvuI;TWovQ8^{#_vuA{lwP*lD_WV&>`q)}0_@1}=Z z&T;Gz476XpUE#fyeP-m^P{HNC{oh`%Z7ht=Il9!N-mBhoO}8qsB1w@xpUW)B}erC6X-zoomk}JUP9vxbj$h(hQ<#v-(i1_t(v(gG^9Pd|8&;tZ1*<5 zPdmq23Ofw*4{s}rY`FKJ^@seHjv9+C<`~@mUGCnT`X?iWSug8C2PH2%cIR27{Vl;K z*8{iOoD#}nM~^z)IH?)gbjZe7W$vB@<&1$YU+oV+9Jr-p;f_DXvI5BP`@Q+Z^O*}C zm+u?Nt&UWB2QN(?II^}fccYixZS%$LA7A4ZtcmCJK3}Q!UB5M@^#tBCt))JF5oziz m?(=~bIq>r5=b7;g8)wFnpX0HuPgWVNKZzj!P-&$kKJ#zM@Qxh- literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/edit_element_act.png b/Z/src/nglwidgets/icons/png/edit_element_act.png new file mode 100755 index 0000000000000000000000000000000000000000..dc377c10819e8af78e3cd52320294adf6e8623b5 GIT binary patch literal 1676 zcmbVNX;2eq7+yfs>R25V1f9xG#PPuF1<8^?3?U&U#UMgZunZcK4Ot=CuvwZQjzGLy zt5Zv*RI626try7AL2669he#Rih_zY}Y!#$-go15A2elUkEYFkm*3LmEY#-t%@2NNPo# z)jTDlG)W0PnXrK-Qa2>2G#hd?0xd_p42-b~SpoyWs6neC&uA7}MVv8SAv^bM!yItT zgvk|gUWiIpCWBInCO{s9a5V@Y0r@C|MnvK`z7)g|6oC;8Mlmjm3nMTgf`H=>hxJBl zb;1;xeB2ki5^?klV-mu!#bSXh5fDY^z^FhV@Ni%lm$l%U3yqB0$~Btjdl_VeSwoX1 zhNO(3hf$qP6)++WtMo+(29r|xlGtb-PZXOn*s3nU>O2{xDKHR5Mj;b%*b_)gYK3wEE=N&3 z62UQqABCa^IG)+3j|R1P8)M zKuS|nQ$o!H_tPHt_H+P^ot?0FUFxJO(@O@IoCqrUK{w>=4fUJ3rRt{pSkcUFJ?>Gr z;F~`f=XKldk4xHShYbOGezV=}?)2?$JR~vuUhbGXK;1b|DX!nDx_mKc#69UxpUlo) z@ht!8{FwEAa~cC5-#(?idQluXb#!$2gCiGO+rzp}3^l(Sd)e;W;B-`%ym9w-acSO+ zO?3mL(`gYyc1_Xo;98_6?c(zLa~7RRsPQkB1cAeyy=%7>oeFIYZH{ReOc>eulZCp! zw($nD8d@)zkg>0%Ws@aqRJ=&wQ(C!lf0k&+w*E&$s=-S!dm1v|KR550{nvLK(gopH zqf(aoRJ8PU?OOV?@7ITEgx?lG+(+uAyUXLCVK@AJx@_+Puy&x?TN!x7u$k z+_Uf?S?K<|{ZX`=a`-3xmAk4=b#}qE08`lJOP|LYHx7pA9VfmV;Pz(O&zpujxD6$a z#+E5T{a|8QUypx9%a((Y`D^Ij=AE@Y<@Y4}+MZkdw2JVX0dpf0KRvurmtK<-cO%n! z;V2xN2x+s(V(0I!txxP#*9Vo)jGy4;n=^cuW;?wZe{OI?mlaDMbsfqrc5WPURXiB&K7RomntCm2YIH#9?wsvKSb1R4Xgh4#5w27K*wZtW zine_R8tRv|U)ld-Fih!&s(u^Te?XWq>9aLwd;HU?%O$#_t@c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+0D?=0vPlL#+ELIhOUMd#%4~A zMwW(-MvjiA=8ncNy`Fi+C5d^-sW5vpf%Zc6n&H)JEew$TZQ#&rIbo&`bc{YIaUdlYm=G`pf|&5659GizPih`8#}omxhQTSjas~z_ zZci7-kcwMdrk(bd4iq^y`L?!~{0k>l)hS{kLTs@bi<+D!PPtifajim=Q}|tuUE+V3 zMgBL0wdj;6c5s_J6|l61)$rVK6%!K?JgR;(^8L<>?^)!xmldcn7e6>&d*@K0uZ?WuIQ;h*u3u;9OGdO4jD{sI#>I{HgmS?^!No$p|{uxHbU zKYfA^n7A$6)zcUHM0igyGCCl`vv2MCxd$?s#Ul<_TG;5_Zuxp-Yhd}A{rkMtmR0tB z6nV{4(8xN+{&#z45l=+4#!@*mse9`6GuSumJMbAKRrK@j-UDiDbf;WQS?^(9x8uM} zu&DLVyAEoruB5o`W1oGw_XLYtml>nc!aLXe>>kc{bYSkg_RM7VjkeCu*{{nF-ERna zu&i{8*}|ApY_k(Gqm$$I_|u7fY!7?mgi9jq7)E`oRnvqlJdojJ|r=DlEG2 z{qJ-CyR3iget+RJey_B03tz6m_8HO#41V5;Rk2<7!ohI&hAaIKci%77-O3lf=$?L= ynDe)r=Chv3y?Al&Nzwy40+ zjZI}kv$@R4#6*+LFJxwBI3vZOLB+3S65SSq7(dXV5VinHp}Qh={$c!MZ*uoO?|aYh z_k7>xtjr~{NwX#a03fq0C2Zn8Bl5gDL44oz>juSbreMkyvY7(GPjWP1pqP9bw0Oxv z+D4O9=?CZNbO4AcaNBc*TJ23*Ku_Ax=g!kU9n3`LHb2tdH@#*ytF`q0k6l$;{hEs%8QF~dg23W1?DzW>{!|6S6~d@itBr7Am|WD5^QAt449Irs#x1&g_RxuJ-n=ncMtbBjeGJp|(_@zOrQLg*mzi-K}fxLK<!<`^$HnqS=g0{e(TgFGL%7y>~UO@ulvgCLYx8Z?Hb{!h+e(HS_>9M3gN^h)f& zi1@7a#ly4Vp?%`SaN=mlxE)RakmxLg!5;V{pK>~#GL&tBa@#DlnhK+mckyj%OtkdKjby{_OxEq zOTU!F7c5R09IB~Y1$a(%1S^)vo0(H}!HS~pO?u;niPhEB@r$=i`TC&a?Hdypx2$YG zeD$#MQ2Xu5Zl(S2Q#EyAhvY4CP28NJn^n#Ij_P0_9C|!d^XB}n_3PD_moJlspA3h; z*i)O(wsUT*Hu2|-$vqoRCiV@46DH8_?WmiU^xF!@NQdmwiAkug&1ObfoF3AUnf0jK6m+6`Ao$C<&js|DA)^7f!o=%uyaQ>8rYJ>Aj)W2gQefLZqL> z#S*hF{Q{q3oV$u|ly{yf-CoDGRMa=Mm&P6JoSO$6-L&)L&98X|6F%+KJ3{Z4eRpqM zW{c$*AZ;oe>c87@q+&&RaH#D5$iCL$LFvSC9|AGJ_xm&VIxaoXM1If~QzlWL;oSHy D2@X`# literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/edith_graphic_eass_disabled.png b/Z/src/nglwidgets/icons/png/edith_graphic_eass_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..123f669e6db0fdbaa260d00d45169fde417d2019 GIT binary patch literal 1237 zcmbVMZD`zN9FLuAyWP$Ws?wE#ArnE}C3$kaOA~tAjruX!uH7_(}`a;KPdWPU-r@!>^@Wwl`$9tryC+7sH-5%&8R!JS<@F$@c4`o%0-JN>u46@9-g$5zp@*G=W!5p&cn%QnOW)ht3h zqswD33uSeBavAnw*tU|E%e#4LkXKBdlzko2(=CL?u--$SB`f35#fxxEGh)Oqm#z}H zrpAcF5s8+pBrIwDGd3KV8OkX$;|iw|hYsSs9*+og=*qaKPZ$pG#fWuY9_@WGMd0fy z?s$yYa4Ihi<4Mzoc!Z=w3LT~KC?G+&n`PMpI70)Pq8SP>A;9ushNo$~@es(Gt&Z|p zG2O6*PBEh7x)x7S<#L%Uhe^{OqX5ToJ_o~ukVeRvHeA^Y8P5JDg9shP)+|>u4cupx zi{_LYBao*XA?TJQZ4w(!BT*=2lqXvhAZbe1{kYb(9XAXAabrtuCpT?DDhnNR%2rT4 zM)x!2|5*} znRHZ)h)gQoi5kN}rtMKgSfU!aY6MQCeBp_;Z$9beBduWjK$ zn*DF&JuFBk1kfE8xNZ;?Q$z!+{-3N-$QjCSkAJmGQ-pfZ-)=TPI&6*)G|S*|9-LkKLn;IoDs`a{I9RC- z6au#^t70MW!oqalNFZPPtM+O9nZ;lK-2Gwby$ic%*J`oHD|m3}V*K)nw#2oPU4k2|zB7Ni<8y0Ie(;0s=Z@X%sQ&&*=K@x}eq{F4 zV{L8oH`}VI$;a@al;QMjX5GgtY6m!o9b=fY%T9Egzp-dTw#>jXPGLwpQ;O*mI@zZeRSB heN|`2ldbJEcJcbPj@v(djebEGmPrkXA0=Ko{x{I!pP&E$ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/fast_playback.png b/Z/src/nglwidgets/icons/png/fast_playback.png new file mode 100755 index 0000000000000000000000000000000000000000..e6a7576b5292ad43e5680af71faa9a2021c56540 GIT binary patch literal 1826 zcmbVNX;2eq7!D!@p`dj@0gEn6@>rliCL2#yuAjp(M#H&T2%E+L#8x-pg#~Y)V3;e3SQ#agMDXRLnu(comS9S!HQfQLQb>x_r;u78G=>dGFgc+y z$)@tWi5A6mL^PYdsc2iMROqoYUThfe9I^u$TS(coA^TcI5yh8xrTqQ@L_$n zO}%1Y0&#EuF2A`4JLYtt1qJ@Do>n)`&vua2D?BR$K(EVS?%@lpP2Dr1%a7hg%8OQR zT@>Nd>=fqW($||w-jBSCv=6>$vbk?ZzBo8}{dMoU5#xA)^i-*GXQ%P@9j6>0C@IxW zJoLr9#S2PsfavHMEFBrNf8nyR8B1zbOXt}4FZsuHSwe~90>|0c%j0CtN6mlJxQ&%O zx}CE8%E+mQ7OI|FBUD`;*_y_&TV&a+g_8Bqk(tJoIpd8-qxxHq3vox8M-}T3^jTu= z=Z2zdXH{hz#w)jlh%L54=S$27Jo3d|t}X4eJXOY`M245Lx(v6_7R(F|nvobJa|;`2 zYVG)Ab`kE>(v;g@e@E5?R#}|35oRB|*;uFSi&)un<@Ps9PLZUIAgnH475bfRI1Sb= z3B2;!pBuQQ*!s%N*WD9k;@W7Ztj4jVz0YA!ou19quVX_Iy3I ztgmwaWEQ!5#_+j{&MjYp{J!D!VEZdws{AXj6W;jh?b2)u)!JRPn-X}|V@|vqqx`x@ zu_7^8cXjRW7b50ck1mQ@yKb*EfA49zSA$*Y!od?ao6&~_K}0cpIL6J=Z{UFAnRw?1 zPY(aR`{k^YZIR`+87t2Gc;jikpghqN9BZ5ZYT*gbYP;a=Cr&#pbq}!TCb8o-Jza0J zobO(g?Qu|C7Vj;49xaJ6CgxVo?H={aDto>fmkJg0S9bI^kN*-G_ZRqU-iA`M0jzVe zWTSFNhQ}qtB@DX`-nq3kRd+mP!B5HAcCz(DeekWNfIGBB+9kNZwKa8ulOxYFV^_s( z&aWMJ`gVQQj_)jY_F<#EYw3(oo)Dk7SC~3-DPlPOB5oN!gN->X>B%a$(vJo9+Nv7E z%O5`e-g{Zgq_}8uE&R%xs4CPptUF1Dw;)W@%edSmoi4 zY##xWj4smNbu02l0$raB)VLPqw=3%Gkq41a4wbsd z>cVqfT%E=EjeT4&F*uF0yw b8iqOJ)~IG-x6tdP>8}+oj6{!zByIQ?I_kt~ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/fast_playback_backward.png b/Z/src/nglwidgets/icons/png/fast_playback_backward.png new file mode 100755 index 0000000000000000000000000000000000000000..7776327a4240c7fe5bc1472bbc08ab576e6cf4ec GIT binary patch literal 1102 zcmV-U1hM;xP)Gr3=U@MR{=(0b767qCY*lGq z`Pnm7O=gT^>k1H&4#3%d-1G1&C+_!^Y&Z7*F*JPvW0z{Od>w3wDXZF-R-{?M?n>p`ca~8@p60w;X8Tx(a-m0nhK9%ovq|cRbY!)&W zNn8UW%B|UxU-4dNrMIR+Ka?WI9A;zz03fAYlNTb&eWWJ8^4-qLW7TDPgH?>#S6EhZ ztpE{O0XRF`OZWP`MJ+pAp}j&~(@irHXIRDSY9%7qn;m73HhT+Ow&w?HNsd`eGa6^5 zQvV7NQI_3q^PGLX^58Rdj;8Fi*_LqD3pr$To7?D6? zmL&*4W_MRreZymUCtZ$(YM4_NR?&nG05BiSx+L_SGAI472iTm_SlwCl73&{TKUe_B zIsbexaPvmcZi`AysCAESB(xYZ)j%v&3oDJFt;b5q(3sgc@bsy_e;HW1a*q=sryXuh za5^hSqIGpL)_3l+rSEbwr9aP3Zb6)ujJ@txg8~4U**`d9_I11;_~!ig;ZJ7gV*REx zk!Ue13Wv8$w7s*?+xuhaQ~$hiF&P_^tBxr%2Z-pmkG=}eT%I&W+McsE@4Q#k34(1+ z*e1c6YFP@0G1&8EcxHG^8*V*p^%ZUtPYMC+YL?|~&5oI40H%m2(tpVabhT;Y)#c)_ zEd}nl0Mp8&!OW9H6dC%{SUly^#;Z!jvoO0e5mxs&X7&?NUuTcG*x|KIG(JH`bF!&oc`u2;>Xd!)t(v(qp+;MeXfG8NP`#3O zcIXxM<6d)SbP6NBMy+{=o9dJl>(2vbHUUf%QFQpK40IkB*DN~pBy2pr14AW6zjU?P7&J3&7iT~z{${c6cfR(K9xbc-98tD;Zxut@Hz{hXz;VsxgxL{ z``#^J3JjtsH9yv%Ua!yOa%YxIcqwpcKVb&P((@w?n$6bvnd2u*&ie;I?qGKKTTkML z47Rp*u3EsVDf2y;8q5!lO%lIv&}cM{YA;wei(epeaa3o2I;7=8fZFEf1?llzMD78n z#undm$i&OnZ{M#0uYj9?OfC+<1`wy^Lsjq0tYc<95lNm4!y#x|Ud)V7)#}+Jarg|8 zN5JXH^;z?xZ_@Gsz+67R-8?Z}-tBfvUDaAwm2u&m%f!pzy8f{7IZwa}aGOzcVyqRe z&z95jL))})W40Q1++(M@uBt7k%7O4M6F+iYFD%S$cYo}Zow|~$uc>B@`+`%M1v4g%Ul}hx>PcIs= oyMMQscyRiBYJc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC$&`;L7KM!bjU4{B8IDfANSJW1);dy-EUO zR~2Jj+?rRC@%!q&%Xj~%Rp?`T^w=eWAzWWgsbk^1k0&=z|6jO6M1*Ck!yWe))`G8> zCM9XSl6-Gh@oB!pjQm!%o7PNX3s!_rn$EU5eNWx*d-X~|=ae%h$SNLU+EK+TdQ@4* zzW%S8+Wr%a9~l+aDH_!`UX9;Vwz}=9c%j&VLqE7VXG*M@7s2fysV&l>&+suN>1y; o7-p-yB1!I6snJ?p1`Y#;YX>=}&Tn6Q3RIqXy85}Sb4q9e01lPU)c^nh literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/fill_colour_act.png b/Z/src/nglwidgets/icons/png/fill_colour_act.png new file mode 100755 index 0000000000000000000000000000000000000000..9282c68f6a4bb591e5a937f7746af92e83611695 GIT binary patch literal 1303 zcmbVMZEO=|9KSI(5m>}!Ss3`?yn(@l_TJiF?_Axkz1CIfs9nh#KUi*e&$e^D7w&Fr zw0%&V~p`7Q-~V|x5z>ySr&|l(M3%qq7uTUL!aB);fI9}UUK)m z{eQpz@Bi}L!FbDkRckk`MG&Ma+AJjCxY2pnRKoAYY~UIk>g;gJZq+;NtY`v+m-Tjl zMpdyBB!DRQ?U?`#2vXjqBvW=Owu6&&)h#+U?wo2sG=elV<_uBl1~%FbIu$K|{Wf|M zLlrrIwRvMi%m{%lrMce(t^F-YslQudWvuaDv?0eq0u|UIno~2H#pMFnA}G4gWgQJ zgG&gJqA$1#U|qIta5$dLX5CrZt(%=V$+E1&K~XMf;j;QPTgh_0826z!&Y<+ zbr{8Vy~hq42(eu}seIn?cA2!>=mUIr^-<^Pj49E!o6_V`b`l(t|GI@9Imhl}Ow12lMN zOn5o6m+m}*AZ6jGz$bI(KY0GL`^)(a1D((2+fujoW6gi8>V5msve(9@$1aQow`W!t zK7C5PT#-2cV@1uD)yKd3ZsFH6Lv--ez~)2WezPCE;5wmqR%%lOeQIcGe)rIXT$r4E z=;Gcl`-e~Oyl0<#^rPVd|4HkW&@ZFA=FNS7=eC}%;(c`bvGt_b)LDP=QQxlfHm-@Z!?9A2|6Nf^>FFp9P@WbHK zlYiBHQ8#Djt!1jQE?MTGh|sYf3uB3dy%X4|BCC>~tco%v_}@B80-q^on& zlBQKn48ttRZdUSiZ3*7Sh4lNfBu~+0B~g1ww=+menunRB;S6AqwX`9e$C@#=`#x@G zn9!hE=pjA1Et2k75iQV(lr5K{8Kyl^b~Swj6EJ{>Oj~9@T))8r(~#M1LJsEKG#)lL zk9)X#ytAN>kLaSoCOSZSS)v3MCK@PPqqZ-VWpOW5Kiv8Ijo;r+RW-AnkY< z2oV_8VGM#8ilAs~JRaWwc!(eec@FVm6qlmB1RW9;(aK@lUt4ETu&;ZjOH9WG0i!nH6p74IPiI1~++1#! z*!F9QqABCbn#-XG=XknXV6`7?s5yLd3j2O=#6mNxb9>&@b68RKVW023p6hYzDOr2vcY&s+G zf~q1I6%~Y3)E14UlDvqLd@?D-lhHahYx_jAbzHY=QoA)Q{3ljQdsrimS8$xsdIxk3 zJH+va9T%j#1(4Hp(+=dIJTuWM*faNFBjY(1n9i?c&S4*lZSe27+muvFK`D{OtRhhm z*c#UOpPX^j87^p!znZ0fL_09p&bB@kW`_scbYeU@8V9zozDdXGY*tAY$}a}0zkVe` z;d#qK$L3vY*s*UavHatnQ~QtJOMd?Pp>OHkro+Yc?q>`-?o3QfG`_wB9#p@5U!gn? z?cUhXT&OgjX;|FST>bgu&@S!K!#kNBi~5<{mA)H$pFFGdwO)C-?tOSlcoUj`yn14? zqvg~6lV4UIn^bR~PPATSdVAL_cukt#hTb(-e|#;;=P#eB+cIoSZy>97Di>4zmEWm~c?AFf literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/folder_open.png b/Z/src/nglwidgets/icons/png/folder_open.png new file mode 100755 index 0000000000000000000000000000000000000000..81e97908f7f67091e0b5536366a06e72c5d83479 GIT binary patch literal 681 zcmV;a0#^NrP)VgU;pUwg|Ezie+;#dK_n7p=P19iO{t^9TUTSxe6G5oMZg| z`vC(w*4C0U`Spk6(a}@SuLITpAl3)$K&%D|79P%@tV>s&X=Px*9xsfH#~J0NW%z+i zTRdhyfco$sEX;KeZV0NfGL?w<|K}x;`p zk4^u7J)lmiVOL?`P}<@LWbOjupI{5VTv6QwcfsMWeYfuYejz5z%uB8%yh8dy(-vGg zb>P_3Bj8l@_b((^K79Ij?eh<@Ke=fNT@3$zQREXl3wwVFy=8GI7F@r}e9Tl|(B{|Y z^Arcww=WzYK@knM;LqPbV8J8jm~Q3jy^DeIDFM%3{=NyMK0wSGX_wyM0Ne zM(}{Z*1d0^0;$g+3;zH4^Y`!b*Q}qJ|G$*{`;YSA`TG6;-8&Dyya6(QgDiOe>doKN zrUpV9e}289itAs$*WX`{IsX5rjs<&;d;zB*5Ss~z-)-3W^7iL1zwiG0_m6>6 zeBt`Pxu-9Fya+1jkgH53Xf?@A1rLD2{~jnYfi0kQrO(7bV?c8Y00ImEpLsbuUXjgc P00000NkvXXu0mjf5f)5! literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/kosy_audio_control_act.png b/Z/src/nglwidgets/icons/png/kosy_audio_control_act.png new file mode 100755 index 0000000000000000000000000000000000000000..b94bcb5a4b1cd019e06c57252f94aa6a582bdbaa GIT binary patch literal 1958 zcmbVNX;c$u6pbLb99e7?0~Q=ZRVOie4kenk!LWJo+2izSl=1V?ES6_$ho;Tj|bRiKE6=Tlo@GCk%}=b5C|}eDFO{jB7jk|SWAeFFyk$+n3~(RSq$K<37G~n z-ieBr#{j_?jsiR;=&uC%Ai#&15Qi%e2>bvx2!Sk+&4SqekU-2~i$M?=co>v7T$L9jkWg>wLf&^Sp zzy|q32okY_zz{yjmhq)LDLX_q$nha;2#*`Y0l7gSMNWzv#cmfG$ z5F4%~NJOhd2mPukzXMpwN3r5y97RYBkHfIVgB1{yijf$Ris^vhSRNAs8Gx_`dLaK=8Wa%RJ4brRm2YoR`05q}6uI@Sl!Gfw2KFdiH& za$4})>`ekj0-DW0$n!vm}LQ>P|)f-}}EFRWhU^u;E4K+%-_v{Cd@7>q5nJ zG-dKysk7G0#G{{cd@#$~bJ%f)_hI^^ zluNg+?$0lumGAoMhmCf+$Ro~vXes(OC?7;oau4qwj=-449Voo;yb z#e(6QdHwv&(IyW?%lB=~{JhpROEWi?lV#oc%dLmvLdtJ%O00D`W12e_&32S0RlMGG z)H`RVHLuKvsmOoy(7vqtiLukg%i2y>UbMR@+ih2v)!Yb&c@B?${lN9rO8iML)F?QU6`XU``_uccXYSB(Ai!mnAUkdQqSbhvRpYFBBYUmv#}8?v$CCU=M6LVDSa zU)kU#rVl@FtHU#{d{~#E{gQUcC(We^Lvz}RJ^BfETBf%B_-I_w~+;Y3WaaZw+mVzt?I_>4Rykm^5?Y_1@XLv}o Jv?3^R#XplI3ylB( literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/kosy_audio_control_act_disabled.png b/Z/src/nglwidgets/icons/png/kosy_audio_control_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..7631455e93ed500e223795c838b34725c5dd957e GIT binary patch literal 1756 zcmbVNeM}Q)7_ZbgM36agfG8XV6$owb`ax--u$F73Vi}YgaUxRMqjb<-X%Aaa9D@mh z0)_~VA&nZ9iNhhH;*0~#0zrsKl_8*rOabLXHWd}Wc13XhVfyh9w2gY;vX+su8+#Al7T@MLUf1>Lv>OVO`hw3h(r`a^@*q!2#I0>Vwqf} zvB;M4yo(k_bgFHLLa0O4z)XHQs*l(Q+5X^%ar?u3J`C~Mc+3Kb&18~hv5NnbGb-*3 z)zTavG|Su(-hr0w`_{*W_rrr|@QKmkqrq&8H{la!D}s4aV{cu_oiK+;hZbeRTEj-W zGq#?P=lnbyTTiQu&^AF`9UL;^ex!28gTpPcFCA+gw|jZfe3nS~)lb}izV@)`NF(3o z`V}|P#fgbq0Rb5u#z$jgWA!$78ILPa4dgb-xyO;-nPux<7ZqL4T(S2v z26?FB#>kpogq>ccUDm5vKRNE5w>aHtc*F0`o?o>7(qU#)TMrU%<{s#Z@&19&`zP{y znImHLS}n{>OeP0pRz2m#)Y9u}t;VdF11qDweSB*QCZkCG&Y9zTmJW10ywhICIJ;~x z??(0h`*slvtD1P==`+Tb{RcCtSB| zuJ`$^;0=R5V4WPUhDt6E;rKk%-t{#B1Lo3o7 zzG9vGyipWzXXpPQv<8)5Iaibl~BMsH5ToF2_e# znx49+NFx^5$2>(df7Ea{xt%9!O^f$cjm(%)hyOy=qYbSzSr^ZdN+21CG>(E|wFR`}f`M!{W z&KHHH&d=_pFF5}8Sdln`xTGgBHgI^vhQOj=75UTst$i9OhS^om=gQ$Z5 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/kosy_radio_error_act.png b/Z/src/nglwidgets/icons/png/kosy_radio_error_act.png new file mode 100755 index 0000000000000000000000000000000000000000..02a3e7c2d0946c4248f14b23604a584520d0c91b GIT binary patch literal 2473 zcmbVOXH*mE8V)5QMFGJTK`=%UR7is)B-D@)4HyVbIugP_VjzjhK!Va$6kHKeks?^v zvMg1_f*`D15EMj2K@sI*!-Dh{_u`$Xxc7%=f804|=4B81@pf)T@x0=xirMEv#^zzzme z;qrX^L4W3EGDjGLVk>M=vKSGBhQaI{Wg<3*4}gepAc`ljM-JEALLzt(_DDZG6T=iy z0WNRT4l&@p!`+9ogU=yFARQeLb}}+V5Ced0ge)dnAR)`_kzaYq&|I;NMk2nNfP8!8 zH&Omf7J@1i0|-0{W68k~FbDz`g|)IK5{VWF90rR)V{m9J&Js%`Tj9tU4C4EPguIC( zBFSDf`gdQ@${xuDK@k~^mP(~4sTE2njzVKeB$9#yhqHt%EG6**kS((mNLJ4?&;SWX z%oBk;p#Y&^WQPl5L3<>m^jioqA|~?(u|V=YQBcazGPVefMPbk}F^agpT1!AL;BOf} zwU+qAivYA2AQ8rjIZ!i?-2Jm7g(0Md>>=hsMPWzNgq+wIKmamm_DJXi6~T)j z(@8`+7E83o5OElS4HiqnIb&Q17#y8I!_#ms^m&e-VO{Xn&Q=&}I>w4b!(v^qHdX{@ z3XX)O;3yP4kzzHEWe6l7TfhP4{qi8c-?1+Lh$U0S02>sFeT2g3`3_)lg`iNv6^am4 zZ#)W%V6r(pfnrBdpl|Wg05LBPh@gvwF^I1jCi8xxfJ(&SA-Og<%-@kix(P%K5lgbh z6OrGs5&uut(2y9kqCNhnUFNr-9#l+!G(WWXaeV**bZ5lSV z8^76Sg@l`@!2zFseP zAhnXqKeeUv@qSq5<23L!our`}z!Io#$qMO79G9zm?J`MiM(&&f(B|wyssy&#;JX%O@Fu>b!9oOGfSJyDNQWM`jn%Ef~;+J!A3{jDaYBMm0mv$!#xeuAwXtZ21rNHsFaNVp=WYCSr8bY(wR4#ui+f(lbniU`G0x#s2}Af1=mwZ*(uft)sTMWj-|7?Eq%dj z4!x~g^ttC5>)+Q_F|reLgxrevU?-M9L_ zd&bu4oCb&UFt`ES5k_q}-TQb+C1x)4!TW=+9y1&4Y+FW}R$V&jbZ}|zDnVVMn+2Sr ztodRi%+jtt-owS8eXO#eYY#PK#lZ)I&NfJu4$gJlr(Ax=E9GB zj*1>-KAX#$tgEggFn3(M-DY%k;=JFLM#3)7q1~g;pKg9xiM8zgbNdSKvu`}?b%LZj zqvMX|7h4!AT{LE>E(tG1mbn&O?lhfZWetS6d51ihLI%ukJ{eN-p5|mZnSN)AZ(_8K zF!Zu6dRtWT^W4(ASN2y7HRheUs5D`A;aAndd!tq=mvY7Vz`cv*Y2wVx4fj9&Mf20~ z9hk}O=@X~RoLh~L7M#_FGgkW^NDmqf%8$H^S9TL0vq_?;IzNqo|8c0$WSybso8)D4 z4VA%@Jab2;`>s7Ddls1NOC?T*dd97rO_9r=qC3{QbzZB&wi}j9I-yOYmxAnfqfAqU`W+U1)>$2YDPa=-JDmK-KNoh>GWR|~loZQlOp8R3XSZSDA zcpF(brv5fTyNE6??tPeNQNBG3rOpr`@(dotzF+eRwM44+F3*)4sZ;JTHSvLWVnx;1 zRiyf`ZiXz>{9F>LN@baIjd5D2(cHC=-@OmB)*lI5$7vB4jA)vdC0`9Vet7B0@E%Vr z-yo{fyY^4R&Op$h1U`H86#jm#v*QYzlz@))W6y>Nsl!s;Eq3o!JE(+%?Pl5xJnLV( z^Y>OXU6-12A6SgC=KN$sz7K!PC{vfD7eBfjR2mw3Uaw<3P>DV`aas!jMoc^7H$AELILvHhHD?-W7;RNOV|hhK z>qg}!J=Hb#qjP=xeY2%VS7b?A2!^O<<7o`fE)1D5(Mn4=sWOu8@#<};?X3J!73&N; zhaC{N*uodA=zoIqe8Q|xU4Lug>oem!;IzH!_WfFeaQp;5c67Q}V`tg%(_nX*{{B66 zk>+`R+9s)oeGeT7Irll-u)(fT9?;>hm-xaC%rA0|#Qza!O8{DpKR_`}`Sm>~%AgDB>3p+H2wA3NvFeBb+h@AJI(bLNLBe5zw@efX2f!jp zQhY1S!r^oyq(LEQh`@&_Mr0(BR)?gP#bIb1j^(b76NzJBln@R_O66=|y!sA6kV@FV zPO1PD#CgI|(k*)xaNu6wAo1Q9F+&2lyAfDwCPpBGQ4v8ci{25d}=3l0c#uq=5t)M1q`M=ybXhfdWDx8KjUQ3K60+oheKZBz$-P z%$hZvQB+F#lxZY_i(E#`l zH$JJY3`&ZF$pNquNl=KfdPJ;W0%N)RYeQN^%p2x*g%m4_D3*(e6J)R)_2#kx?1m(f zN|<~Goex2D7m!W?X|52&pm=~h8c5;OxKu8M$6w<36xNf+hj>)b6?A5BA&3XLI@3Hj z6b8hha5z*t$9W0sEmxusAxP{}2lz!HD58u);s~CB zRDwVxmddrVwmk2n<-!VSA}rx65ESBZrjJU%%6hl@>3g{S_VVQ%h}u{~oTJ$$;ypf$5# zAhW92GSAO=Pi)OZ{P<7FW2!O6Os>)k z74DqPxBTqEX8kQV)2>bR8?Susq??#t`#AMn_NeP>6V;Vd*VCrVyF1(DW}&X;6zSc{ z5v%T(c3(PeIZ^A&F}q@LbV_C6fU_v*JSY(uMZvF`QlkoY;$t^o{5K^m?{iJJFX^@J zP8G)L5PfubyFef3t6!Ry>K)<$CExmzM)Zd+!g;Cfqd}DTp0g%pj%5ouz7HB-yy$hu zbxDFB-YBd#swv|Z<-~M1GqJMnX9)U zWl90t9Y4{s7IvF=llA#}u_|(_X>9RePf_gLYempnoo9_NNCnGs&Nw~HhN8ruP2GB# z-`V{p&~Qkn>ujOgLXzCNRoHz56(WsKIWwKSuYT!!$o5fOo6hX*9xd9|Jj*wyvZZ#q4b}wg27q@bUy` zd4N`V;QH`lSbiV=nZ_WcFW0yBSVvfW&HdMFE6<&C3>i0Y+c!V?bcLF2*|B0MJn2|r zizENgP(T>HLuqZCkZ@zgrV3^K)iqcB{}I(LKmTAN!z&`xJXB@jGUdKPsK|PCvm&hY z(P0xiL?w&4bB|OSKUI9w$FRCuWyIO=Yj4k+vNvp+hT1wP{9e6dTDMq z51ERO`#h(0;l~U##Tlhi8=?F#+z_^-r`qeP*-L`(wMQMNR0~8D!&z>|h zXQl76Uopd;RCQCWNPB?H#Q9eT6U>Sm924ocf&y={abbh~cODfCcrWHmaL8khchd%{ zvJlPDiKpP5#NOKIwx&*zYUJmVAG==mZ>vK$_ARr5b>}4^@rG|#&ATQq0C~T25|^7S zEDUA2Z3?N-d-QE2C!jLD$jdMIZPLt`pS`1gir&C4gI1?n?Ddszhx;GLcye$S1M~uX z$NY2&XJ1R$I>U}%^XH;_lD}K$+?;%$Q@4h7RPx>a)4_GRuWYK;U%=h_jlalV#Dlo|IwuoP?>Swn{Ri;o L`En~fzCQ3jYmRj- literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/kosy_remote_control_act.png b/Z/src/nglwidgets/icons/png/kosy_remote_control_act.png new file mode 100755 index 0000000000000000000000000000000000000000..0a6708082cd692ce73dcd26adfbc67a9651bc72a GIT binary patch literal 2730 zcmbVOdpMMN8y-1kE0RhFjA=`jIXA~OYM2qNA!BI12xI0QhUQ>qG=m(nv6PZ6NoZF> zOR^}DGFpT_nkG!8lTuPPatO&`N2UG#*lYjz-s^hb-|4yU=Y9^q>v~gmx^G`+5Bsur}_5CNRygjjg-oidI`Bw8A}X+$Q)r10CwfGf&n_f;zWkG0`?$~ zb_kEblrm{C^6s_<<4M7g|P`7$W{liy_~2a-~&@I}5|73@ zl2HUC8AT>zaAfoX)>R;pvIJ~k!7oqa_X`&NuUMj!7+^_-Vunz-ccBAzh6trXNr+Gc zcJji&kYE~%%@fS;%opf$yc9sp+Xrx*#X>&#Q-+DWe^B6rLt!*>@hHUKk!y5gaR?le zumyvIe8F=5pRB<(V&L=b@jvadu%+q2`RUi@*DStXA3&hFGh)r3uYHHt@%LQD+O(>Cd7FaCDhq>1t2C7z9RUitIiZ%0&xJDv+uFx9*^iyrH@Q)?i;S=y`?lJB%6`Nu9Gf~4z7-3iDc`6{Pyx&1*C1z}dfEqbB)BF}){t7yy0MQU$(XR`4PlSPT)qPznQ z1&!XP^zH?Qy0uR_FDjZXpX+p;I2LR?>8!wjj%AiTuI;Of_^7rw|5<-%L?lQx+@$9? zlUMm{LC_7o6yW5qr-%%jofRcG`?c2%Ze;=lu46P=X&B?r#^c%D3BC|kE{w*|bP5o!t~ ziYpP(>bU8~+lp($Pr-E1z;&fiE*KiK;C4_BS3eW?HjP2v@4J(oJ~Ov?Nyps_1?B@v zT#jR1Zb$8;zCSNoYpkHfy}qsEz4uf`!B$vgXig2(L;hMBH8c>Hn^Lh0)RT^VWN=nr z`KcMElW3+Hm$?XRlQx!>dHxfakKn9e8*YP z>o;T1+iEKheGi|x^g4fr1Yb11WYR4^@Z#3UCx}6`)GM<5t!IP^^#!{uR!98s!g6>|ODdqc~i*al?Qf+L_H7=FYbM1_&TBEtkQh!vz51fSC zSg$?nrz4q;nu?Lj77ZsXJ$}a898OcN#=y5yET>sZr4 zJma!wD{f`fDU0wCSF6-fhi7`lcqgwxLqzDtJB(?Q_ls?RXSU`yr3IU1b|t`y8qI8= zy9dh>UisZAEgtkM&s=Vn`i3^W;)6@wgQ=nZTXpBh2?g;-X3p?#8qoek0Zs*z{F~!?5@jmEH8b~59hMnx?{J*wsrN!c13iN$`zHJhlZ_m zl}Y8l%-msgK8$&JNVy8ndPtgGyIrFFJoCtJQi;qrY-gWxd(I2r+v^&yg*{nS>wNu4 zS5R)yMn!&jKm+uY!8eo0>NxzkT?)5Iz_cmrBlI0^S-Glkt-$)HxWMTD5dZMJiD+jg3EnwHWZi%IH^YYva|aC^tLh^M+=7ndxFke;?0w@nT)K>6G1_!HE0XJI$8gl z_Z=ZA{UzQfECW)KR~vZ=IHitOw&!@WK65W;jYMewA-P~mrn(W?Sto?{B!7P^&NQL1 zAv>SdUlH=_$lq^cskrY){r+#;ZRSU%qr`t%WM9% z&Y|IVyU^uRkJHS;Xw&$+)KM{j1T!N5mjyC)U$C24x{2M;;>ON;xw5Fvr`l5}6#5aX}Caf~627gF=Hs#3Bw1i8vw= zmnRAu#wv^!Tx--J!*)@^?jSZ;E`KMMFEJxp95csZSjKP%#H3+3W=X?LfJDUwqO>~H z=#-u1c@?b`F{4?CUT($=z+is)=v(ZAa47g@+@VsjSPF?@B4!x`bGeKmtp5Mxj7>Ph zb~eWw%`$vMbf9zly7dX+_3$7@Vq(n1Xi#rIMTm(LD5Rn|n`6VKr4g!F@A_S>2~2Nv z@)LJ|kh*e=ci~1iiey_LT@p)vF{`|mLFe?Cb z{Z}Jtn)+iiJny*tD!Ru$m~U)%T`7Kc=}0B8CHU%00Yw&kWtkA92_M~$&U^3LrE#mz z&2;zOxT-B7-f?nD-G!oEYhr35uaNJMB=W3pTs%v~?g^Bluqvy8{_Xgr&FpMZ*VuMW z?Y*RPXFbz3>omEyb{0o2!w#e?tD|S^4y_zP>l{FQTkP{pOEA$tCH_0C&DHd3%_JA7 zcv(onL_81Gl%S3_$71o=Qdifq={0$KE2pn2^RbU@nbel#yQz@f5SzauxAE`QmsLKh zhWUq5Yo2VaPOeyc%Iof^9kbT@3B4M-KWg?~5WZthd8=qc^NRM#C(l_Mo5~}WN0iBZ zP9X49YDVjEdd2p}{1XYYP!(J|q6d9U@rb!QJ7E37XPu`<-rNRv|EO%a?{O`|-K+es zi=$fl1~L}di;_;Sn^H$!+V$PfoA=i!DRWvIXbb4u2W-@Xh8#72Ov&!R{@NmgXzv|C zYhCsUTJhW%lCkfZx4RH^FU$JmvOVrHNufB-lnIW7Q?vcz?WFqT`@gGe4m?y{RV>RC z9;;a*cyOKk#2#zf&=_{KbLO%46hur+V~+Ovn3qoa@PYOq()diJQ6ufLcZ z(50W?Qi|nwt_$Ywn^P&8s0t9S^7DDw)e-u#-#+5B`~u_XQo67qp`ep=Txc8#UHOcB z8XkSdI^&ma>e;c6kY07#v>eyPwX823A56CXAY3@*XzZ<~dcQz->fe2lRg-)tt*7*_ ztdctL^;u8#J^4%x(=GjRe&iawsd>$xK24uDl;2vZ9Uq^_Ea-b)bs*6`;w8WBLWsxe zGatK=fAU^B(hH?skNkAgJZj2JH{XD=HRI@Y7c)Ie$y4i=-`wz9Mt^08VxWM3p7uu; zvPzYBMzX0sM<14CsCZ#&y!@`d9;en-Foj)jr LY_9aMSd;fJjIpZ_ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/line_color.png b/Z/src/nglwidgets/icons/png/line_color.png new file mode 100755 index 0000000000000000000000000000000000000000..d4edae3f67279b37ccad297dadce5540407e0d19 GIT binary patch literal 822 zcmV-61Ihe}P)OCY-_v4D|-o!P+GnKSa& z_nUCRkDvcvuIc*$3Yt5FTt~qpY#&V`vKYsqbzyJ#`N-WUT;E?mgj=*~|ZX=B)a43dnp&OyscuYcO4Cjf4(BS)NTs?5`}$^_On^-A z!xT{?g7iOR5fl_uDBfPM3B&Z?zZn{BTS|m@zbk(K@$Xsx!hiF2Ul#e9FgGScKvF=O zkjwx6`TMQjrYV@^&!0d4_ukrrp@8`xGXpCt6W{Zf?`~(-{hPxgCczgyIW+J3munK= zZha#dG|c~*f5YS8yt`4c{&4)!o!R}q_xs-GdGFc6$nY=^ zw+U`E8qGsC8;zz`FZ=82LVa(VMFZ3_o|Gub7$TW8V@8}7q9&4XK&HbM;n6sz&P;2@ zg*2K|vL;qZDiv}>Md+BAU59DW87MT3CJeF|FqIZ3fh2s9MlWLY9zDSTG-?rJ9!CKx z3}QS*Gds(O$7F@as{x7+}$*>P?76#CXSxP<#6^ivhe-A+;jL zd#99&NI*;&ae%`F15_Xv1h^0rVh8egycqxtLLdu-Sr8lm@enqQfFSVUVNlkL>SQDu zm42{ANg_rHNg5Cq%WO6?&1@!NT*QI|0)d?ah65;#08^%(#4G`NlkXq{iknnMje*n< zdce+zB@yYQh(US!J_MaXq4-FwH+@JHl`@tEGq4~g$kOTTalO+vko~UQ)%>e*cq z=;#5qTYcT4-@^-(>vq&*dk0GAAHQ9lzu7CQ+f?mexBu2!`f_qh>8$7HR_yKt`VqIX zm2&QbqsJ0N5^Sg&K&fcI=(jkbth+XUviUY|1+T`%#`ZI{wnV34P%;qJ(zBF zZt@$Q+toq~9_bwHTaeKa10Sk;QPENBaer*Q#XDlG?dAwqd1Jo+j*cdQbD00}S&3sR zr^Hyp9+hZD<$q-vdfO#AL#~)pRAKJyK3hDWErX^h96kODoU*E|{mAg@jJutFKzZbuz|0~dj>>I=j&UpSMqCT)^{y^-ug=#Q?(%J$p-dx|Cq+ZwbuSgww#l} zyPe#G2uNOF4d1vSJIMO&rAdu1{mczDiw}i%EIdKKk`r>Z?DDc)U)b~2xdvMtHt%-B z-1y-|S7gUn8EDqtDWcH@ArDrMY!BwYM#^@;o--bnJMX_TbeF3_*{FATF|nRcyH{Eu zkZf%zvg5FsYhfSKbe(TY#lSV9syy_?4%WDzQr5)%?S@QvFZLaNLm=^B2 z1y?Dv`fP{$(~mt#C}|vMSi{q~R z+;zo!EQC8hD)LZLtJUMei=Yz|$CNg*>g)3W literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/marker_left_disabled.png b/Z/src/nglwidgets/icons/png/marker_left_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..7dbc6c2ece47e27eb9ad1160328397a40813d6eb GIT binary patch literal 1317 zcmbVMZA=?w96!L|#+$?$?wbzasilo%68Y5hLPw5H0>+Y`h zKo`q06IciXG_ejx^zMa&#*EHmgb18xj_4k&6u_Q6Z;p6B^L z|KIQbegmy7hpH>~RbUua9d6>IXnnwZca@{>FL}=jTK4L}xZb9u^t_-#j1!dv#KRe( z6GovR_8ggp4H#CImSS-|9%*KiO2#UfI#wf-MQ99b@ETbm*#&hx0XrqxLo9thPT-R0 zAr3ntR3saKX{o7Kg>Ahpv1D&o(k&9+M!dmb5kUs(0&ZlwWsNmF#0D>m_NJI5@C_Bc z%R_8B6_2#y0Y!zl!%A6_l#{}pzzS@3hGFV)ngSF_(IlWPfMIPkOHugNLm+Fam|~-R zXv-Eld5E;GXIYZW=kwOQ&8n!KByhXkCI?MhkcLI;k#)ha$l8G-0}r*NDrI#^k#Unz zNGLhoLm*E#L&#(!k!@mG+e#El8EFVv5?CoRlQHAk(AM-Q{Kt(QwY6AJ7Lrk@DLFNX z>XAB71f$&D*^sG-ykVbIB~%oln^%+zaS?;+5QRg^?F^9DA2TndnY+=R!lQj}KLz?aJuXZVlP!F2h?dC^^?eT#!ni&-h z$JnLWP7Et)3-eseIGWjh>7(lp-8wmsEk5_`^vQUxdA!i*n`|m?F1dcTuu}8c zzUU0NUA`cSgH@{+uKiH@O;w*!{pr=;pTSBeem>V;aNYOFn>An0g`b+baqFJpzT-#w z`myDweLWifMfe1Ju=QwR@Q=RP+NE!Oj)T6jx8k|MQ?EDHVYMAt*Ok=Nk9GKi=8r2J LY~kPccO3g0G~3O_ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/marker_right.png b/Z/src/nglwidgets/icons/png/marker_right.png new file mode 100755 index 0000000000000000000000000000000000000000..d82f6a3f64ec5cc5a350925941091891d469a3d8 GIT binary patch literal 1926 zcmbVNX;2eq7)}HwTB8B0Vv({gMVVHzySWnyH0Homf{Gc8<&Y&=Ld0ZavXF3ifQ|ww zpm=hsh*c4_T4+5$D_5}O(#DbBJ2vria+yKMHN;Xpp0J@7j3UwDaTuU9qIxVGLv<;u zFJgfdic7pftsyk3P>~ilGEt`v({41AXbL4T*ltF(i5LOIVS0l}4ECKp4*~|A7+l6x z!78&9OE4@*wO~tA!_?Z;M6FN<1_uFwb`eQn#0V6y8&{dEBD)xT#VaEB&SMA!Ua1g? zV(_(78r5Pzid!&%%Y*~8Fb@WJ2oqs*_#YCX?0F%{sltG4BwHAY! zFyJP@$%w|`NrV_AJ$)U5(X3LvAvRe@5=EvAvZH1QVZxBn=#1-?wv`CS{&C~2+E#Un z8H2(xE1qQ0lJ$u99R-uQ`)@-|MbaD5B8!163c5;$Ymo8FV6rkgq@x zJ_qKrV4eU$gsl0noCmWMJQ-KUk}F0z-iGDF3ZX=Ra0CJg4?*NC0bd{x3fU4itWYQr zId>GRG+7DMq{T+<8c4e%SoVKnMN$if61YW;n4Ge+ zJg=jbVHQI&rc+pOBk(G}BEwtk!x91f@3_ejWHPB-#^=nJ$+#>IID*yvpPWIYGmx`6 z{?#m_M`Q;&w{KdX6y6LEW+ErXLXJk2N0XSGxUZBliQ3*#9g&!zUdAX(CM4GW1fZNLW~+Yef(Bq z_>%rDjSRo&;#^*F>#eT3o=dAQ*A=(6p7H9R;}+jndir)rUrC|R8ZmYLH|CrP4S@ys z^2_~sad$URH)m$wQM5^!C3os~$u=F{cGdgFK$TyE!!_);jTiUnr=o!yLW71JM`w)H zhCfP<4*6hcXLV0U$ow zvE!YgisRd7Sp)@T6+Xf6%j;Jc9o#-8QFx=HAfOkwx)V-5p1 zrS(MPlT0@+>Fx?@4{zL74fSLUwWu@ZPUx-nsJd3JExDIf6#IF*JMsbid;XaRzQ(pM zi+;$v*Q1J*>=vGI&7!ravOUa~mG$3@p~Fcx`%5an;~uM<*K>5=c$UsW4{>Q&ZwP>& zY}j<^`}6ltM>U;}e2_Nn;vxTx4EBL_Zqt0R(A7gdDoR6p{XzVj@sIaqXR_r99UhF?pg zBMKgW`lKX1=V_QWs97FN)z94Ss?TCiKGgft@S)jdy6p=-rF-SK&FwP=2R_zoegVC* z7@qGfObe1>!b;kD-4*_8o>7JCchCGW<%;R1)-P?{q?oM- zqiMw+kXw6FE%9xBM?h&t@lVSYQ)dVl&vngmsr26~`Mx_mc_6iIVBy$88QqoU2|BOm`nC#g6*v!8HOi%gt literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/marker_right_disabled.png b/Z/src/nglwidgets/icons/png/marker_right_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..ac9964f3b79c00901a9bde7d0f51ee4d13010160 GIT binary patch literal 1329 zcmbVMZA=?w96yGDVmg{EQD*G+a3l*c^xg`+_D0toy&kPvz``;J5;(38a6<38>tS0G zpf*uAw@m#obr_csmyuxNwwTPBW#W)z(fIPIy7&c$Ge+Vz7@BS3z~_LXCS)JHcMYaoWy|= z@!%P=`%}_095NpX`p{-aViu$svI#G$fFW_N#F&>A_cZIW#x7NgS*~ zj6M&(=2T0l5%@G6f@*@Y%aoG>PMV+{RV>R^0*0a~l43}jvC}N)U^t2b>kp2s>5*V^egzITeFs7{;{$ zT}JijF3*us?jCH&1R`&^23l% zOZlA?BRYj@f$@tujm@~Vw9DrbML*?m3pDMgT@Gh0&$wxx;rVKocjUN1HEu|%40CoB zWOtn_Jdn%zbSN2`-mGc;xejRT)eJ4(tHpq?shXfcNRk!R+%XHZ7Owzxjoii3Vl7WsIe2#!?G*g@IydrvvPL3jNV7fu)h@X$)Pv@9qxsQdU(KI_md8Y}?QrUX zYdr1h_;lz>ci!_hYeU(WnL9i8jMYu;0!Q;_Uw2i4Q(Lo{x6jN-hkst$`=n+1%0f%} z8QVlb!--4N$ByjfpL=9_C|UX0X@t61a>Dxbc-t7i@K#`89+YrmVfj+>;P^Z*%h`q z&hfw7M&>UvgBHH?*!67YAa~iJJHu6P+14i71JnurXjP3<4=o zN*~bo?z_i7q~+&SoF_TC_uPBV_jB*Lm!+nr+Ei7|Voapse=^2ELhvr1udh{66y>%% zR`9fMLeRRHLz2zSpP7;CFgp&^VW5ifCK&Axkt5NVT4o>w=?8t#C z_0);VSm^=>Ef)j`VweO7k;u;U;(_;fnb!n%T(P^vuXp5So9pLNJ=1C8aI}yNSef94 zzhcX0Yn^t<9hVa3U!xQUOm$a^SaEEp_V%aWNev%-A(fe&#%AU;{?0>Tm%)Y|VT`(C zR&7+cr|uKcB!C3Xa#bPEw&%w7Ss2N|gVqmQ){@`E_8a~(nm7+eR@^m;KB zAV|#erZ%anyN`YU;41yK`wPZz_is-w35BWQj}BCC3?}b={s~dYIY-=QX_)4vTh!i# zkN2NYzrM<8E)zmv`BKAQS*&e*@>Sbg$7-y#$16tO^rlkQ)SA!`ot>sLaf4Zpe6e4y zEkA6ld8ah;hQ&e)g#bS9bRje<-*xXZQm$2&lRrGCs_hYiVHko-SI6^IfU5?#*UkV4DDI#x5#{d9JEInw9IsX(XF f#KZ_L(Sbh!QJgukrs~4t00000NkvXXu0mjfw`=uL literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/missionmarch.png b/Z/src/nglwidgets/icons/png/missionmarch.png new file mode 100755 index 0000000000000000000000000000000000000000..ea52a59cc470513e7e7b3eeb246d85ed9b28f015 GIT binary patch literal 1431 zcmbVMZA=?w96xC27~3+HIH@l2yt!!%?Y)$~U8tq>dQhc|lupAhV0F2C&V; zxPb#OuErOKKrRHyYB*=PSZ*&OS>B^!5<04&$0wm7DAyG9F>DnWRP1D%>R5vdF+C0E21$v)14IT6dg{G?GH68Rc}Z!XI7Sh8 zUPY`kA`4EH+e=^zF92Ah!jvqg#b7P2!qquCoh}ud>t|Qe1iDB^KgGkl{ zR}JZ)=tWzSWJGF3(MO_aAP`Um)GA(ZqqxCfNN^B@QqoZR8@(bERC@gzk_;5^vjXQ6 zIo=B=7@2CmK{O(grwbu?e0KX1vDd$tC@E!Vkny3o3PU}fL|pUQe$fH`b7NU;zq8Q? zPzUhy4FW6Gqh>=AEamRrh7yXBH{@o4lZwLBQ#{+?0bbEY84>A5<>FiG* zev$FAAZeGA>@H%>_r#JG0WcyjIC;K4*#RZByvX}&c^_;k)xdU!<-7?wQJ#fpDIjn= zfQuG*4?Le=l3T_;X4YeO$1R0GQ5Gwu%gLuG4UvN^VqO0yXQ<>1nrM!@nk9K8bzow< z)cTUJG(5m7O^hIo#^V(M83d(#ZKKT2;8=Au9yiI9DVefE1HO+VyB`~RD@&o+*z&`A zDzhgN?rZ)r?XZwE7pe#-ekB{m<-uC>GuM=NscU>*OzGPJ|vQV3kepov2LzduV%TR2CX&j|{B5 za1Q>-b~f@om}v7^jyEdW^gUZUuf_bB%6;|pWN)~A#WrD8_NjM~tX(x_v!X*eJI(yF zwly6bV`GEwN5SPA`!045-{Mm;j4o%{{pqHj)-&zfhK?NGf8y|~r3WYGD$bvI@S`Wz zbz#u;Uq_})&Z4>ISUlEvyZ63*$7#B?TeAx5Q0$7w?3XW1&rQZxRDQybRDCf%yfU;l zrfzXOaJIkgVsjbL#d2q72EzyYUprs0Jtn+Af^@^43Vzp3afVJAJ1^)8T=@qw(F9hdz9BVk+F{N=qvY_fDqw$I@-wla>Tssv%)*=so^}%1!Cb=+-c;PGZZ}*H6 huRqr|7*1`0WKfHTeEaINN5sUh(q=8DI`W@?`CrF!9s>XX literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/missionmarch_disabled.png b/Z/src/nglwidgets/icons/png/missionmarch_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..0edc9d7cfa719c22e98cc3f9c9b5cc6a63d04ba1 GIT binary patch literal 1206 zcmbVMO>Em#9Cw!vrqZ#BP1P8PS?&Q4#D33d;@Z@$oH$;ik*uUago%$j_G{y{_Va9~ zNqeAZry@{cASw}@;LMp4w>%z&CF>%s8da~JupROOpwxj#r3gCRT;RCNzgiit~z z&e-}W$|K#JJb4lIQdFdD6^cPI`=n%Go7F=dwr0BoO;Nr5HCH#rP(YW^sO8Aa`h_|} zTc*rB6VHOIn?hx4V9G;7Q@MgMHD-t=)89w;)+9n;qd=!?_PFCqHJRDumB>C6a}2$y z5{${rmQ%&-Af3V0m`?1?3k3NJ#1SCqJ*#G2TQ;|IE9pr&1m*ll3J9kEi% zLwbO{0>y9e$jo?TI3DhN;Y%`D zYZ+B3)Rsycw{Q1HqAl0wcSrEz`f~l^cNY%KJoap{_|W&Ctz5c_*N)$4pP8mk9`3lj z_QUGeKjyy?*82uaE$z?Uy~^v#txpej_DS#K*k2`c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC)zs0*)ydJtz}V8o(9qS;!r08o z(a6%!(a6!!)ZEb+rq?sCxFj(zITdDaCeU7}UT3^|t(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe&rrcPF*!32Bm#;ch<{yDi!#enQ{0O3a}~fLY?X<{1#&rIiaQxbc{YIc_1Yhm=G`xf|&5c59GkJPih`8&lCYOhji#0 zNd^YS-<~dxAr-fh{`~)M&#cQR%-nnM!uEz%3D=&Uo=FZ~aviPsLd6qBy_(l*vlI#p-#6pr;0N-u&Z#pYgnZbuXVw3HPwI;Fe{BUx9dqUr=)~r>xxwnT1{65rQ%oG2ww$c3?2(vRlCZxvR#FdzLRUb{0NdrtsbLq9Y5BT-{}zkm%E z$?p1RvaRQM)6zSPuImogpRJdB@Pwl$V8O%f4T&`zXQ%H!y4dxe@g^fKC*^8QGwuzn z6Q@)zTzS>|nD`%sbN5g4us2>Y)_Em&=o5?1rpCU*CvNuK$TC^r6sxebVf_=9RS#K$ qv`)Ng$kG!|J($sJwnvA7!+_!7!RwRx1oS6^3Rq89KbLh*2~7aL0U>Ar literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/normal_letters_act_disabled.png b/Z/src/nglwidgets/icons/png/normal_letters_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..cd98e3fe4930b42fee51e75d46810a78d3257907 GIT binary patch literal 1274 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+0De*$i&#yz}V8o(9qS;!r08o z(a6%!(a6!!)ZEb+rq?sCxFj(zITdDaCeU7}UKhN2t(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe!8b8EGY`ZEMGwTcE~!PCWvMA{Mftf3;PAD|#A3gJrG){qzb#yxoLmf@ zEP;M@HMBG}Rf6hGAt%iAfsWA!B@U#-0uutJKoAq2^no0B=1I*1=9nU2*6^vAq`|CgZF_RPABk5{lV=P@#$U{d<{?mtI>-x|9`H6NazmseFN75980$Iabs zWGI)QV^56AI?n~uFGr^Q{CfLatgBgRu a0fq_tMKzXl@B9ZUjXYibT-G@yGywqEU9jZ< literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/ok.png b/Z/src/nglwidgets/icons/png/ok.png new file mode 100755 index 0000000000000000000000000000000000000000..6c75ec331209b306e5b5d563c0929d3f12642a37 GIT binary patch literal 1825 zcmbVNYfuwc6b?wWfCwsziiI_3i;*O|2_cV?2w@X~7{Gvnh?bCS$O_qw$wC6Ppr|7c zwSp+3z|?|@;sYPWA|py|g9;UxjH}0%K+sCH*o}hqhvSdlncaKO-Sd6tJ)08| z7VP9O!+}DfIEBby1-VbNKA(;y-<>Am3v!!INMeXcTtk?Y280r*#uE@AM5jzd6o^ut zw(26{Poa#_piwbIjC`R$h3gnfs}94g)01cl#ecq8uT&)=1dxCvqL`4{TX&WUplTsC znj;70`XEG$%F+!;WO`VXDm_WXS5xPU0DrT9B+wy*5-{tMF{8jNq`u)5kZ0>PlM1|1 zA(DjDw@$^#BY+^>fB+l@NLPV=Am9fvAhs`;%k=?RAOtc&787F8A+CVU5`Z8uvZ$mr zgIXg{z|s+0q$H$j2|_PmGEF8E!^CFbhD0XB=ku)`EEb*Apc~ULLTRRBMz2u@7%{30 zsGdM^46rgP6Yvy5NF_ae8-h+Rm%k&%j3bF6Q^qta^-PEXGIcs@TyM0EgaY}`jSp%Y zqtf&UQ-K)q6oZPahsJ9ZOy=(6hOCODH-c~jN)|<#4CAU49fA=du#ifAVW?5HK+5Mz zA&Bb>a#^4s4}$nCF(~l^SyDfk1G6O3QH~E`{iHlL8w}#}c!7QpBw_KmJRYCV4rGH; zsT7iMMzJB7kx*hPWYjK7+8x32K8h6t84x9b8=`PLd9(u}v^aqqwYVM#isS%tr3%HY zvb8*KqlFOznu@5U23!Zc$*%zYfPFBK2fiOS83GIkNnoz87=}44U+M@}{eN=CB%NVe zo8!G^8NDJq(0Y8=`lRq~co2-77y~&Pw{8v|CMRxD2pkw?Za=v=Nfx=v^%fDEGi3L5 zrMI-O%aQKzDt;(X?&w)O?Y0}+oBArEtw>fWqRolfwO%vn{>A{Bcka)}53R01D&KToN`*4e?{`J(JXXeB37 zW8b;<+`fW- zPcy}(9)k8?EK`>=4_Rb#9?g+DPWs$?1#Nx~yLSqO22HE%j=7uPtjlkx%>n~zPV~iQ zq;zlCAK7Pgc)a`ky=!T(-J*bPCwT**Piuxm_~vK7tFMTQPOnq(CsBYsOJl|BCw_7b zS(MPhZ&n0yaNq+MBqCTqKN?zREtk~=)n%Fj;K^tDbu)^NnJxl&dY)R2dl z`22Q!R}_U87+hSLF|=*S)EZvj7G>V@p!t#Np4(Lx+qQGP9(1v26`@$E$gOzdB2@|_ z)Q;~c(;eO8-d@FJr&duw_pJUaV9v9bY~l^ndi84-1Y#LmKQDu45{CB z&U6}V4?Catt6%DgrmzFOta=;Qh(9)FzbxD!?pf29cC7rH`l;oahpX>a&lrqr!Gy!~ Za}@YOFk>jI+4|3;gh;~RBjWh1e*tZy#Mb}- literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/ok_disabled.png b/Z/src/nglwidgets/icons/png/ok_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..86b8c08bf97c4acd5b535461de3cb245766be879 GIT binary patch literal 1448 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC(bdew+04S+z}V8o(9qS;!r08o z(a6%!(a6!!)ZEb+rq?sCxFj(zITdDaCeU7}UNgLUt(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe&rrcPF*!32Bm#;ch<{yDi!#enQ{0O3a}~fLY?X<{1#af3KDRJ8baQev zG%F>ThQwwj+jP;hUsj#*$+h?4ges9fj6W_Jd zpIxoWxhtf>F!?d>m(6WKMy7FbuXw6yHnv95am6(-)pXCLHDQ+J9Ld!o2Nll4_; zIFoh41nuwxR@EPV*Z47&EbnH;JdRa^3W!& zh>fpT2&_0c>yJtGy}kq0?o6RSxr9XOPkTLxxE86Hu)B$IgXR@iO_!p^JTpTEN&9;#b(5U9v!H-Q>F|1$%mSyx(*~*vjK#F-yyiZ8j&0p2pv(OL_CRc!#Qi zW2j=(NxAF2svCFQ_IV+wKj%(qVvEz$>3cS>y)|v^WDDEWdiezlTizEQIM>MQI$_F| ztqX0~JxV-xu->v<%fpxSo#BqR%v#`4$27B`=@Y+m0Dj;H3(l zA)vl;Dp4K_h%pliu;?I74YEOi4bh?S2o8r61~5SgWPnTt#H2wSemIj4g232AC9Ih= zTD}67j@cq40W}@RjeG_pJ3E`69ZttgX$*+Rc`Q*x$`}^J$bje|L$9~R^-|l6E71Skc&oNq zxzdO-6sQ@?GO3ArXoJSVMDE^g$fihm!(V995k)~VVN9K+M-6y1ET9rMbd65Km-0AL z2;xM5945%-LJ*HB0wrvaDP_Yfm?@EtbG!}90mWi542rp2Asd1uOfHAZkKy8 zR-RYU!l+5N0@X-Om>zhUU%u`w_CX;Rd^2t$1Q-@eU`~VxhFQ!A>KIn@e{#kkoMG6S z7r0^-c3!H@$;@pyCx5Nc9$zuhZ^Cs_nX> z{isV%*3~o3gM$8u{-Ke>^(Q(}Zq(^Y?06-w-=mY~CSu#?`M)=h;r(TM*6r>~gCh^4 zzS$(YxNB&B)w0R#!g~9C@k_bI!0v-Rt2_JZuAc6w-_g1u?AKnLhXnQ(IRow!w*4rq zjL*0J^U(_{XSHjKK4|#J&J=wph|W)t>f38oUzCmHyPI5=Z+2g8Ram#IUzh6CS$*d2 zp2fwZGn4Fh@I0p_6dKg!lY$Fd;?|SScH7^vOFn#{`_wgulU&bx&$^3Oc$eN)A%_xO zyd+%|`S604%Qx@WuWGhNm5Lm{3mKS2uAY79+a(9MTq-kRzl)t8sbgO)-RsI(x5isb z-NgQqe%0y3ZIAn)5?WQ|@I9@f)os+zTc$jf>)-XfrEIz1q>_h^ewplTW%;DG zv=3O9TzL^TQ4{0a>alJ{w9;Qq<~8~UY2TmS6>h!i;$4=|cn?jgc(5krf}PJEw}p=J z(rSl-{O3nU+rY=i^0s$4%r-TR8 zoz0bZC({DShwL(^IN(3rYH$kba2g26Yu81!MQ-$Z062t@Nx%7$vb6G89T5K~;J3F; z6j5`1mrs@MlJDu#HIy3{=Ei>Q$IQD$g4G2Iud1~&_rN6zk}|D4-8<0X`|0FK*CyIk z$XtOWvL$#MbxUe-1)8@8m0#%N-mHI0%1jBV2 tGI9>EhQfLm71=u;ygudc4hcO3{)SxK@;!|1ZG(qc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC$e%sg5KQU^{k>51axGP7$w zpOBcC&UKXKibvV=Yww?2c=+hu+9zcX*sZr8uKWG=?fe@O&O&GRF#2$6H=H_g%zMhU zT%}zMzMuN7FV-<*F|@kn7w1=bwus2z1}?KK$lF-jXCq9 zf6Tn~yM2v3*TF?Ia+?G$}V<#E9AZA$bY8ct&66s=<&$9Wqt4D<)m*qE@mj4 zlmE2VVnxUSpLa^4M;Zk#Xl-bCbb-%FKk!BUf@bRkzPAm(*Zr=^VoaNBTdtm9+2Sz8 z_RKbm{kx{VRIvZ|zxcr`AIrJ79N&l-tXvX&qV~owp#+8#3*LsZXv$R*dch^=f;pVuVaEtfBu6=ITZ0%Fq zXIwWhVdzZwV)$TGqKOe-0$-M}uz-qD@QcJKS-|jO3@-^8Ap^dFi80~nb~pL3@PQ`n z^ZcLZ|NH&ldtjjd_4c+6Z4^bd=eMavvUW!AGp*!%t*-n-mM*N7@gS<=y5U1AW1(S4 z=N)4N7NKEHymJ=zQdCRTE|qb)uw6Eh!y1te8#*3AQ&ewX=o#iH#Pl#6v0a6^_rp&N zZCeVnD_H;qF9&P(wn-ljPWG3~$x&0Xn7-HO-cTk44#Wl>I%94ihYGXAE0cY6%rW$m z3LaIMWv9x80Xm0#NGDkkH$e)}DW2sMJ)$VaXaVqm0|LhjabA=Yf(!uNco<^Mx2kec z)f={mq%bv%J(=U`^*UQmu*e_bcuA5X4nc?$jd(EOVk3;ZL3fiug@NhY9=4H7M~ucW z8pjGlJY5dK@d||%VmD|cilmGS4Ugklz&TD7*OGRCi|~IpR@Dwl6CUJ>FhJwJN$OGU zZh}ef9&ad8B;Lqx_%9JTj z=R*S{zl6|OvjYZd2&15eJUTa+qzi^=yOA7~XE|CG`u1*U={|DkrTohFD)vDp4IYh~ zgrKT9O%;2xs+tsfmOmnCm&+>#fQH=Fh} zc2c~E7rl7!sKZ^vlZWjl;$`4YA~Mi}qM!!_4?=zE+Nm&hFp#`I`M&S>|JKaZo4&L$F-O3 zVu_aWld4G^!H6(I=y;6HaU-LlXP7IPf=HuDg zRMD)hn2N=ZUIHVb$^;xt4G=o3ZlH!KzM-qKeRM7IpaG#PDgMBzQho-E6CZ-qNiig=aY=;`G#{Q>^Q|Sdpl6%5*eS)ADfLuQtW+vOB`y$u zSwxDWL>iJ5V~AK#b*T}?+@QCmpyR;wZI9Z-1(Bk$NY-eIXPzE};CT7`p|Be?6U9;{ zhK4610g8?j#nnIuw1EG(aU?n@Ry`~ha6s04lhtFXw?$^TJKj(PWZtOLzRikatm?#E zbFfQudWvU%1k1M6tRiO-k_VwI!Q>D^ij;<#B$TpAJ)ujPY)j)PZW_sHT|;RYS9F9j zXegdcYm$OANz)Rt7H@HLZa@v!#4Wovv)klq$8yzi9~+eTMM73v9WYZSlmunsf$`ad zfI!|bZ8y4!3Um;!j(z(Ewz58PKqJGdeS`;D`QONgWRy*7XfUoRgD9zI_$Jr-pR9?@ z88K>)zuKjB#d9yUKa9F7lm+06KCIBFMRoeh?k)3svw=F1*By#u=1cg8-|>+>&i zb7NiSzwJJLw{d4`p}#Nw*RCgZcHR&l3A@+rRg;-D}@E z3F`dKtKOqw4s?9zd;ep7bC|2&9o@dYx4BWQ?ChSnz`1Q5+?j_tQXRN&L{pv1OzB(c Gg^k}VBwIHC literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/polygonmap.png b/Z/src/nglwidgets/icons/png/polygonmap.png new file mode 100755 index 0000000000000000000000000000000000000000..04a8b9ed9f8ff54250800f245b2002654ad1409f GIT binary patch literal 1527 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+`!Sq*~Qq&!otza(9qS$!ra2b z($d(`*uc%r&Ct~prq?sCxFj(zITdDaCeU7}UPruot(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe!8b8EGY`ZEMGwTcE~!PCWvMA{Mftf3;PAD|#A3gJqlE#ozkyzGadCEa zF*k8?aWOSAQG)7CAt%iAfsWA!B@U#-0uutJKoAq2^no0B=1I*1=9nU2)_A|>76$_Z zle(viV@SoVB~#CPOFN1jH#hyekRvMF@wKB%My{Z!=)!cxCllhD;`VZj*;Kt#jg#W| zCC;*^Qqa}KrD;u9tC)(L;KBO|dpfSkZ#;GGhwRMlckiCbyY}^9`^~vGYmM)l8^3S0 zcs^_T$Gv=Km#ZG&@MuhY#WQtQ!`p4Y=ROb$X|fJrm`6IrX zGN#|@|7_C1C~MMSdb4jj&&B<3_3P#wUs}AWI6(E#*F$g59}4qkDmZpS;)0AygT!p6 z!UfUC7EOD;WOdW)JMK}f(>r-<-!Ao7`5=FrWtPEV1}O@%Su+uy&e_+H%=QvLD2$lSk~OS+X(zF#Ymv#C45BX(nFE>q441>5Uo@-L_T zJ8&+yx}joe${jtw`q~$pzpVCP;9EAwusmoByZY+V*o?FT-+!(D>A7dMSlYbeA!qJyj=D)p;*yvu; zw_HA3reVs=b(=3Io^oUr$n3p)J87Tc=b-Ao)H`xFH literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/polygonmap_disabled.png b/Z/src/nglwidgets/icons/png/polygonmap_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..54ad2c490133b6c79e9fa240ff73ac9194f970ad GIT binary patch literal 1532 zcmbVMeM}Q)7%yWAc7hsNGM(b>K-nDJSLw%{6u9^Qh`30N)p_|)MjZ!TD063>4#Y2&`9R zc@Bs$(q(*=s0AfYpN8P^n$6FMIp1iaq?Ew{+6$u)0((4>xJJ-E(Zc-W#&gj=TeX*g zEsT$^5*$)JTq#jyDR(b66ah-!5CsA&6@{*(ct@3o;Y1Uq1*IFv$vO!mt~R2mIulW2 zh)RQ^IHp4kDg-mCC?$m%j8Tr~>FN+lnW>bDpui~Gf@;*231@u-WgaT&T!EzBvq(D#O zr5J%-&Nz(%?*T?KOt8=Kz^MLjE8}kyEuL0wO(6!EWX(Zftrp*1MwyZnX!&UCO+ESf!ci;Z>`7iGb$=4;O51nsGPMJyegeKeRKq%!`ScMV@F+ z=~o0&ubmiws)qgA9~innzvEEHXV$a@C)yWoDuo_5u-C2c9`kO$boA3{*^h2@xU9y7 z{jS`3IGwX0wa(ldbPjs(AIv_nq_FQnVb}NP9-aDdj665i)i6x>_8%TzmZYC_QR`ox zy5Z0-9b1WETT$J;`s?Rz&N&u;{K3{0@yXtjfc)m4OpWtOcM10GPYIQc>#GMfrOo5H zZ|43we&dk~7spLr+hng_&+K{s{=!X*>U$4doZb^3uc&ITu&>?qO3y&aj<}Aq-P;Cx z4cF#0+6($01cz3#-9_2kj@rxm>pnm`*OXq}7(RGoEhpO`TeiW?zX4r+Irsno literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/position_map.png b/Z/src/nglwidgets/icons/png/position_map.png new file mode 100755 index 0000000000000000000000000000000000000000..fa3388d443ab204ba222f37ba836a0b868af817f GIT binary patch literal 2361 zcmbVOX;c$e8;(Q}ZBb}YK(WN&S|OPP$OZ`nCJ8}7gveTfm<%vr7PF85qSSIMpy;Qp zY6K~6C|j#2i)@N$L5m`F!3~XUYFP#SpwdoM{Q9G(KfXEV&b{xQ_j%s^oJsTb;hM}_ zJP(CJneaS8KV-MmFJmL*-K}Q4LpCcVJ4op-jZ~@yatOr|Nw+{)o>&kC`9T6v{I*{p z7ZeH|3G;)LLEh`>La7)p(CgqeVi|%)p(%8=m>!rQVOsd@m7g~u3_Ll@Y0d9{+fWpeo#@y zGH@TA3i9^FdPwCE)(H>T3js2KB@^*P2S*BpVuvLGM1TO02t<-SkwSMM(E$Ma>A@k^ zi5z=OB^n5e<7qyhJI`*h>_)GYlZ4 z5Xxbh5|&D^dPcz(sY=PfA)bB=K`it3{!A=Ud`c9OGJ-}RBM|WbK`hqC^+8*q^n?EA z#y@H+`0+A`;0GzBD!CA;N2Kix7|Gqg8`3Kx-q1J5VWcR6t)Nt>594k;o=dDO4(r z=D>0QI2;a~0#9v(=7OpF{EjW4$)45CnmFb`z$HC4mH6PK zn$DXQ_Zs(=w$E>@ik~`#>Bz-f=hzl?oj2$MwdIdZYFyfIxqSEN?^ipetzIf8zU)C}Xj`iAIe-)O8w(KoRJlW%L;lJA2Cfxm!lcSF=UXdpkNL+2y12>l48Jtc(Mho9r z5~}-S?cLsbCa1st5W75-5oglh%n%N((Rnn46jXgD(Oy*rT)W-y+HtEPer^Qn(jz`| za{tqLEz_u2OhhVcRlIIX;fPHASXQV@XekQJG^#V)-oKNc%(`lsJ$6(Di;w=cQlKbX zxuD7n)j`+**KaL$4F(3euN&Lf%o^$2Z^C>O?6CecHFLK#kNq0!X>Ko^?&FpF*C&YC zrBmIjoVBOi3Kunwr(}*7O1iE!9vu7OBIX|0`%P5gk;o9?o45W^KE!>yty>MEn&;!5 z>+;NVPE@NN)~t(=TC7L{<2bL44?f>yW)ytfE-!r!-lhA6&lmoR;`H~~<4;zc>nP%) zONX|h(k)w>iIYw8Gfpid$#o$+PSnj6p@IG7ulC*K9dahO>?EAHg#O{$Fud^89m=ya z6K&g$0$2M|6Y_PwSxpuhW2o)@x~j7tClsR%o`;WHxfKV8n|zgOI@(>9cIf$$98wsm z{Z)-I`xlR*3fsz(Hu>cJy_fEiCwI850)K6#)|6X6Et zb3OBO?Aj$4Vp2LhYTPeb=q_(m5pxV9*8X-rboV-ktMqja{Ix%o9CuSRx3ih`>|wuJbH_^OJj= zGSZh+Gz?sv0+%ii+MkkhzxB=K7MC_7EqGx4oIKU55-*MVz-UqscPdmpuXol!@>^8F zv+=Q-;<{t0)ap1I!%4V1W@HfkGu`vx7g=AUx*{@$Fbc|0y%Sc7k z@JdMK%zEq9ZR7i6eoDr-c@(Fr>*kMvx9{p-Y;yRyRnuMeJg4Md>vHRMRw1kMeQ2~O zqv-Hk=IDfFgMXabpFLfvV?2vLb89#{B&*N4TX{Y(X5r3Np?gklKXQ&L`Fa?W^?qvO zyPPVk{PByXr4Mz3*MKiC%V?XkRf$W^BufV>H($YUUtYQXlWUSy)>1M5=KO$`B0NW; zrq)XPdwMc$09{GCX;1QsYKykZOv~!VJudGDB5Qmp`~v7jM$c5v(4V`%;9dR^Qu^I>a?j72C{|4hpZ*1bX6 z1==^K7n(g>`Fs4PyouYLLo#V%Z_=$jwpZVz9fq>mDW;e;;oaq!8)rfK`-;rr>aNPH zl*1Tf*AZ7{C}(nrIV~z4WG`sYh8Wlw{AmoJY?QndVtBc;{%3~A_5sV>BX<1-X5-tg literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/position_map_disabled.png b/Z/src/nglwidgets/icons/png/position_map_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..a4cdb4e50a82be390812dd427c2c82a2649ab475 GIT binary patch literal 1681 zcmbVNc~BEq7+(p8Mv+6nh{|jiv{ND3Bjhx}29gLW7y^#5BDy3CY$4f@ERf*UhTRY&U*=SlUHk%zlo2JcD7%nU<9us+NeM9zqo@RnMN~orQwx;>C8kolIo^gd5;Gtk5t|v_{iK{@b z<5dzCvVbtCEtC-)&ajkxiwA1aeelMj@e^=P$M$nORNBCjU{6P~ ze*hk|>A-o;=gsjUN{FLs?Ae$cq0)NBY9ivb(d{V}nI*Gkb{$xN zeEFPs#A$I{7}^Zrk37@1u62Ysy=K$tOMDtS?bZt^LFF6P-|skmFD0t5A|E8G41VH{ z`)Br=uMBlMgS@&{Z@71|lXbdOUf*@|gKxZ9JCRl!zUXqjvu-GEZcmnGOp-&my@MtP zp{w2gr|LFWE#OQ@FMGPJX+{9B2^@dbel}p|t&m$Bop-3up2@U$y*Xg-<@^6bf$?))%f8-0s=%-Dd+dipf)R;6@-|@U->J~vTJ@tzlb05!~ z*tXm!B5r(JnC##Sr^X9D)LhLrj=KBFiA6tjl}&%u`7o!ct0pAOfK7_*Ee@_9CG*U? zp61cNU*`F7b4~dxq}6w*ejsW7mIzr-xpM5_!sJ!v_NBs9B4W-jeoML*m-t*sJLqrN kAFSb=YV~_r*X}V6P+S`FO>grkcl{(1R7uL+vCABP121BCr2qf` literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/preview.png b/Z/src/nglwidgets/icons/png/preview.png new file mode 100755 index 0000000000000000000000000000000000000000..eba432e1202d93790d84fcb91632e5bce10727cd GIT binary patch literal 1201 zcmV;i1Wx;jP)NVz&6lOlFLkE-@NiW+H#-G(lY?G1x(6Xr{yH ze9XsSgYg=V($aP~T4;gNdvEV|uiq^B4iO@6t(_n!0pzH`p6=X?kND1u6YVo3d( zBp8q+Nlavb2&%qreeBS~wM7R~UHzMG_otUO`L({ z2(Xw^aXHUH=h~A1c=5vK1X#pLEgYH`VcgA!-TpH-1OZSXqs(S<75YMx^8ZD!xFkZ) zRc@lSH*ZK^y*)3hDl3mpqt*TXkdNIyC35108X?)%C%bYaLsTqaUV(WL>_6}o$GI-Mujd)=3Pqpic= zn|YB&6ry};8kg>~*XlF$rd`JyUur2d%0f-#Oy(o07x$kW3xr!Rzz!%gV+4<;)&wtcIT!+`ol+<7&xIDr<*i1|? z5&+lf(eC4iN*b&=eFnt-35dG{rMdlvHxFAHy^hJBB3uM;4z3}~nUk);m`C*S+gL`x z0@#swTS4YEoe+zy8Q>+z*N>#zuvQZ#HbDq5x-6ZZq)9>2gl|b8L7Ehfgak<~fr5%5 zL12MG>uut`k`ge{ZInQ%qN$Z0x0WKg$Q!}TC~_Bki+(}C5Y(HbF?Ve7-!?99Y$0qk zQ?d;g;k~oIxw(Hfy-jOi$>)q2uBB;#?5w1|;@%UVQchAAmghy_IQdT}u|wGSf3P#7#qLK(9s-p9h0oDrds>5HUdekJ(q85*yB|W@;?ATR^AEh<}@BLohKn z0j#hr`yxXzh%Tw6?G?w(`4A_#+NpGI+T27ljQW`C?| zP({Myu=`l_J?l$FdnqMlvSeC8nuL}!uXUV^6I|{<&ZGw#qCuh5FH1BQhE>6AX_O8c zDl?+_&zjz%l*nW?TA}}g!2=5NO;u@wXdwglfD{-1rjQR1qOcT4{4hb@o&N>iKKC

UfVf;Yq z0}=Wwm$|O$AlZVy|NesMmF{a9acKh$dhDs_$9-T1BEF0Q zWw<}z?qUx@XfSDlf&(NVB*?*Xb-&Cyr(KLBCDl`2{~367?)V`IJpkhCAX9X=Eb%OI zu#!rE1{%ZfPy4{}&&uaWl;OWW9|UUq161z}7dvq5*#e)K?R|_IDgxohHW;q>`{Oo6 z#qys&|36AvJdFjhU!RfL#LS_}Af&V3j|CLcKR;imyx?bK<$rf0ZWD<4^ZhPh?!FF9 zrofm+E4aw@1H+%!+c0zTf3(t*`ZXHZ2Y+d20WKeCdj9Yu#h~lkIW}Rn;P$;w*LEIe z?r^bULaCJ=o(|YViUprvZbjiAKJ&j1louGG1)er6qk+KLbxey{m>Kv<4Gz!Le<9Ca zG5kWxXg3(qi&;>q2&CkJn3aqme*iQOrLY4CFaUnvAglm!VF>^L002ovPDHLkV1koM BFwy`3 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/redo.png b/Z/src/nglwidgets/icons/png/redo.png new file mode 100755 index 0000000000000000000000000000000000000000..ec5a9afad1a84abc37399ab6ab115f4e2c4debe5 GIT binary patch literal 2040 zcmbVNYg7|w8csn05wPfrKo&^@RwyPjNl3zEi8PQ40YV^2k=+#~CKHGunV3vS1TPr8 zQL+T7rD#{Hpr)Vgy%jTWo|R*{A30$OW52&=eM5J~}YCkl3dc=}`KoSE>dmI~rP+le~MO3I+Zh&zdC9)1C2(|JY zSOUwH8#lDVu{fN2u3DCfW{Of+3PekmyKKl7tsX<;aItX~yeN?iY4LlXMABRHZd1P^(+7|o6Tf1jf@y_015;_E)FV{gjtY`8+EAMLed$- zW*NA!QDIQ)Q8l6?xEST@5EIHKVoG0ypw){+uZeZWnM7eJ11xeqKp}&GR_luErL_^2 zz`x0OqqR}CQ4a$W*oc@63alQguvsvcyWe-@GQ`xd#0E816nP#OQJA!_4i$3QMC^pD zR4ZA0h{>l=n9(4U3Nm6S6o?uR@)#hM&*0LzR33kp<4sr|Jq7~lFoC zluo7)L~?~%=h|@<=vBO2*r3jbm3#xDCA`cqOZ^4~2}~*-lN&=xF8uIcOM#}==z53IxPi~+kGtHhs7;&5}`6>>Q;OV8;5 zO`a5f*4WT+T9MfJpYErDWtE@c6+QdT`Yx&Nc9*FF=A2Hqa@-PqT5U--mB#}+&sMVA z=OcBOS4FF0qB&^EO&DLQQz-{K&X(y0JIpz~g~-rz9eb^Mn<<18EH)UNh0c*_r_q@_ zx0v&6tJ|VdVftS0mfD}4p*QCa_)M4PRz)-i6OKRfTe;eKT&3M7c_;bnp69d!7sU&f zPJTYg8eCwtAD-OsKF{g~Yx6S(c z>v+V#uM6{WSNgt)Y;#PIhYFZd_L?HD#zzQM2mCv&-Sj9v{o8JHk-{yDe9)bhGMW<{ z)!>K&C4{-h_Jj*Z{71a%p67N3n?;4mPkOn_57P)8C)d`r0+D|(CtAat9telG5o+H& z%=r}@FqH3zT;tI_YT8Ln0)a}fL>3=wXEPdqzB+jCr?vh++}-_WTESs{T^v(TUot1K zozpY%y(Q$zTich}&P{F-;g5d@oQw#8D&*jWTGPpIbB!L;;f3a~Fki>kTWMp_195>v z`@j5WWx;58ZPeYtlAJNo0k?xel3#Wrx7&8Thgkk}gA`X@XZzxOO!HBrEdndc-~WFm)iq84vs#IzSnE1WJ3;F70<5Q8|OysIn}YOsNhm<(^OZ; z`_lLWgQLTXLYdtHIdnFS^i69-1lpCMnyUPm-22D-8tGkL(y}^hVDIz6^%wq;vFcog zgK_50^ryTJNba`I>-PQ22mHzwU0qm3S6q+lAbI8|e>&9FbZmNb>g(I5_mwikBga!B z!Q$|5Y%8Z!V^X4+dg>Ry7SDO2L&zpyhqf8etrEYtST;rq;9rwo|7-ZI9hsr{pU&hI z-%j1qH&ATJy1cFN#7FgSpSz?y+Duwm$(MJJrO(52Z&*QKyB`#=n>c)aYt!xd*GkIWC1wzf zJU4x*CVTag7n>fo)&xb?dF*+@*|IB2=X=t(<9dc5+v~ggz0KrX_ZKd``hcA9y?s~e z=8n;0oiLMUHm=Bv71RsbX#MOn{V9&mS3||aWg&8(#Yby5f5;obmtNXS`q$XyhB*4%laq! tvnpRq^tzRG9TBu#ey4Aqryf7;pN;dxi9@OOh+i}4G?+|LW2Q2k4wcLqW};4}WMR^z41#5%qH|ZI%s-5O?2^0pect!^ z{hsfu%g_5LF+MdO0DweuE@hS1l<@m%oc!(c=^n_-9LZQL*?6bqqXh;a9sC*wG;?%0 zV`XSZ<+@9Z76781Y(cS9Y*|X!c}_uxbrgQiE29BGo8$M=_O*-zu3^eqj}99Cz5@bT zhYl)ISrCiYz_{4lDuJ<8l={e(=wF%k{>Ik!h7{5oiYmyq}2V;BM_ zRHU^!=$TW+mVD5_3k;}IAQ^TMSWv8wxAR-Vnj}%@@;r-{VgzxMShR zb*sO-Sz5K_#x>jd^nC|v-#R?F3T}h8?HjdHIyb!N8^)zMdbnwQ?I*+RqusZBL8(_9 zcqcR>4)un954D7zo)xdeSifzkH+N&0o4hb?x|&d0la&RGZ#t6>*iW8v&F*|}=AG)Y zl*PdryINY9nBKIe###Df(^vlbsV3S~5%sws%quFp<)-XjPw#Nt)?kcxh4)F$rQ`oZ z-`n*zuPGiA{a@|&bwqVL&-C<7Pl}G+V;y;-y%Bq<-F#y4ss`t5>YQ=2wszgf*wM6~ z;|m*I7y1&K?j`i)j*dV6qrpj(tW4WpJ0l?W?*~`+jGaD46`oBAZj5bZLN^CH-d|LA zF)tvdUVUX_?w6a%nGcRM1o|_tly?QId%CCn8O(l{o$t<790Ih}MPzE<);I1ZZ(7yx z`25b}A)OH`teLqd`f=2g&PUB3gaQu+*4qqi2e!Aem0bG@w)M`Eg!JUwJF*L2mu?rb zxp)$nu+ui{)culscx$LTv25<4Xl)5OH)X%!>MwWuHzXBR?t`hiG-yswiC&x30&v64 zy1#b}4UY7;S$ia|?#iLj)=rltUIws)R( ze{tFN^zwOh=-dxQ`O|({q7R5AN!7vFvZZ(9me#~0hK`5h%A{EvR12-8KNhur?KGcg jy1qC0;^>{m52wWe&3LAA+kw*9@K4!n%%hIz%Rc)T!h1c@ literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/remove.png b/Z/src/nglwidgets/icons/png/remove.png new file mode 100755 index 0000000000000000000000000000000000000000..c3b1d9d590e83040aa253b95a9186310d26f5e66 GIT binary patch literal 1134 zcmbVM&ui0A9M3u&V^AE3!-=?&sNkah{#D;)y*WeJpYs;buCGaNAnun^FahN)3?-Ps9WUL<;E{)21tWNvg>!;=O;&P-IgDO(m&KrzY~FWX5tJ8Kpr; z1u;OzSegw-c%DB*a)1R4;24$*vAh`OL;%RvLt$%1~gGlN>ccS)^tsj1zu)ZJ_2|S#NsR~aKj)Q1DqU_q7s*t+Z@|rV=^Df3gKux zo{q6>mW%W8xFCenVIa#gn~k=yInzaoslv8h9oubTBmcyT83!uJa!Qsp-R^+VnuRR4 zX4zzBEK24TRX2UvFVAMQ5_I%gsL76Hkj?yx`Zo4KIu8Dh8;2lCnXJS|h9xP=MW_~5 z`=6XK*crxej=!3veS|yE-)^-&7Pf{5ns{OyJQ{rkEyyf_lwJi9}q97QshUlH${lQgx7($RpVv&;HvliF8q0MQiuag=tP z`__NX@6_l+yK}^&MDNApAC}1H1A)P{m$kzFC*@CpuC8-LClS4;bc|np((nHPa@m6P IaJYQ_H$ZT34*&oF literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/remove_disabled.png b/Z/src/nglwidgets/icons/png/remove_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..3d14eca47082b5e0a229cd3ebd0af57042eebd6c GIT binary patch literal 1080 zcmbVL&1=(O98MWi*&J*Lq8>D4;Au_XH*K0FF4nYZT*1!L6)Za~P2R3?%ZJHZn+}92 zC=(|77mT3?J;}hM6Y(Ve3m!xSFJ2V!peWQgT{{)V4hE9Ri=a zT{b0)$)2ZYBAEy{2pe?dthk{ZDNIjSCj0oBW9S|PFDuNhQ?*i=&U*o(1r{VtkO6cC zvM`kvMRAJe0R$Z2ImjoWD5rQC0J{G$#9ClA?ew(jEfAP zgDl`2CyuL!4siwjabsU}Snc?TtDw+p1tzISV{$+yxjWcU3?$yjmjjy=#aPiiv*jQc z7d3?;e^|@5WL*+<2*orId61cgP~vl-kO91&(FBbz=mU-YxDpV=TsoHnDM^E{0H;%# zoXSg3)zpAnbVF>oCK}kaiQPU|J&-Hs17u(?sCwSYpaaTH4|`$L^XdG&z(TrY zn6?|=#0A=oS3`k)9a(zdIdm_>vb~Q7y7+J8(<0P!Dom$TDGf7Pf$4Lt|H&FhoZ;g3 z_^Vw8SEL8y?OyYf!`}EHm&{B+h9il;oh5_SC~9godRzb1?PiCPiDN_eUOgFpbbMoB zZF`X$?>=VUjXqnOs8)A6KQ}*pyuH3nPp&r-6Zbb?SX(!TkNTshvp3Y%=mr+XkMDH4 u#^DEFw;ujDSN^b=KC`g^t|pwsg|!6rr8Ol`cV17#vs^69X-{*Dw|)aT>{8bN literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/rename_exercise.png b/Z/src/nglwidgets/icons/png/rename_exercise.png new file mode 100755 index 0000000000000000000000000000000000000000..d8cf25306f762e9f87909154cb656241c3a59326 GIT binary patch literal 1921 zcmbVNX;2eq7!F1(Lk&np1*N(K)Yg(@Hvw`$j3JvPh~ZY^fe?}niI8mEEF?s#2(@af zRZv7!w1SG*6crH!(JCV25k;#Nt02|`siS}g^l;E_RBV4Z{^-u^e&73j@AJI(?CO}P zaGL9QR|L5@8Dpw8Kefolx-lC7KXv(H^cy=CKawT z5<1KPI2e_wSSBH)lb*f_L2s1H-w_*3ZxcnPjAc<8Sr8Ls>Gh7dUTd3(IP_mP-m7g& z$Tp&^IMjq?;wrKp8owbhnY#}gawwAC2%>QvSrlakjHxp9sDX%pg>>?Usn)3l2%n2U z5H}FyvcX^;1o7Enpfng{Bf)SG%$6cU9Ph(&L5V~HLm-bQ4u&8po5$tx_VOz6Mqnl_W&|YhL4aJT(it4G zqdae-g;89Wg{l!8(*v*bE6}~iJ}Bma|Bagr0fr?~m>U=d!$Iso`dh5}|KyBCI>T}_ z$A6k-=!on<$M#+8lft{f_xRM=j?$8lEA?z@t#|kB6Ll+JbZ{PQ<9F7ZE1#BK|E6?)d~J8XHLzeE;Ij8= z)|X@Y4`vlLp0NA+znB{6ROY2N+sCK+FPG5dqUb7nwdf;(Hm~XKxY@CvE0q~;i>zKO zs)xHv5$e76t4p;qw|gzaKKZseqbey>rV8-L%cmu#c$Wc-rX{alG15kn~>z8}6mJl6Bm(yp8ac6eGz$@Nd2+I?r7+&fcZ z*4q4Y7u}>pJ27|TO&%Mi0llxB2evhRBrk!a#b4s4hI@vEhN6&v(*4A=wa^2Lyz5A<|E{Q2P z7Ru~0Z^sUl^gQz5ca^R^Dl~1uMvJa;T7E^~NwKBVpVldFz~#dD9E8I{zM1GrjBl?$X4W^*ekjHzlN0oat~H zoY3ogL3XSF7p>oBk3tFx>tE&!oL-=~0n`>>%Sj5`KkT0s!8R8 z+y8puc4}ceUG;0*-5zlU?bYu}^hzF!V-({`25p*>2zSX2CWQjVXFT4TG=?RwbSB>Z7bL5o7c z-4GJ_Y}|?SNw+55TGBi%VO(uwrrX7x$<+*B=W8DO_G@TYU5hH}>h`owam{P1cvkRA fmEZ6rJlBcRS{ZfvoV`ls_$fw6qu{Erl)Qfcp3?e# literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/rename_exercise_disabled.png b/Z/src/nglwidgets/icons/png/rename_exercise_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..c55a95365ffeb81d84cbaa3336dd5dbb6a481347 GIT binary patch literal 1539 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC$>s`_`P7~^Q@L+!HTyx{v_&@W`tV@2i=J$ic zdw%XcUj4Z`{~7Og9qmIBuM>Z2?zPFC#dkX1(B$+c$r7gTs~xWQFEo_AZ*4I}@`Lca z2lct`PftB{I{)KeVpjNZxhJ``Pj2iISngNg`R%K5qfE4MYr+zlX$KnR!eat_sysJ_ zubc5Xy?XiiY^Iyx!pn|&7;iZg+Ogx&-T;4({m7$q93C+O|2J6qg&tv>f{*0RnizJd)BHq3l%N0)N2yj+#EX)oWs zQ@`TTm}1>`c;7j_A3yu{7|n0LWqoz3rs##MdGP@|Sq(FS7=3FC#a9&m`CJn3 z#+Gi;e=aC2b8{-^arI^U>~}<4uUO4fq!GU$B23EpYv|41Syo}SUJe{=iWVaC*PNWE zFkN+4qk!&d_FwDmTaSF?$vNFG@aA-t_u;?1F~S#Qew&DWIC0?HSLgFKbo~3{!SKu4k2CsBg>r)i8hYF;KDW>FVdQ&MBb@02iw}S^xk5 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/save.png b/Z/src/nglwidgets/icons/png/save.png new file mode 100755 index 0000000000000000000000000000000000000000..7c034071c468a005ba9067414f1067626434832a GIT binary patch literal 595 zcmV-Z0<8UsP)G*}4DWY|qGzlYv5) z!460Af$yJ3KARYRKV)E0zU;?92KaMVcM~Ih20x&=o6&v1@bBk+I6HWY|0Yrl zU+c5c@83UQsQkE%B93Cg|9}7C>^0sS7)h~!k%7?{SwB__{{H(5XFDyn`%hvB`627a zYQew1|KRL>v4=?WK^&tmvVQCq{6i?vpQugH2N(0NGUC#YJ&67yym+bL8o`vrSitCu zOF!N?_;e?66FJHB*T+4?#leqvyBMeiSO|HMx)%JSu?5(Y+0YFl73a?+6?oF(jBE#& z@vI>!h@PGg1t-_${)SEK}9aC*hOX|^RZ!u|Cs90 zeQ-OW^3U`cjZ8nS3>gcMgKTD(nLD(EV#5{;FhAf8B48Ew16Xa|$f*A}Z&EEI$gdBt z-}|>5Bqt^ESr$a!y#Hqdv@XXA{sHCATw$0Ft@s&G>SVY8BO}OCc_4mGV$0$`Qmf)N h$iY}Gpf&&qFaVv~8R{KZn)d(z002ovPDHLkV1k*=6iNU9 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/save_as.png b/Z/src/nglwidgets/icons/png/save_as.png new file mode 100755 index 0000000000000000000000000000000000000000..fe0a91eec678e7dd0ece0e79a549ee7202876ec0 GIT binary patch literal 938 zcmV;b16BNqP)+}?#Z}YX zSGuf{sf)Yg?9ANm9d_2yopjd&A9v>5Irp6NopaAF1OS9!?8MlHVfL=Uh*@GgfDq!P zn-n>`O@F2^H6=EuvDs9iKAw0jnA1g@&#jghC(hNEVU2^XRjmge3!st=nP3gV z{z}$ERT5Cf*Ja`i8kT1O_yviSHc$E?sJvipJq#3P^Lepc6eL5LQhQkkJhxc*mP=oQ%iuE9NbThv@QWYpFWtLp27T8DAeLlr zdnRaa+dp`>RPq#Yiz)W!8&~Zlm=87N;Nsq*GO508xTF?4UWYr$BU^*H(JKLWP;q&G z_YX(cGA&xU2K01uz}(X=1c~wz7H0^ zn@q&%XcX4U*X~igc=B@W3rYnWdhAeq>X&wU^7o|67!s-4BTMHzYcQ7oY{8GhcvXlL ziIBdF!r=e}-GUk9YopTLdV3ekupX9W!4h~_##TL1#>_LlIC@5OVD9SUE6B(d$FB5Q z`c4oXJ`{E*Coav=>S$td7fCTQIIEjzw+qyWw#31Rwt%f@@8+I}RFRcH_b4SDLya{m zQO9u$AUV;Ln6)t?#yv?7kh?&@%rSdqofmw$;rutWOsr>B_@(+G@6bBg4|FIH+8C9!%uOOs~wgZ zU_>ocNtGI@LJsH{`2t0v#v6}%`ZffalEZmVELXov6q+((3SUVi5kR6$ri<&1wptU4 z{LhUKYO8svN`x4Ss1=DSAzF_Zhh;FDyFWIhQ$)R??@&q6qVVHkg)mWu$Tb15Hy*tq zh@>Jqn?_-iNE8o{0)b>Ii9~~ZK^7T=*ksrfhFI)njt^nUYzl+TqA{pc2AM=+K~xHr zN~5_m+(9;*O=5X2V*})B4PP!qmhDPWyC~L!MRTYAA(qZmA$*NO#ZxHampdR>qR=SR z5`_|Aayed|}uV z^1#2tivFLR5m9G|y5{&@vn(H>9jM#BZ+%pFKRk#Wofs858vfP~I2ep!R{+f5rQEFw zOAm|;!)<&1Y)Qbf(|0?xvIjQ2(Qa9cSQKpewC}s_ALo142pj5+qJoPo6Szaa*c&JE zo8Tf=(URWkDFd5KeSVG%Htsr;qwkg%viI_k)@}6J*d#4FyYWgNtL^8Kxzj%_wa$*t zmd);4aUiRx`EfZjdOC`Bt(|_~?nZ(A;cTW7_?B80xS7mmY6}$=R(@?ab7w)_f(Y8y+O+9We4Pf-&@>X3oeJ%ZLoKRsab`M>pupIoe*efH$&{cWfvJ#&){VDMd_0%>*<6}^4 zJ6|$cskb*r;$d7b|19B~bGfH{sy7U#W{ho(QH9QB5AmA04K}_euUyBzs^^hkHVhpV z3}o%R`SfY?$s1WXmm?Kerv>rSw_>Zoe{c<@O`?fCg@zr$k?RdCCVF^tNfGzC=IPE| z-%kjz&auS<9#^P~H#K*5xLQmXP_$uw<-9Kc4O+WS$wTO4zXy`N+2wH8{r;v)DByVY0DBoxToEj?BweSt@OjLCVMuF z_?RcHpAHJlw>|@5>^iX`xOS=kwqttg2t$nxRa{cvifmdpd68SxCDtCxUZsB!Zy$CB z7dY5dGbg;4Y&u$esBSE+vhRTLLxb(z)s*en-JZ{HT|Joms2GnL)XaWaTbdOjQSTXe|t*lj@?rewOwMk@4qHmfaP#)2LD9Q3>K^_{!@)to=x~^ zt1_q`Y?*fw1F*Mkf42N}(Bm(8zK$!*Q#+{2){uF*>|Z{@GcMGMi!OsM-U}5|4u@Y| zZ3~f0?k-hVsxk^9V6ItBMY>55!SvSJ&m1dqkM=#g;_`&xp({-g3EwA!5z9wzd8A*G%H>?E(D4VkCE?_BQsyIXl1x zM$S2J{(9dD@!Evqx~$O93;$ecZgCEucyc7WYSW?W!s^ND-7$%5Tuo=4xe@N}1A}4h zLssf{O|tt&AmkOh?)wNsXw~`HO$C=*cCFlK_9}1an{AG}b8UCo5fa3J!Snveoqj6) zxPY4nHarTWE>4t;HICJa34gKnsXb=oqG!)ec>UuqnTK6ZPv5CL-y-I?$Bzuh<4gQ} zS-oMirQFZm$Y)P}F=W&Kyn2R+f0A{>Wbs15%p4`1Bk)r6=1q+o+0DM%+6T5@sm-B! z$YPXc45HQ07t-#s93Jj5)3y2N{YK02vU{!gnfwr(-f+2ahnJyv$jgzpF zdXg}g6!(y+Jl+%=m7B-rX;)z;+6fUM9mwZ&b7&qfHO=QHOm>n5ibyNvl7qpHE)by1 za?qHfg|%)4X`?bq8PZUy%QcnSO)@i>wgO1?VH|;zWC_6Mbhtd2PYzD-V%$C?7J|Tp z3Tu~x&z;KC<^T$sA%PSK7MNf$42Tg35hY6`k|Y3y5m*SLLIf2c5=?|*FbqsSAZLv+ zTQI#+J!y+O$w3>-x-p^9>-9oj5kxaqAtIB>LL4Y6;4}oD5*JJO1TIfPm_bQ;Obq2_ zDcS{u7>Oc!11kqPPoIb2bZfOQh+Uq^L~$t-`UtlWfncH28H#H{+r#R~f82PfwkNm5 zO$zm-hu*-LxO!L;!eB0UuQn7?RjH<=T6eX%shdEw`#Z@U%kpx9ykxYpoDnu$0r{ky$!BHGfk>H{* zR^#%pgv&&R?NXfGNi6b8ET&*cf~A>Uns$UcAjd|tw8uuf0fiw2LI5pcqFf5`Uo<~=criYti<=pS8;-6AAd^xlgHx_)%67&2Kl;oY|L|J*0Bc?Rx%LA)z840hC zc3PW*3Blj%y}=TBa{So6JE^xG-apkhe)E!b?e5`emfEF-#rpSdKCWH4^s~(GTF(z} zS<%q^4gag7N4u^A;4cfcmQTvg&8*Sh+m>@=Z;+?mpH$cNEOm4H^oqhcm$u{&&2EV) zl5{8Bi>;5`ADCY`b#{Dv{^}v?edCg!wzj5SF&N_(HOF_@yJLTBv=4iWyP8z~iw%lSdDWQI$ ze@#@M5ZZwkcuJo1(y>X6<$ZTgHkJ1+<0rOkUUur7;-ssUpJXT+Q)1P|TBeT~!X4nF}b@-fXkyzW{4-Y$l zzXa}am?01NS3OAlv-a4XpW{9-_B+M3zZzGxGjZF`HrqxUqnL=+wf)(LGSv-Lx5gsw wzKd^}a{cRPk48G49zLE)1&V+3RgEv{=J_gi+RQPI(a;ZFqtYplr5AqmHc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+`!ez%*ou$!otza(9qS$!ra2b z($d(`*uc%r&Ct~prq?sCxFj(zITdDaCeU7}UQ@h!t(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe!8b8EGY`ZEMGwTcE~!PCWvMA{Mftf3;PAD|#A3gJqlE#ozkyzGadCEa zF*k8?aWOSAQG)7CAt%iAfsWA!B@U#-0uutJKoAq2^no0B=1I*1=9nU2)_BuXxq*R! z$<5QnF{I+wmTT|*FFQ!Ee^|a|a;DFN-h7`PD^;~)67fF|mGAp}{=$*{2aZhFdZEp# zy61w#q_e!<)w~kU5_@8dI%n~+JZBRV680&$%fHQXqJZ1`bGvUPb{lLjz4tWk%d8sv z+I4%kF)_#_KNgW*J>?S9mYtn8HKp&41vtdj=yDv2=03GWc;~jiPqSK6)&<*^8kau5 z_VjknJ1*(tk}P@c2O8H-^*-_XVC;jJYzM2Qid^%nexydddfR_~$J!GtW?Q@WH%4t< zP}Aw$9dzGeQ7TYqnw~}DEl)n#PqPC8e(Kz>mFPF+p6Q@kS{HwSb7R-3xi1BhE-ZFA zJb`n{;j z8q2rqPFBBoP<%F5*Au&qhu7zHYN<6C@*iK<)b14BWfkiic`)+#Z4raShfbdx&Na>N z3kyx%H0zG^8-^dY0<(6oS2eoKKWVMi^+rbG&6)J7_@f8JBHFGVEuC|Ekp;wxi%^NQ6e=b!-hJ|&ON3;oyn&TRYD@|Q7! zwN>a0%dwR`%MO%okkxo)`73VL0^tm)NnsoAt>fSKVSjye9j5`qp~iI~FJzNIc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC$)IM7O*t0F4+?f|0UST{;%vJDG}v11?EMnpI5A06 z^uPDfyEh9r#hOl(*gW&yf%20&_w)Dr8fgoB?AhWcWT?W+(3QG$$&%YImn;fMSo>hg zp9@m;w#5rfm&$lZA7<7Od;i1z{hTY`4}5Ewe%<^}Ixn}1yxjba4{!C92yjjMyt|s` zPKbcVy>riQe5x?6FF71_;A~1)Q@EvuBCi(X^y|WU3&d31AFmE&>{{S_X(e+^&#~2P zQyjdqg-^!YJndqX_)$JlUBF9P_UMn*8jJdeteVwjsGHr(&Dq4bQeHH2^3hW! z{sJj~CNnJPEWF?U_Q4_+fuld984_0YOuoC8*SxR4&p%@R45I|^W7W6!UYeu-E nM7ip__c>v43ez}$h$JvDF1!5VU)0StprXms)z4*}Q$iB}>z2Bk literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/stop.png b/Z/src/nglwidgets/icons/png/stop.png new file mode 100755 index 0000000000000000000000000000000000000000..285dff1c1bc75573e5855921a1ec459339f418e9 GIT binary patch literal 1720 zcmbVNYfuwc6iy*ni&92mDol8_0xYW3reK3n&Z- z#SyTeE!GwgwA54`i{O)jXe|#r)~OZ{QR^dh=!nG^w2pLxVEy6rM|WoT-gEEyzVn_f zlO@G@xcj-&Xf%(6cvMcUKF)XcEb4p9A{?g{UouunrVtv^f|+odNKItmK!P62#N{}q z&fV0FN6~1m8m&S}Dy4~tiqJDLrw-GqH&SRCEh^e-#8f(*1TyeUtwG2bJ^eic(5i)u zwHzrZHHz^pZM@Bdr`VDdDw|FvP&1;J15s9lBGBU`23Ymk1~Xz6GNyPDYVSN|F@Px* zQYU1*a!M(c0b;_00~{t8p#r%ez=fC)JCeuaEd^i@0$Cu;g5U^UL=GurP@cXDL2r~wUlSY5(}|)|#c`8@#@DXfF`8eP11viH`^?C_=Cu!~!= zdsXSeN{kf&9cO5Rk8PJIb`=)TgTNidK=@ztN}^r5pTzkb07|dOgVv=shoKcs=PE_&EZMh$C!|_u5GvdjuyRK@JZdmp7ZOxQnKrN3aamyJ2>g@X3~e-y1ZMOpV!3~&Q09+qu0Hw z-^mOghI(I8hZxbD759*jHxitF$Hvnm>R&Vo2mdHW!sfuY1hsb_H3YajIM0XvOoR6} zbc7>y@9)bGZYAPcYcC$tbw2(3?6##D;_54|#g~f>(n*`Oe0}b-bN-$iuC4CVO@^(@ zIIr<3X&u*ml{VpU_4o3DJ1)KGU&KAQqIT@s;!R+4bBm;Zz`LHqX-|A_Sj>MO1j|TpLT6P5ac2snp@Y^kljY%z-uUgWd-fn*(xoCuqQWm@=sjdvg~eZds?yn z@*y%QuFig;3y*gTjTDt!ScduRj`_k?QT$%-bB)r)RYT{lq?gStk{!y=6O3Lie<(9c zL3&M4Q&5;!5hMO#{{1zX{zsxdb!;lPm^)kt9wpzn;Kuiw-=q=Lq|GaB9JU43PjvZ* zE3q6&Thz*DioVKIHf8so+3`(fyxa$luH}-oi(TqcdMe_s$i~KpM}}IupL}_HaK)<9 zc16}VLn|l3OGOX1E|%@wBj{Z+DW=OKb!h0R4W|b3h6b9qD1=9p6Swriqd!|WemiIn z41Ag2kb3?4V|#T*P2t6Qe0R^PPCP2!+;+&DJ z1NPh}hpTpyeuF@CVbU761@&~KZ{j95uj+W-C`&j{8B#O0nLgZGp=hWr`0RyuIxVqr Vp>LYwYftCDBq25lJsgu>_z#bHlNA5} literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/stop_disabled.png b/Z/src/nglwidgets/icons/png/stop_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..4146a097cf071b2af4fafb45a73d79931db85fdf GIT binary patch literal 1702 zcmbVNdrT8|9B&a6nZ-^~3ZZ%{DB^5;cYV=H!9rV0W)<72Rg`eF2kqc`^?J~P!3Q%& z(5Yd{l=(mfr=qA~3X4&|$B_BJpmR<)>F}+fXb~2sWLKnaON@Vb$=&bw`~JS4&-a}x zPMJNE5fmOoqtO`28l{d}S>88rIQ4Zq<$qC27^yOndOVYKA_PiPnDGo0NXC#XREHww z{G}~u9E~>2Vl@~^qjr|egkwC!tHX0)b_z|S#U;4xh$$N-febXuYLj!GpKRa&R3NpLp+d=Vcxg~wH>4m{nw56YC8=1 zc9gF}9e6HbqUwt=_`>-LeBIS*24q>H=g5)T1Q!a+u$YiCQL*4MqR3W7 zfe)K(bC8J5g!=4SDZ4{h_=8wk5`iKlP8e`J$JYTV7M#Q#7TgXb=|wyU&>|+Q%`5R1 z=xw}8l(6QZW;KChz+i@D*7tazmi#~RSP7&~R6s(3LMnvBN)=}aYyOz5@hNBc-uC!U zyZA&@4|=!nnx8tn8z0n0%?v>e2ec`h8ce_I$x4O6b*pmA3XOhlNOOBFg3X#-zJ;j@ z2{8byy%zD@@RAcie`L>*!11H@FiZBZ0+ZWTv`uW%bnfzp#!Owx`g;7jocbxN6+pD9nu~6R4|-==1Q@F+YQc*RmEGD<_DsnghL_Fi*nX#BG_oITMml@~o=vz6iM{s#Ndut=@=E%78Kp}z8yi_DhH}@4V z?{@SlxPgZ{)2kZA)2>yFt~54y5_(u3#wws*)3AuQQ&3#`l3`pI+l(n?#-MU!>|!NZ!PsYgm6_$+e!?1z}5|_NF|bdEcEY zzxPM4jjW5PczmY3f_*ijp?k!g^V|n(;!hWZcuoCj(fc3%So=%HgmZ-lI!=-IlFokPSusQW_`4?=k*@Khj_6;*^(_O3 ze!^~?Ezvh;HA>_DEUd~>J#u!}YhFy4ynM|Lq`P|&*TyNa!K+1&=yeJS zOaJCp=Syx!SIfPNX}!m8z~OZ^@XYi%H#fvQok$-}TXwuRym~_b=KXUdt7a=}64Q(R E0n0Cd8UO$Q literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/stop_playback.png b/Z/src/nglwidgets/icons/png/stop_playback.png new file mode 100755 index 0000000000000000000000000000000000000000..ce57a95a133df2a4b7ee0f948e01c08c3618c15b GIT binary patch literal 1135 zcmbVM+iTNM7>`rDu0BkJIT?hk;su+Wq?fc|RlAZQW-^FV3CtY@tOo{a2K~mLR#H0*7fY_|14WRhuF@VLJ2HHG`41q*q%~La?895-TTJ^$1bao;Uu@>R4JEd)7V99 zlm{Ul!~h!;c`+Q3W%(d00TBp55=1E^%1T&L0ATA6N3FTWpi+Qp-4>OST$vC@5rk^B z%2&fYc83Hpkx2L)k`$sEA#cnkS}kOI9SsJEJl!=NVq%;18MOgCN|GG)bR`7K$>mmw zZLgjvnlhoLIfBRo!Lt0gmbE=nK!4m=Q`;+!IY=lV50AP!t;b+T159)GZ$rK!^+q}7 znzSg|2*moRg=~_ANsiv|hG{5jLRLjljsRH#vA8HEq%M$&0ZEO)D3mg4gJUhM4Aig+ z#b`X9iiu)Iip%kMA`wo7fvT!vCfdMeZI5WSjv97NYPXJ!{1dCBU8E807BL=abU?n0 z3HHj^Vbgt4HmB*P?aO|7R-%Q-H7m$aU2L(-`Bls{?1NMs{2ez90m5_!%8@Pzqf&&c zV~zjGnLwQp{O0(pSsF*Q1O4r4>r-KMc#use#-*dt`Qg)UI#yFzm@3v5=59O>G>Od{ z+V}6wue*PqEnkc+rpA6uZwsECW^ONj>gVU%+naB+EIpVX{}K#wy{{HF?f6=`Rk`{0 zTV?N?>mPqDyhu$Q%^%-#(A#olHVEG>Jv)8r?)w+l_LOF?rVeNuCnfOl+3@7PO;1~n zZ=VaaeV%R&zCIGU-19J(>95$|gFi0xNP$PKrI9-`LRx%F>vwZ1lIju NKsM70?{%HI^cx2IZB+mO literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/stop_playback_disabled.png b/Z/src/nglwidgets/icons/png/stop_playback_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..e01b1bde7767b75e27a27571d97567e253e96388 GIT binary patch literal 1066 zcmbVLyKmD#9JbmH1+@$yBpyN>4q`x!edjz}TTP1-$8981N@|siIQF$MiG9Yt61NNp zgb*N-#p~1&qyc6H{?u*)2>#124ILf&a1bng^~^;IHMXuo{$b)16rj@%-wnX|J|y z#o?zW!9=Vw0S{9P#9rHv)VRQRbyc=cu0s7~}+)wqYKEJQ7eQ zE6eg2kRXC0ltd(@k*sDU6++N^cxEkh7S)<=^lY(Hfp1b8sG`{Ebc9YuAmNgT6h%oi zBq_}h>1f5LR-E>uR9`{IksZ1Lb%_rWMXN!UX@O^+?uOt6)#{$GAN3N&QYOY$AR+;Z zo|nYcMMt!T|G2R)Ix<%REY@&DmP4D>V=>hyv)mnQC;>8W)GMLOiej~OVlR8xrxm@x zvp<64I;x?_210Tc$`Z_vBcw=0Sk6Pq$m=;>DjR)`{kTOW7j+F8Fr(-QmC<-6U(_T8 zX_BVpWG&O@R{V%szK#2KU1qn(Eg#5LOCh!>2~9%U{SKIG5=x>b2|#H+Cm>L@Y}Ze2 zk^=3w!amPH%p`fA{6vOOY^i@y3hiXlvwrJF89Ym?`bH`KIw**)mgK*Por;%ze|3u3bGc dcxL$3zzFy2!n9y6Y(7k;w^E+fpBAs*`weCVP0;`V literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/thick_line_act.png b/Z/src/nglwidgets/icons/png/thick_line_act.png new file mode 100755 index 0000000000000000000000000000000000000000..1ba4d4feff5d993c452379653153d0afe16433bb GIT binary patch literal 1079 zcmbVL&ui0A9FLZXtj^0=oq`avt4ZEVn`Vj2+OBC`!OqeZRy>&|Z)@0+7n3)eO+@sf zf_m`aKd_4+diCHzL{YryNpKhO=0Wr#D9+87uH8J09SkJzN4}rW_w)UAyEb!nXz;`! z!!SdYX`@cp(fB=lh<-nH^q+J&PD)KOi|0wl3=mVWaSO2(*IYn#WZEm2-l7SHNwl3t zlQgU6Gz+_e8QTbv>r*ttOynZpv=$LzTWG=Ybne@;=N#+UIyWa*LDes!wllpNpxM=# zhPAqAsWz9JWG5nx61a$%Y~(I^p%&>}msg|v_*&%Ht_fMxxouI+YK<-80I{+Fcnf3! zn}q^QXB0&_%}M|Q5lAAGc&KP;NdtiGJskBG*z;Q5DEEBPlg_mX@ikHGbUH#OE#P25 zgsQ5>9FoLS3qD-&h#B!-IM!z{P-q2?PaN#AF{9bS%S7j>((MpjzgpcP_QGDGXv)OM z^hGED(RJgvy4E47qg@$$T8E7lABlAo;^n}i^_U;)gK6&ecN7~^HQM>Wp+zy53~VjC z$Ria)=jb27c5JPzDrE?j3{WJH9fwerra&nRq;l4f4XIS_bL@pJ$*NQ?X0jly8W5J? zcse^(kW^TZ3I$myr2E*47ZTI6P~WdZ{r0f(zF4goAd}#rf$>tm18QwdaM;E^Tbz{z z$W~3u@#34fK-=*eC~z(#yBuJb?PgeW_E1n%B$>(`m%wi1RCiVZ3RE+)!u7EB|71<1 zV#K&T{%M!~745-zyVLyiurof$qcaoG;jmwy%+bN3IV&`xkFAZZtz3dXFr2vi;^Dwr zs&;hrdh^(=k+!{=Nb&Ni$B%AWbMIdL_&oflnOA?UuYb)Xxd+$s$;qo5#+l^i*6%mp wzYOy{Gw}W?E-EANUh2bI>duAyl_YcU2qWglUS{rxm3WjZr5WSN)WsWr0f(4T%>V!Z literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/thick_line_act_disabled.png b/Z/src/nglwidgets/icons/png/thick_line_act_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..5387fba3f67132f53a2be466ee57dd31b870b72f GIT binary patch literal 1059 zcmbVL&ui0A9M2evY)+BE@CS@XcD2cSN!v7GSxuY973>^s!J-$_coDpbAYSwj5WIR2=1bSk9mWm@lJ_H@&*%I5(el#esfqIw9LG&n z7tK0b&!+E*n(0XxUsR+bT(EU z)#Zx|U_Q~9fRCvS5`Qg-wM6F!x*FT3*CG!F5W1@Kdrq}#%b-jm3~~a@I4}=E9tlX! zDvELuNDx60N+OanNYP|TgAfcKo>`0Bj#f9Vp)GdO`7WiQCW^gYPw2@4iB?3Us%oks zNg0O7#QlKUNhXNrMhYg5oyZHRM*@&4+HJB;7lI$wYWu=LJWLcznV8t2hy*D5 zej3*R9n(7g=f42q{^pNHAYONR>*kl82I&H*=;`u|^t)am!X#ma=jl%BqP_1r_9c$&gfJ zNQRM940*(@1~Ih*2aoJ}%x>9|RfvqrkzB1DVVjbuNyyr$1D3mllDJDkP;TTv&33#X zJ*VZ_i`K-EcL%#xM0_yFujUZH@!Y zGP+_Nm~Qu5pB?sx2M26oA~qV^_b>fqW7VjdMl<=={Xrf0WKabME0tyY%I*QJ}Ae*qHXN0k5o literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/turn_left.png b/Z/src/nglwidgets/icons/png/turn_left.png new file mode 100755 index 0000000000000000000000000000000000000000..d4a0faa130414955d929119dd3eaab56720bfbc7 GIT binary patch literal 2057 zcmbVNX;c&E8cr!FSkSgoWl8cg~slw)c77=Uu)t zx`?nqhea-na5$Vpa1d93jZT)=b^-Ritzl1NgEPvDMWc{JR3lcwIF1xafPrASI0+WO zVrk~q4%iomdp}twj74KZLs$|-P7+&eNLslPL*sD1ep;nik_w|h0-PjMu<_>R7Ca!6 zvhf>zLcvgF0Guof%2L5mSz$s+R;q+4#rv%Xe6=i$Kn|l~Kr2sEs99Pz{xvTPn_ITY zc;K}On##t%5fvL60R$i_81Ny1UJ{T70yKyOQN8JO`sV-zgg`P#Awv`|h|Z!?SRe?@ zJ$THUN}9+LaQSn-uoWAhjG{^wnXJ)hNE#{$Q6-TfCX;F5pisOp3omu10u^h$6l#xo z1}?0YsANi1hA03Fqc{OcN7;Bx>6;Mb%Fxia#0vFXqOg>awPGb1B7tPN+!EJoYc(o> z|B~@eYqc;_36lk|8cA14uzDnV%!9Gq{k)LtokN|+1}oI4SRsMu{mL-Eb6D!%Vp#zySd1bnA%djMcR)lkf+FfC8;?>{Yg@Pi>y5 z+6%T5uDV+hp$hxwM~FuG?(NW-_)zPutZ#%`HPSV1^oNnhHw|328A(V#AaESsX?9$ZH>FriP=(bi zJ>wJMFAKi8b98n>m{{}S*#b|S#A@5#cx@l8nK9WtyZ7X}YjJ0BzIK;h=&XCaZ%qkA zVK=435d|r#Gr#7y*1$dWUpP;v_D-my)Kh0p#c2GdD+<=_inEzO4}3Wj8DsdPBbEo` zn|{QvsaUf5!(qHBVY2jDRZHV!eEEHygG!H+5{4;*cT6nRz>V6X6s^+eN_DVR*ABNm zNpf2&KHOS)0&xB3=C9y@?nl>FguNpE;cCdPJ~aWvmvFnQ*A-12dv5j*InLK-tyB_& z9*M}tfeia)S#}SdI|u7LeqUT%G?JM+^y%S!2gi>GcaFGpZHe#5*0=f+Q$$Zj>&_+a zT)H)`hdj2S%Y1Js+%Rg~S7ufEU3JNH7wH>dLHO{?u?xc7s$F^io=`qrlG}eI8JBZ+ z;)TxcU{iDCqw4H0_Urad#l%^CmzH@dsDPUL$)^|WMGO=bvm6upok*KW=_&6OA1lwP z@o~9vx37Akd$*t@XhVI}_{7&$4@EnPS2)oPtN4Y7KHo8Rd+qVUbD>Wzk?WlwK}g{8_tfo);DCCS!{g}4 zXSUJBWovTETWX^-!nf6?K5bxKvGJHJb2lunKQtUtx8lKnoG#8Ltv>(s)Yi?W^Q5jK zPS35j?H>=ecTRpg>1@mjNz+&V5_{QLm}biSSac$$_|VG&31rM$R>(3=#=RQ7i8$>c zE$lZCI;RV*1USR#&lZpRkp`T4I~G*sS8g|%$9Kpo5U0woH>PC#^x$;EMu$&o*oEtf zG5E5a>$g%5`Snb`4AR3}+#eIh!4zS1II-uxvGjLOf6=DP>y|;Qs-(YkhhEixZ@S)Z zAa>Ly58NtQKK8HtmV7jLhm)PB3wN($1n!614|tnCTAp#N-t02eEBdI-xOA}KX1qd8 z*d5fIq3@~NJ0J_H>+5g5(9GW;Gxrfz!poYin-oKXyZmNCR-ZK=xHmDXoBEyzWS?w` zY!IjB)q1ZDI9hr#Vo9q+^6EET;EALryWYmer@2$xZk$Q?{Opw-i2J~e2s5nhYb`(L NU|txv&VS3!KLNIsPJjRa literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/turn_left_disabled.png b/Z/src/nglwidgets/icons/png/turn_left_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..631b1cb87939c0d4edd9b17e3e24c5137d685f88 GIT binary patch literal 1585 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+11g))B+gj#+ELIhOUMd#%4~A zMwW(-MvjiA=8ncNy`Fi+C5d^-sW5vpf%Zc68sODyfeuIVw}p$7lZ&B~ zCD6~VhL)zLN>IHi?JgIrW98(0$8rwQ{1Tru% zC3?CzhE&{IGqv6$I8fwxzTUF#lLne$At$#27|B^}DI_x`S^eQ(kII_>uE%gplU zs=v=G-e>*2@cfL_NS}#(54K9L51BLj8N-GHjk=;2N)I!(HM-sqyD=?LGa-Bb{~ZtA z94BviQye-)eI~EA#)et{p0>_rDBZd1fo|dMOM8_gCmr~7>Xk*zjuZVNN#+N>YWb%| zc|JIPKGnQb;M7eo#{6@$UM#CDFP)ke?QmoJlxHo{jOkDF9qgPeR3`q~doOlZE@R^S z{WapOd5!nhH00l(r}CEdVH~6Q+t_3GLRA~r=+;EZG)S{t{Wt5c_oZKjJ1q8gy?=1} z-E>1%=S!k@4XPUEZT`oUZFrzTx@77VN5$Fo{{v;Nn(XzvDrXm=FSl*8u2FOG$Hwpm z_kHI7`!cG^_N5s!xo0!0^`$lToouaIS1K#PHsANmnYTw4%W++sI{ixP!Oz!DEjc@d zgW=rt$@x=uJN7Z}tXnnlSbt2k`hwzl3_TVrwHoHAJy`f><{mza=Y|J5Japz2tm063 zK52^lSz!+Iwt2;e|1d~=Xtplv?zgR#b*!0CWGZm?gPhCp$Gj!Vn>RmYe34^$H6t%X z;-k_!`IyPmb_?2nx!-MO^v#E7{p?GZ!VSAz_kJ^0H|eruDd&k{Vbm<+Fud!!{N>+^ zoqRj0gVaC0NxzgZ`K{gy>-u#!x0tSLmp>|%(ZtqO(^USzDLva_;h+9#FMmE1Hq?wh pASiTsMMm4YZI}DGpZ*t3U|>7Jzvj?2$2?FW?&<31vd$@?2>^AhPEh~= literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/undo_act.png b/Z/src/nglwidgets/icons/png/undo_act.png new file mode 100755 index 0000000000000000000000000000000000000000..44894678553302f1c316ef6bde1aa822befc0a03 GIT binary patch literal 2034 zcmbVNc~}#78V(2osqw0fL8uLZ6)%#RKoXJ?AdnC!1Tdg-2s$JKi8&@_21r0u4r@cJ zTUHjt^*~ucgrd8qct8NFD2Eo&vbqSkfPyH;v(~LHwYU=%yMOrfkIwVV{I2hPzxO+S z&zPbk#U$b~B7s04g@p>G_(-w7j&t$vzcTqR@WB}q#bGf>DwYZ9VS+%8q`=fL4U`5; zVMuP=)(-m-2y+z5*f=as62X%p8aiaPp&K+h98Dnj1sHUYOa)`q6gW+(<q9t z`_OQ2dU+~ODhzq+3t#bR3JlZn7>vx!OnRm_9nq&TKrWYSSwGD0axI>x8rO5cQ_(Mcrlh_&e3MByo87$6-3qyr3%#v0daYZQ~h zzsh*8H5zNw!3-&kBI$Y=UXN7wSumcv-*#j*#MSVk^h&%akXney(lxLa3ls8b_z7LE zl=DKkoDdM?_y8Ox!1e_}E;9%au>ocXTgVbJMIo~s@572%91h3@0l=Fp1VIt#>&*@l zFu9v1M%J(P;<}g{fTwf;eYvj0YHV43i@?mjk zZ?W>0a@gjMBQCb&@?&n?p8%gGEb;gj;rV#V3CHIO^OF7sa+8D^8C# zFFd*EDg8*!<6j&mIzH?er|Q?z2SjBp9)IaijDDJa0y!9v??bx~VVj-ZxqoVj)^W1P zo)f*qQMYZa?K~T=%P?8nF&f31ze$|IF~Po@H=??GO~-BPT#2&4l809o=4`16?p1Y$ zcZuttNj=L^R2sh3|4g&^3%aK9WIpuhh|_mapET+*MQG zR2~(c%mvyq?r=yM?CnpQE&;KHtu5rCld>U;)6Q@F{CZ6865Y2S?um*ZSvF~1kE%%5 zU$mAkO`P9Y`LkIU{CWD>;oP)WJe`Nl`}^IIIx258cQXRfT_lVThPY1B=vRQ6A7k|Kh;OyZu z+E<>^b1QAe4T@^@egEc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsfTS(>{U z8k(CJm>U_GSr{5x8aWxbni&|mnYoy{7`eK^%)qAC+0Dq&z}4K$z}V8o(9qS;!r08o z(a6%!(a6!!)ZEb+rq?sCxFj(zITdDaCeU7}UQ@h!t(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDe!8b8EGY`ZEMGwTcE~!PCWvMA{Mftf3;PAD|#A3gJrG){qzb#yxoLmf@ zEP;M@HMBG}Rf6hGAt%iAfsWA!B@U#-0uutJKoAq2^no0B=1I*1=9nU2)=-}tT+hJ3 zWZ>!I7*cU7>CgZF_RPAB!pyyl+%td8XuQGJq1zZC*kRA~(M!Rud!dks%aRB7_5a)$ zKWZ!d>u1$xO_EFb+Oy=y!S(m|S2uR0g&=Pj)F_x;ac2`Y8jwRBSV z$>RCFLKD7M#>+NqR zi%F^%n(p&tSj0v;J~M56a);%}9EakY2OLX2-dgMGP$;_M`t=vtEAO&&H8wpL6;O`e z$FK3+N8{dts`rc=wJb#c{`y*NHNlGQ>@VHr`Z0U?m-H`?JJoKX1Z#mjE-1|Q}XQmz_qZ2pZE>>qdjJMTEaXib_UP|2YRe1`pWwfzw{3sN zD*lFtY+Y|^GAjG|@31_Y<=}tZv?Zot;^grBdwXR)Djx*=XX<#}Sdq74{ph&@ugiinFJCT`XlQWI~uOs3o4U6UHx3vIVCg!09j5fR{#J2 literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/zoom_in.png b/Z/src/nglwidgets/icons/png/zoom_in.png new file mode 100755 index 0000000000000000000000000000000000000000..ef3885743fb8ff6698374c0ea1093985601bb507 GIT binary patch literal 1330 zcmbVMZA=?w96zXxF(42@GSq~}TXdSx-V5~YMk%G&V>K3=(kLI6Y}eicob>MM-C+wM zu(@O@nTvD7WcmeWmSrYpf{R%)J}?B$$P$CEK~1E|J~$JXMscH)hWZ>(+y}A`UUK(5 z|L6Jte*gCy3wCx??t6M4hGCWd!)yqx`;B++9`sEoTv@c#>%MNiOX<-Qyb3XophO_> zOMEX3L0%Yqa}l;+n5jn$ckA7OSD2_GS$IRol9b{IjbSbBWSo!oLmfn5uPD3l%*-qf zM8So>ZVixuxEJ<`hlf>G zRrG!rzU5SRAPBsQ3W3!^nxmwR1UAY-H8tDq_C`RH6iJXYLD6Q)&NR^sNrLSMN7huK zhY7LVwk;&N@IGCSGX#-HBrJ(0i=y@tl+)=nIB438G|bwdtn*2;tQ{yYuuzMtVq6y$ z85oRwL>bUsIP!EW1SuW}>=4V^cA`+qh$J5;C<{qQk`dRYwx);Re{Srmt%V2UkO)Cd z8Bn9B9z6#NV3fPZ8!{A;H_WT5h>F6;SS30jL0R{+E*#xh1W{l(r=6oHdoyXLNt=VB zoOCF8&exvtD|-Y9swQC{G>qo@ZVx`Qpi2FMm>( zd$@H@50_TYcz?>AST0IkH%-@8e>%BP`dQoXp469jB7xr8iMyqLfAG}z_m@L;Z?tCDGMW6! z#DlZrgU1)wp7^HzUc*#t_TlQmkL#)@&gV_HCmY-&OJ5fUpIf`LPJG*#?KoGG_dl3( zpMBw@lXvs(b9d7D+59^TS7u%tDi`KPPp!<3es`7oMa%wBKR;hFa!F_oH6FV(aIFN~ Y#1@t(L&4jXtHxi<@9Si*wjX=@Uk9_?6aWAK literal 0 HcmV?d00001 diff --git a/Z/src/nglwidgets/icons/png/zoom_in_disabled.png b/Z/src/nglwidgets/icons/png/zoom_in_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..5b4f564127b3c9e17c29a511db5289fbd3294219 GIT binary patch literal 1268 zcmbVMPi)&%7DIirlV99>( zeee7IzW<&b=zsdazDM_A7qUgdu-JW`u~9&lU(= zQ$xh5K$1=tqp+aGCoDKP(VxyvjAVJ02%o@v%K{?Mp`+kseblgpa){XC70})lQv|-H z;*5ldZKpEH0X%A25D$>FFH5sD&H@tndpM5k#u*yW6wOe8@c~ZoGXhQH^@l*#EHx*j zB)M)2okB#xaf$*(l}aVDU3cT!(zcxx{Kt)5we9qH5mG5=n`2fM z)gyPb0YE^Y)3J&uwhq2cI#N~ zzE~k@LB%nxv}ukuI$)q+I;LGPi+FS}Kmt6eWHrN;xCPpdSAv#y9;&is>iAZM1#K4( zWbVI_2RR@|M9||G`5wSZF`|xD|4-H^j4*$us_*h{XH(Rm0rH5K4|Js;SJS=$p&ciderfU1! zzd15{pe_9}cd&I* z`2@=!e-B&kyw=u7&bKUUOSRz1*|yqr`Kk5`(bdC!FM8)*m+)UB2P^GEi>H1#9KP_t zTi>54>@mOUc(U^5Z%wzRujb?5Rxd5ZUy;)C+Ugp|uik#}yRNyJcjKq~H~x70m(KNf zK5VXRyaB6~j_%sY`Q}TD$DY}H4-T!atx(BVXU^TYejM}c$F3!uFQ1sdam4)(C1U;3 JN0Fh6e*c^ zlX{Xc)>K_5Hv<5t%v?~!6zOtg2Fk)G!a97X#m1rmV6(z$BMcQJ1D2BIW~&^Uy6AyG zvr!K166z40O+}i_+YZoV{(&6@h65D_sS#3a0XI8kEP;h&2+(P%wAy7(IkdzpWB1`> z7y_46m{O917gSL+2@3fL&wz*!P=xYPL55f?P6sgrMPLMjQH+O*WdclwAmGXa zvDRo~nM{vsR&24795OMCO$NgbhlB4B@F}_+Mx|0|m;=LjtOn0sV`T^@&uUMNFyN%! zK$~rhnX-amMxvCeX52e4bn@;zX*lJ%%6q_>GN!VbNkH8j7IIbmaJEJH6b7NI) zdqItjg!QDIs-_KWJ<3ueU^aKpHxyQ6y^-yt&1_MKN}MuOTSzOT#pMut!#A3ZGL2NM zK~ZrABE}Gr1VyD-7NQm*m_~#PaZIg=aIA(EX_Q$iRHBwhlp+*WV-m4MB9#i10z{+H zplV?RtF_u0!fGHRcFnBa6)gT-tV~6d1VhmU6jd4NfLs&BP<9h#16BD#P)8Wd*03Bd z&vLXlNt^eRMh#6_z@_}k%&XW(loI6GxY-bJT&2dv8Cf_k#4?~2tnvTk3}&5y!_Dzb zvqX;A4h(OfwmvI79UjukP7KYCMl4Kc0YG$|7FQNH$4eJOAq9sQwT{yqHOMQ8N^-m1 z7q)J%KYZ^J@JC$#q-!vGeXidJIo5UOxcqnKs@hxU16v!r8sF)k_RZC{aidSSc--#9 z8$Xn04;?&lE4jv%()u{zquyIp)4qw~wwaOUso!cB7v_?#1n0d|K5fF@T>$s9*VBf0 zjz6~=#T$)lxA>p5zcv;MT$}DY`QYIP?NqQQt#Rf~;r>2L$2YTqB!fIJz)g^!@k>&! zM;+5b>3-Gmn6BRgp1)`3TiVy3fcd)P!?gF;vx>2-L&qMT?%DIR9ou_!A#i&x+xcd6 zy}}i0HD2z{tn}86R+Mb-<+yL0zuWua8)V16?i|nXbTH`Snow zb))av)lG15Xwm;jylJ4=)Ow2iR^bY+ZFU70<__KZ%e$t2{LA`tzL*hy=0A$}GKpYg z+4~nfiFe|XQU%_@Q_2U)$$1G4F3$wAxNva8)i`(OcSlA)U7V}~FXue=!2{W(cPuGA z@8b8t>__ow<1+&{3!l_C)O{86%k1(8p7pwsbJ{#gyb&%%4=q&5`$? zslPisrAXX;b6=>bixVu4)weed9aUX=J8EqSP&2Z})w%NvZ}?ZMRqw#hWtBAi3+q}% AeEk?LMf{Yy0$GdaWF+cfEs4JjCP7*w8?)ec&2sduz+C zpj*x@QAuWo>>I@C5|bI{ma!PrEO8m(ivv zp6CDkf4~2GM?2bEYbu|u#4xNT(I%$QTJOHk>_FeU`S2=Q8thn?-D&jMdC7#Bpcom5 zCp4)arl6z@ANc_`VOV)qO?TN{$=7(<&`8PEAssD;&=}U#;^ZWG0NQv4_N#iBSiX9V zz*Qwo91JAsWG)J`YTJkjJ4f2n^2mV9DMU*%-sJFzK!dh~JKCUb@lKdn=jGAf6;lMh zu3`^_i4CW^k{x)|Fd-fwX|GHNX*>u>;PbOA`wGs`fTn1M0*n{1ypQ2&8ZSNsvSuoM zd`gTLZJ|?`$l7*}r>J~BPv(83VfIsi<2aXtVZ2DgYYpqR9E}e4JzB0I+_VW$0iC0FH^! zu^`RFgJM8rV(}8kR#+hx5jim)rG1>;KW|Z{7yIs1 zL-MPWpL}$2_bfIsiA~?Vam%=Wcx>0~+XsI1%+3p!mKK%{m-{`6T2*_n;C0p(_HcED z>b*NM9{emed+x-xch494{=j~@aBgudO<-%b^6oqFK=hQ!KP}j5Or-N;&VP2a`GAMG9Ia2xwSFzvdm6*hFK;v?rV774Sf2m< z+q3t3mFIn< + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/3d_viewer_config.svg b/Z/src/nglwidgets/icons/svg/3d_viewer_config.svg new file mode 100755 index 000000000..3a88e5077 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/3d_viewer_config.svg @@ -0,0 +1,497 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/3d_viewer_config_disabled.svg b/Z/src/nglwidgets/icons/svg/3d_viewer_config_disabled.svg new file mode 100755 index 000000000..209609363 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/3d_viewer_config_disabled.svg @@ -0,0 +1,169 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/3d_viewer_disabled.svg b/Z/src/nglwidgets/icons/svg/3d_viewer_disabled.svg new file mode 100755 index 000000000..6dbd0c86f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/3d_viewer_disabled.svg @@ -0,0 +1,78 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/about.svg b/Z/src/nglwidgets/icons/svg/about.svg new file mode 100755 index 000000000..e3270cd06 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/about.svg @@ -0,0 +1,428 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/about_disabled.svg b/Z/src/nglwidgets/icons/svg/about_disabled.svg new file mode 100755 index 000000000..ef49ecf7a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/about_disabled.svg @@ -0,0 +1,100 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/ac_adapter_plugged_in.svg b/Z/src/nglwidgets/icons/svg/ac_adapter_plugged_in.svg new file mode 100755 index 000000000..c19bc1256 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/ac_adapter_plugged_in.svg @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/access_rights.svg b/Z/src/nglwidgets/icons/svg/access_rights.svg new file mode 100755 index 000000000..9865249a9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/access_rights.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/access_rights_disabled.svg b/Z/src/nglwidgets/icons/svg/access_rights_disabled.svg new file mode 100755 index 000000000..d11ee9747 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/access_rights_disabled.svg @@ -0,0 +1,95 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/aircraft_sim.svg b/Z/src/nglwidgets/icons/svg/aircraft_sim.svg new file mode 100755 index 000000000..c126deeb7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/aircraft_sim.svg @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement.svg b/Z/src/nglwidgets/icons/svg/announcement.svg new file mode 100755 index 000000000..f9ba271ec --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement.svg @@ -0,0 +1,428 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement_disabled.svg b/Z/src/nglwidgets/icons/svg/announcement_disabled.svg new file mode 100755 index 000000000..796fe8c1c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement_disabled.svg @@ -0,0 +1,101 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement_menu.svg b/Z/src/nglwidgets/icons/svg/announcement_menu.svg new file mode 100755 index 000000000..e71089143 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement_menu.svg @@ -0,0 +1,419 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement_menu_disabled.svg b/Z/src/nglwidgets/icons/svg/announcement_menu_disabled.svg new file mode 100755 index 000000000..3a65c7740 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement_menu_disabled.svg @@ -0,0 +1,91 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/application-exit.svg b/Z/src/nglwidgets/icons/svg/application-exit.svg new file mode 100755 index 000000000..fa5e04b9f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/application-exit.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/arrow_back.svg b/Z/src/nglwidgets/icons/svg/arrow_back.svg new file mode 100755 index 000000000..c94a6877c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/arrow_back.svg @@ -0,0 +1,392 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/arrow_back_disabled.svg b/Z/src/nglwidgets/icons/svg/arrow_back_disabled.svg new file mode 100755 index 000000000..8f20d3828 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/arrow_back_disabled.svg @@ -0,0 +1,62 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/artillery_firings.svg b/Z/src/nglwidgets/icons/svg/artillery_firings.svg new file mode 100755 index 000000000..832c59f6c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/artillery_firings.svg @@ -0,0 +1,459 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/artillery_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/artillery_firings_disabled.svg new file mode 100755 index 000000000..7a0eb15e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/artillery_firings_disabled.svg @@ -0,0 +1,134 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-high.svg b/Z/src/nglwidgets/icons/svg/audio-volume-high.svg new file mode 100755 index 000000000..db3712259 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-high.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-low.svg b/Z/src/nglwidgets/icons/svg/audio-volume-low.svg new file mode 100755 index 000000000..a5ce37fb9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-low.svg @@ -0,0 +1,381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-medium.svg b/Z/src/nglwidgets/icons/svg/audio-volume-medium.svg new file mode 100755 index 000000000..814e30e3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-medium.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-muted.svg b/Z/src/nglwidgets/icons/svg/audio-volume-muted.svg new file mode 100755 index 000000000..8e8f01930 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-muted.svg @@ -0,0 +1,384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/battery_mode.svg b/Z/src/nglwidgets/icons/svg/battery_mode.svg new file mode 100755 index 000000000..02662cef2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/battery_mode.svg @@ -0,0 +1,368 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/camera_control.svg b/Z/src/nglwidgets/icons/svg/camera_control.svg new file mode 100755 index 000000000..06c19c5f8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/camera_control.svg @@ -0,0 +1,428 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/camera_control_disabled.svg b/Z/src/nglwidgets/icons/svg/camera_control_disabled.svg new file mode 100755 index 000000000..44d93363f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/camera_control_disabled.svg @@ -0,0 +1,102 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/change_password.svg b/Z/src/nglwidgets/icons/svg/change_password.svg new file mode 100755 index 000000000..c78ec507b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/change_password.svg @@ -0,0 +1,466 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/change_password_disabled.svg b/Z/src/nglwidgets/icons/svg/change_password_disabled.svg new file mode 100755 index 000000000..eea7d74a5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/change_password_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chat.svg b/Z/src/nglwidgets/icons/svg/chat.svg new file mode 100755 index 000000000..6dd6c8c3f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chat.svg @@ -0,0 +1,408 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chat_disabled.svg b/Z/src/nglwidgets/icons/svg/chat_disabled.svg new file mode 100755 index 000000000..2397def61 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chat_disabled.svg @@ -0,0 +1,82 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chemical_agents.svg b/Z/src/nglwidgets/icons/svg/chemical_agents.svg new file mode 100755 index 000000000..f13b6de07 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chemical_agents.svg @@ -0,0 +1,458 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chemical_agents_disabled.svg b/Z/src/nglwidgets/icons/svg/chemical_agents_disabled.svg new file mode 100755 index 000000000..ace1a913a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chemical_agents_disabled.svg @@ -0,0 +1,132 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/config_gobal_alarms.svg b/Z/src/nglwidgets/icons/svg/config_gobal_alarms.svg new file mode 100755 index 000000000..9454aaa08 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/config_gobal_alarms.svg @@ -0,0 +1,508 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/config_gobal_alarms_disabled.svg b/Z/src/nglwidgets/icons/svg/config_gobal_alarms_disabled.svg new file mode 100755 index 000000000..6fc3547ed --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/config_gobal_alarms_disabled.svg @@ -0,0 +1,180 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_arrow.svg b/Z/src/nglwidgets/icons/svg/configure_arrow.svg new file mode 100755 index 000000000..2e7a4759e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_arrow.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_buildings.svg b/Z/src/nglwidgets/icons/svg/configure_buildings.svg new file mode 100755 index 000000000..ba8ea62e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_buildings.svg @@ -0,0 +1,472 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_buildings_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_buildings_disabled.svg new file mode 100755 index 000000000..100885015 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_buildings_disabled.svg @@ -0,0 +1,143 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_line_of_sight.svg b/Z/src/nglwidgets/icons/svg/configure_line_of_sight.svg new file mode 100755 index 000000000..ac9518afc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_line_of_sight.svg @@ -0,0 +1,509 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_line_of_sight_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_line_of_sight_disabled.svg new file mode 100755 index 000000000..7b05ad00c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_line_of_sight_disabled.svg @@ -0,0 +1,184 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_symbol_attributes.svg b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes.svg new file mode 100755 index 000000000..d4831ad07 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_symbol_attributes_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes_disabled.svg new file mode 100755 index 000000000..53ddc1bc4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes_disabled.svg @@ -0,0 +1,144 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_tunnels.svg b/Z/src/nglwidgets/icons/svg/configure_tunnels.svg new file mode 100755 index 000000000..53fb4d258 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_tunnels.svg @@ -0,0 +1,498 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_tunnels_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_tunnels_disabled.svg new file mode 100755 index 000000000..3f8bb4cc1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_tunnels_disabled.svg @@ -0,0 +1,173 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_distance_measure.svg b/Z/src/nglwidgets/icons/svg/create_distance_measure.svg new file mode 100755 index 000000000..b88d6233d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_distance_measure.svg @@ -0,0 +1,470 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_distance_measure_disabled.svg b/Z/src/nglwidgets/icons/svg/create_distance_measure_disabled.svg new file mode 100755 index 000000000..2301c4cff --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_distance_measure_disabled.svg @@ -0,0 +1,142 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_evaluation_topic.svg b/Z/src/nglwidgets/icons/svg/create_evaluation_topic.svg new file mode 100755 index 000000000..6cd3fc562 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_evaluation_topic.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_image_topic.svg b/Z/src/nglwidgets/icons/svg/create_image_topic.svg new file mode 100755 index 000000000..7cd1bf70a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_image_topic.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_lecture_topic.svg b/Z/src/nglwidgets/icons/svg/create_lecture_topic.svg new file mode 100755 index 000000000..e08bcd0e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_lecture_topic.svg @@ -0,0 +1,470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_pdf_topic.svg b/Z/src/nglwidgets/icons/svg/create_pdf_topic.svg new file mode 100755 index 000000000..0eb493469 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_pdf_topic.svg @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_snapshot.svg b/Z/src/nglwidgets/icons/svg/create_snapshot.svg new file mode 100755 index 000000000..286d1c909 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_snapshot.svg @@ -0,0 +1,467 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_snapshot_disabled.svg b/Z/src/nglwidgets/icons/svg/create_snapshot_disabled.svg new file mode 100755 index 000000000..c087d179e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_snapshot_disabled.svg @@ -0,0 +1,147 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_terrain_profile.svg b/Z/src/nglwidgets/icons/svg/create_terrain_profile.svg new file mode 100755 index 000000000..41bd740a2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_terrain_profile.svg @@ -0,0 +1,433 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_terrain_profile_disabled.svg b/Z/src/nglwidgets/icons/svg/create_terrain_profile_disabled.svg new file mode 100755 index 000000000..64fb39ce8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_terrain_profile_disabled.svg @@ -0,0 +1,106 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_thp.svg b/Z/src/nglwidgets/icons/svg/create_thp.svg new file mode 100755 index 000000000..5159e00cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_thp.svg @@ -0,0 +1,430 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_thp_disabled.svg b/Z/src/nglwidgets/icons/svg/create_thp_disabled.svg new file mode 100755 index 000000000..cb2d24b1c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_thp_disabled.svg @@ -0,0 +1,105 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/danger_areas.svg b/Z/src/nglwidgets/icons/svg/danger_areas.svg new file mode 100755 index 000000000..73505ebb7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/danger_areas.svg @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/debug-execute-from-cursor.svg b/Z/src/nglwidgets/icons/svg/debug-execute-from-cursor.svg new file mode 100755 index 000000000..c93934070 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/debug-execute-from-cursor.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/debug-execute-to-cursor.svg b/Z/src/nglwidgets/icons/svg/debug-execute-to-cursor.svg new file mode 100755 index 000000000..6c5e5399e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/debug-execute-to-cursor.svg @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/default_operator_rights.svg b/Z/src/nglwidgets/icons/svg/default_operator_rights.svg new file mode 100755 index 000000000..a199a6a58 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/default_operator_rights.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/default_operator_rights_disabled.svg b/Z/src/nglwidgets/icons/svg/default_operator_rights_disabled.svg new file mode 100755 index 000000000..e93eeb358 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/default_operator_rights_disabled.svg @@ -0,0 +1,132 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_border_lines.svg b/Z/src/nglwidgets/icons/svg/define_border_lines.svg new file mode 100755 index 000000000..aa1c215d8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_border_lines.svg @@ -0,0 +1,499 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_border_lines_disabled.svg b/Z/src/nglwidgets/icons/svg/define_border_lines_disabled.svg new file mode 100755 index 000000000..1582a5846 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_border_lines_disabled.svg @@ -0,0 +1,172 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_force_templates.svg b/Z/src/nglwidgets/icons/svg/define_force_templates.svg new file mode 100755 index 000000000..1dabd3595 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_force_templates.svg @@ -0,0 +1,467 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_force_templates_disabled.svg b/Z/src/nglwidgets/icons/svg/define_force_templates_disabled.svg new file mode 100755 index 000000000..b23e3f59d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_force_templates_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_movement_simulation.svg b/Z/src/nglwidgets/icons/svg/define_movement_simulation.svg new file mode 100755 index 000000000..836d1d3a7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_movement_simulation.svg @@ -0,0 +1,500 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_movement_simulation_disabled.svg b/Z/src/nglwidgets/icons/svg/define_movement_simulation_disabled.svg new file mode 100755 index 000000000..01ea0b11c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_movement_simulation_disabled.svg @@ -0,0 +1,181 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_player_types.svg b/Z/src/nglwidgets/icons/svg/define_player_types.svg new file mode 100755 index 000000000..e02062869 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_player_types.svg @@ -0,0 +1,536 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_player_types_disabled.svg b/Z/src/nglwidgets/icons/svg/define_player_types_disabled.svg new file mode 100755 index 000000000..b7a4ac9ca --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_player_types_disabled.svg @@ -0,0 +1,213 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_position_system.svg b/Z/src/nglwidgets/icons/svg/define_position_system.svg new file mode 100755 index 000000000..797da2f2e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_position_system.svg @@ -0,0 +1,427 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_position_system_disabled.svg b/Z/src/nglwidgets/icons/svg/define_position_system_disabled.svg new file mode 100755 index 000000000..1243fba5d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_position_system_disabled.svg @@ -0,0 +1,99 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_presentation.svg b/Z/src/nglwidgets/icons/svg/define_presentation.svg new file mode 100755 index 000000000..5efcfc7b9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_presentation.svg @@ -0,0 +1,400 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_presentation_disabled.svg b/Z/src/nglwidgets/icons/svg/define_presentation_disabled.svg new file mode 100755 index 000000000..8f1ff705a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_presentation_disabled.svg @@ -0,0 +1,72 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_tactical_symbols.svg b/Z/src/nglwidgets/icons/svg/define_tactical_symbols.svg new file mode 100755 index 000000000..8489b1bd0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_tactical_symbols.svg @@ -0,0 +1,434 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_tactical_symbols_disabled.svg b/Z/src/nglwidgets/icons/svg/define_tactical_symbols_disabled.svg new file mode 100755 index 000000000..d9a9fac15 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_tactical_symbols_disabled.svg @@ -0,0 +1,103 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_teams.svg b/Z/src/nglwidgets/icons/svg/define_teams.svg new file mode 100755 index 000000000..285345d24 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_teams.svg @@ -0,0 +1,450 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_teams_disabled.svg b/Z/src/nglwidgets/icons/svg/define_teams_disabled.svg new file mode 100755 index 000000000..6cf2e9a19 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_teams_disabled.svg @@ -0,0 +1,120 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_training_cycles.svg b/Z/src/nglwidgets/icons/svg/define_training_cycles.svg new file mode 100755 index 000000000..6f568d894 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_training_cycles.svg @@ -0,0 +1,466 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_training_cycles_disabled.svg b/Z/src/nglwidgets/icons/svg/define_training_cycles_disabled.svg new file mode 100755 index 000000000..d4896dc8e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_training_cycles_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/delete_thp.svg b/Z/src/nglwidgets/icons/svg/delete_thp.svg new file mode 100755 index 000000000..404ad5adb --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/delete_thp.svg @@ -0,0 +1,424 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/delete_thp_disabled.svg b/Z/src/nglwidgets/icons/svg/delete_thp_disabled.svg new file mode 100755 index 000000000..28b971f04 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/delete_thp_disabled.svg @@ -0,0 +1,95 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/dialog-close.svg b/Z/src/nglwidgets/icons/svg/dialog-close.svg new file mode 100755 index 000000000..e3698bf46 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/dialog-close.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/dialog-ok-apply.svg b/Z/src/nglwidgets/icons/svg/dialog-ok-apply.svg new file mode 100755 index 000000000..2c681d099 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/dialog-ok-apply.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/dialog-ok.svg b/Z/src/nglwidgets/icons/svg/dialog-ok.svg new file mode 100755 index 000000000..2c681d099 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/dialog-ok.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_oc_evaluations.svg b/Z/src/nglwidgets/icons/svg/display_oc_evaluations.svg new file mode 100755 index 000000000..1b1827295 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_oc_evaluations.svg @@ -0,0 +1,403 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_oc_evaluations_disabled.svg b/Z/src/nglwidgets/icons/svg/display_oc_evaluations_disabled.svg new file mode 100755 index 000000000..54bf1d1bc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_oc_evaluations_disabled.svg @@ -0,0 +1,74 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_reports.svg b/Z/src/nglwidgets/icons/svg/display_reports.svg new file mode 100755 index 000000000..68c915df1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_reports.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_reports_disabled.svg b/Z/src/nglwidgets/icons/svg/display_reports_disabled.svg new file mode 100755 index 000000000..b7ccd6f7c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_reports_disabled.svg @@ -0,0 +1,96 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-edit.svg b/Z/src/nglwidgets/icons/svg/document-edit.svg new file mode 100755 index 000000000..7a8dcf427 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-edit.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-new.svg b/Z/src/nglwidgets/icons/svg/document-new.svg new file mode 100755 index 000000000..5a71e4180 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-new.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-open-data.svg b/Z/src/nglwidgets/icons/svg/document-open-data.svg new file mode 100755 index 000000000..7a092bb81 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-open-data.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-open.svg b/Z/src/nglwidgets/icons/svg/document-open.svg new file mode 100755 index 000000000..de55c507f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-open.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-properties.svg b/Z/src/nglwidgets/icons/svg/document-properties.svg new file mode 100755 index 000000000..b13f1af77 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-properties.svg @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/documents.svg b/Z/src/nglwidgets/icons/svg/documents.svg new file mode 100755 index 000000000..b59dd88af --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/documents.svg @@ -0,0 +1,417 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/documents_disabled.svg b/Z/src/nglwidgets/icons/svg/documents_disabled.svg new file mode 100755 index 000000000..9533e9eab --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/documents_disabled.svg @@ -0,0 +1,88 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/download.svg b/Z/src/nglwidgets/icons/svg/download.svg new file mode 100755 index 000000000..233f6a637 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/download.svg @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/draw-bezier-curves.svg b/Z/src/nglwidgets/icons/svg/draw-bezier-curves.svg new file mode 100755 index 000000000..5658841dc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/draw-bezier-curves.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/edit-cut.svg b/Z/src/nglwidgets/icons/svg/edit-cut.svg new file mode 100755 index 000000000..798bec2cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/edit-cut.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/edit_evaluation_marker.svg b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker.svg new file mode 100755 index 000000000..7a135b55a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker.svg @@ -0,0 +1,468 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/edit_evaluation_marker_disabled.svg b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker_disabled.svg new file mode 100755 index 000000000..aafb01c28 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker_disabled.svg @@ -0,0 +1,144 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/electronical_warfare_measures.svg b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures.svg new file mode 100755 index 000000000..78c9b3c77 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures.svg @@ -0,0 +1,488 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/electronical_warfare_measures_disabled.svg b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures_disabled.svg new file mode 100755 index 000000000..e80a8fd37 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures_disabled.svg @@ -0,0 +1,154 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluate.svg b/Z/src/nglwidgets/icons/svg/evaluate.svg new file mode 100755 index 000000000..788eb9616 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluate.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluate_disabled.svg b/Z/src/nglwidgets/icons/svg/evaluate_disabled.svg new file mode 100755 index 000000000..bbf8d9af3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluate_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluation_elements.svg b/Z/src/nglwidgets/icons/svg/evaluation_elements.svg new file mode 100755 index 000000000..2165fab2c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluation_elements.svg @@ -0,0 +1,441 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluation_elements_disabled.svg b/Z/src/nglwidgets/icons/svg/evaluation_elements_disabled.svg new file mode 100755 index 000000000..9cf604e12 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluation_elements_disabled.svg @@ -0,0 +1,115 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/execute_presentation.svg b/Z/src/nglwidgets/icons/svg/execute_presentation.svg new file mode 100755 index 000000000..0c402ae31 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/execute_presentation.svg @@ -0,0 +1,406 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/execute_presentation_disabled.svg b/Z/src/nglwidgets/icons/svg/execute_presentation_disabled.svg new file mode 100755 index 000000000..2d188ba40 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/execute_presentation_disabled.svg @@ -0,0 +1,78 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_force.svg b/Z/src/nglwidgets/icons/svg/exercise_force.svg new file mode 100755 index 000000000..64c7ca0e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_force.svg @@ -0,0 +1,429 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_force_disabled.svg b/Z/src/nglwidgets/icons/svg/exercise_force_disabled.svg new file mode 100755 index 000000000..489e516c3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_force_disabled.svg @@ -0,0 +1,103 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_purpose.svg b/Z/src/nglwidgets/icons/svg/exercise_purpose.svg new file mode 100755 index 000000000..3c9e513cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_purpose.svg @@ -0,0 +1,449 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_purpose_disabled.svg b/Z/src/nglwidgets/icons/svg/exercise_purpose_disabled.svg new file mode 100755 index 000000000..83760b523 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_purpose_disabled.svg @@ -0,0 +1,126 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/export_documents.svg b/Z/src/nglwidgets/icons/svg/export_documents.svg new file mode 100755 index 000000000..d9ea82218 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/export_documents.svg @@ -0,0 +1,409 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/export_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/export_documents_disabled.svg new file mode 100755 index 000000000..e2bb9b919 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/export_documents_disabled.svg @@ -0,0 +1,80 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/fill_pattern.svg b/Z/src/nglwidgets/icons/svg/fill_pattern.svg new file mode 100755 index 000000000..6ab4a527f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/fill_pattern.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_barriers.svg b/Z/src/nglwidgets/icons/svg/filter_barriers.svg new file mode 100755 index 000000000..0ff121de7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_barriers.svg @@ -0,0 +1,498 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_barriers_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_barriers_disabled.svg new file mode 100755 index 000000000..4bc951801 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_barriers_disabled.svg @@ -0,0 +1,178 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_border_lines.svg b/Z/src/nglwidgets/icons/svg/filter_border_lines.svg new file mode 100755 index 000000000..d7ffce356 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_border_lines.svg @@ -0,0 +1,475 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_border_lines_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_border_lines_disabled.svg new file mode 100755 index 000000000..7fec1b515 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_border_lines_disabled.svg @@ -0,0 +1,151 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_collapse_expand.svg b/Z/src/nglwidgets/icons/svg/filter_collapse_expand.svg new file mode 100755 index 000000000..39e5963a4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_collapse_expand.svg @@ -0,0 +1,434 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_collapse_expand_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_collapse_expand_disabled.svg new file mode 100755 index 000000000..097142d24 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_collapse_expand_disabled.svg @@ -0,0 +1,112 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_effect_simulation.svg b/Z/src/nglwidgets/icons/svg/filter_effect_simulation.svg new file mode 100755 index 000000000..27f4e0bee --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_effect_simulation.svg @@ -0,0 +1,494 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_effect_simulation_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_effect_simulation_disabled.svg new file mode 100755 index 000000000..258a5b9d8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_effect_simulation_disabled.svg @@ -0,0 +1,170 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_firings.svg b/Z/src/nglwidgets/icons/svg/filter_firings.svg new file mode 100755 index 000000000..1f714465f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_firings.svg @@ -0,0 +1,478 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_firings_disabled.svg new file mode 100755 index 000000000..9fc96185d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_firings_disabled.svg @@ -0,0 +1,154 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_line_of_sight.svg b/Z/src/nglwidgets/icons/svg/filter_line_of_sight.svg new file mode 100755 index 000000000..0283b392a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_line_of_sight.svg @@ -0,0 +1,444 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_line_of_sight_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_line_of_sight_disabled.svg new file mode 100755 index 000000000..9dffad910 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_line_of_sight_disabled.svg @@ -0,0 +1,115 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings.svg new file mode 100755 index 000000000..d32cc6b66 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings.svg @@ -0,0 +1,407 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings_disabled.svg new file mode 100755 index 000000000..faef4fedb --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings_disabled.svg @@ -0,0 +1,81 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings_load.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings_load.svg new file mode 100755 index 000000000..2466a4942 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings_load.svg @@ -0,0 +1,419 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings_load_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings_load_disabled.svg new file mode 100755 index 000000000..fd3921b75 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings_load_disabled.svg @@ -0,0 +1,93 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_maps_settings_save.svg b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save.svg new file mode 100755 index 000000000..54982a1c8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save.svg @@ -0,0 +1,420 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_maps_settings_save_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save_disabled.svg new file mode 100755 index 000000000..d78639de0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save_disabled.svg @@ -0,0 +1,97 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nbc_agents.svg b/Z/src/nglwidgets/icons/svg/filter_nbc_agents.svg new file mode 100755 index 000000000..0402593e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nbc_agents.svg @@ -0,0 +1,528 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nbc_agents_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_nbc_agents_disabled.svg new file mode 100755 index 000000000..fde679fb5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nbc_agents_disabled.svg @@ -0,0 +1,204 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nc_agents.svg b/Z/src/nglwidgets/icons/svg/filter_nc_agents.svg new file mode 100755 index 000000000..0a2015c26 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nc_agents.svg @@ -0,0 +1,484 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nc_agents_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_nc_agents_disabled.svg new file mode 100755 index 000000000..2f0173fdd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nc_agents_disabled.svg @@ -0,0 +1,159 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_player.svg b/Z/src/nglwidgets/icons/svg/filter_player.svg new file mode 100755 index 000000000..818e288f1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_player.svg @@ -0,0 +1,452 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_player_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_player_disabled.svg new file mode 100755 index 000000000..0e722297c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_player_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_teams.svg b/Z/src/nglwidgets/icons/svg/filter_teams.svg new file mode 100755 index 000000000..d6ab1be3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_teams.svg @@ -0,0 +1,471 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_teams_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_teams_disabled.svg new file mode 100755 index 000000000..96fe60c5a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_teams_disabled.svg @@ -0,0 +1,148 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/fixed_video_announcement.svg b/Z/src/nglwidgets/icons/svg/fixed_video_announcement.svg new file mode 100755 index 000000000..3999c20d4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/fixed_video_announcement.svg @@ -0,0 +1,450 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/fixed_video_announcement_disabled.svg b/Z/src/nglwidgets/icons/svg/fixed_video_announcement_disabled.svg new file mode 100755 index 000000000..fc9ad7879 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/fixed_video_announcement_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_composition.svg b/Z/src/nglwidgets/icons/svg/force_composition.svg new file mode 100755 index 000000000..759625f67 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_composition.svg @@ -0,0 +1,468 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_composition_disabled.svg b/Z/src/nglwidgets/icons/svg/force_composition_disabled.svg new file mode 100755 index 000000000..cd54fa9d2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_composition_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_organization.svg b/Z/src/nglwidgets/icons/svg/force_organization.svg new file mode 100755 index 000000000..22b51f6a1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_organization.svg @@ -0,0 +1,504 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_organization_disabled.svg b/Z/src/nglwidgets/icons/svg/force_organization_disabled.svg new file mode 100755 index 000000000..8e8646205 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_organization_disabled.svg @@ -0,0 +1,179 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_player_configuration.svg b/Z/src/nglwidgets/icons/svg/force_player_configuration.svg new file mode 100755 index 000000000..8ccaf9cc6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_player_configuration.svg @@ -0,0 +1,486 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_player_configuration_disabled.svg b/Z/src/nglwidgets/icons/svg/force_player_configuration_disabled.svg new file mode 100755 index 000000000..38883f44c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_player_configuration_disabled.svg @@ -0,0 +1,160 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/freq_plan.svg b/Z/src/nglwidgets/icons/svg/freq_plan.svg new file mode 100755 index 000000000..5172450d0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/freq_plan.svg @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/function_key_toolbar.svg b/Z/src/nglwidgets/icons/svg/function_key_toolbar.svg new file mode 100755 index 000000000..959045201 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/function_key_toolbar.svg @@ -0,0 +1,463 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/function_key_toolbar_disabled.svg b/Z/src/nglwidgets/icons/svg/function_key_toolbar_disabled.svg new file mode 100755 index 000000000..d1e8b0f29 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/function_key_toolbar_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/getpos.svg b/Z/src/nglwidgets/icons/svg/getpos.svg new file mode 100755 index 000000000..8b1d4621d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/getpos.svg @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_alarms_history.svg b/Z/src/nglwidgets/icons/svg/global_alarms_history.svg new file mode 100755 index 000000000..39c4b0e50 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_alarms_history.svg @@ -0,0 +1,450 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_alarms_history_disabled.svg b/Z/src/nglwidgets/icons/svg/global_alarms_history_disabled.svg new file mode 100755 index 000000000..d0c11b8ff --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_alarms_history_disabled.svg @@ -0,0 +1,122 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_exercise_settings.svg b/Z/src/nglwidgets/icons/svg/global_exercise_settings.svg new file mode 100755 index 000000000..a6b236c73 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_exercise_settings.svg @@ -0,0 +1,480 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_exercise_settings_disabled.svg b/Z/src/nglwidgets/icons/svg/global_exercise_settings_disabled.svg new file mode 100755 index 000000000..358d3cad5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_exercise_settings_disabled.svg @@ -0,0 +1,158 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/go-home.svg b/Z/src/nglwidgets/icons/svg/go-home.svg new file mode 100755 index 000000000..cae4a4c97 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/go-home.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/hand_grenade_locations.svg b/Z/src/nglwidgets/icons/svg/hand_grenade_locations.svg new file mode 100755 index 000000000..def8e416a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/hand_grenade_locations.svg @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/help_index.svg b/Z/src/nglwidgets/icons/svg/help_index.svg new file mode 100755 index 000000000..396b9af7c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/help_index.svg @@ -0,0 +1,451 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/help_index_disabled.svg b/Z/src/nglwidgets/icons/svg/help_index_disabled.svg new file mode 100755 index 000000000..1b7540b97 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/help_index_disabled.svg @@ -0,0 +1,122 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_buildings.svg b/Z/src/nglwidgets/icons/svg/import_buildings.svg new file mode 100755 index 000000000..d3e4d2450 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_buildings.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_buildings_disabled.svg b/Z/src/nglwidgets/icons/svg/import_buildings_disabled.svg new file mode 100755 index 000000000..af3fe8254 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_buildings_disabled.svg @@ -0,0 +1,94 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_documents.svg b/Z/src/nglwidgets/icons/svg/import_documents.svg new file mode 100755 index 000000000..a7c09ea2e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_documents.svg @@ -0,0 +1,422 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/import_documents_disabled.svg new file mode 100755 index 000000000..c51c78925 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_documents_disabled.svg @@ -0,0 +1,94 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_images.svg b/Z/src/nglwidgets/icons/svg/import_images.svg new file mode 100755 index 000000000..98ee0b751 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_images.svg @@ -0,0 +1,417 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_images_disabled.svg b/Z/src/nglwidgets/icons/svg/import_images_disabled.svg new file mode 100755 index 000000000..e3a30e6d2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_images_disabled.svg @@ -0,0 +1,90 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_msdl.svg b/Z/src/nglwidgets/icons/svg/import_msdl.svg new file mode 100755 index 000000000..5be893182 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_msdl.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_pdf_document.svg b/Z/src/nglwidgets/icons/svg/import_pdf_document.svg new file mode 100755 index 000000000..1fde92f8d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_pdf_document.svg @@ -0,0 +1,457 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_pdf_document_disabled.svg b/Z/src/nglwidgets/icons/svg/import_pdf_document_disabled.svg new file mode 100755 index 000000000..e42178c28 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_pdf_document_disabled.svg @@ -0,0 +1,132 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_video.svg b/Z/src/nglwidgets/icons/svg/import_video.svg new file mode 100755 index 000000000..b09ac659c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_video.svg @@ -0,0 +1,478 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_video_disabled.svg b/Z/src/nglwidgets/icons/svg/import_video_disabled.svg new file mode 100755 index 000000000..b4689be38 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_video_disabled.svg @@ -0,0 +1,153 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/insert_script.svg b/Z/src/nglwidgets/icons/svg/insert_script.svg new file mode 100755 index 000000000..243a82fb6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/insert_script.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/karte.svg b/Z/src/nglwidgets/icons/svg/karte.svg new file mode 100755 index 000000000..69e51c878 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/karte.svg @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/layer.svg b/Z/src/nglwidgets/icons/svg/layer.svg new file mode 100755 index 000000000..cae1fb22c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/layer.svg @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/line_styles.svg b/Z/src/nglwidgets/icons/svg/line_styles.svg new file mode 100755 index 000000000..864bb84c2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/line_styles.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/list-add-user.svg b/Z/src/nglwidgets/icons/svg/list-add-user.svg new file mode 100755 index 000000000..c63462dc0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/list-add-user.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/list-remove-user.svg b/Z/src/nglwidgets/icons/svg/list-remove-user.svg new file mode 100755 index 000000000..47295b88f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/list-remove-user.svg @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load.svg b/Z/src/nglwidgets/icons/svg/load.svg new file mode 100755 index 000000000..a40090801 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load.svg @@ -0,0 +1,392 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load_disabled.svg b/Z/src/nglwidgets/icons/svg/load_disabled.svg new file mode 100755 index 000000000..896263881 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load_disabled.svg @@ -0,0 +1,67 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load_global_filter.svg b/Z/src/nglwidgets/icons/svg/load_global_filter.svg new file mode 100755 index 000000000..a85ad746d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load_global_filter.svg @@ -0,0 +1,456 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load_global_filter_disabled.svg b/Z/src/nglwidgets/icons/svg/load_global_filter_disabled.svg new file mode 100755 index 000000000..b897c0f2a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load_global_filter_disabled.svg @@ -0,0 +1,136 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/logout.svg b/Z/src/nglwidgets/icons/svg/logout.svg new file mode 100755 index 000000000..748ce863e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/logout.svg @@ -0,0 +1,413 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/logout_disabled.svg b/Z/src/nglwidgets/icons/svg/logout_disabled.svg new file mode 100755 index 000000000..394252888 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/logout_disabled.svg @@ -0,0 +1,85 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_context_menu.svg b/Z/src/nglwidgets/icons/svg/map_context_menu.svg new file mode 100755 index 000000000..ad81403ee --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_context_menu.svg @@ -0,0 +1,487 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_context_menu_disabled.svg b/Z/src/nglwidgets/icons/svg/map_context_menu_disabled.svg new file mode 100755 index 000000000..761740631 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_context_menu_disabled.svg @@ -0,0 +1,143 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_settings.svg b/Z/src/nglwidgets/icons/svg/map_settings.svg new file mode 100755 index 000000000..859ba8d7d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_settings.svg @@ -0,0 +1,484 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_settings_disabled.svg b/Z/src/nglwidgets/icons/svg/map_settings_disabled.svg new file mode 100755 index 000000000..b2c1fd635 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_settings_disabled.svg @@ -0,0 +1,161 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/marke.svg b/Z/src/nglwidgets/icons/svg/marke.svg new file mode 100755 index 000000000..5cb3964a7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/marke.svg @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/marker-end.svg b/Z/src/nglwidgets/icons/svg/marker-end.svg new file mode 100755 index 000000000..7d65e0a79 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/marker-end.svg @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/marker-start.svg b/Z/src/nglwidgets/icons/svg/marker-start.svg new file mode 100755 index 000000000..d6a261122 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/marker-start.svg @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-flash.svg b/Z/src/nglwidgets/icons/svg/media-flash.svg new file mode 100755 index 000000000..70d4d1498 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-flash.svg @@ -0,0 +1,375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-play-backward.svg b/Z/src/nglwidgets/icons/svg/media-play-backward.svg new file mode 100755 index 000000000..c0c472b4b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-play-backward.svg @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-play-slower.svg b/Z/src/nglwidgets/icons/svg/media-play-slower.svg new file mode 100755 index 000000000..05c5a74fc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-play-slower.svg @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-record.svg b/Z/src/nglwidgets/icons/svg/media-record.svg new file mode 100755 index 000000000..cdaaaa8c6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-record.svg @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-seek-backward.svg b/Z/src/nglwidgets/icons/svg/media-seek-backward.svg new file mode 100755 index 000000000..56f4fe98a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-seek-backward.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-seek-forward.svg b/Z/src/nglwidgets/icons/svg/media-seek-forward.svg new file mode 100755 index 000000000..6af8a834b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-seek-forward.svg @@ -0,0 +1,375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-skip-backward.svg b/Z/src/nglwidgets/icons/svg/media-skip-backward.svg new file mode 100755 index 000000000..7d3182cc3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-skip-backward.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-skip-forward.svg b/Z/src/nglwidgets/icons/svg/media-skip-forward.svg new file mode 100755 index 000000000..91128d7e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-skip-forward.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-vcr-nopause.svg b/Z/src/nglwidgets/icons/svg/media-vcr-nopause.svg new file mode 100755 index 000000000..0dafe612e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-vcr-nopause.svg @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-vcr-normal.svg b/Z/src/nglwidgets/icons/svg/media-vcr-normal.svg new file mode 100755 index 000000000..a18310292 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-vcr-normal.svg @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-vcr-withpause.svg b/Z/src/nglwidgets/icons/svg/media-vcr-withpause.svg new file mode 100755 index 000000000..cc971c920 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-vcr-withpause.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/messages.svg b/Z/src/nglwidgets/icons/svg/messages.svg new file mode 100755 index 000000000..3bf65baed --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/messages.svg @@ -0,0 +1,391 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/messages_disabled.svg b/Z/src/nglwidgets/icons/svg/messages_disabled.svg new file mode 100755 index 000000000..726a2cf4c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/messages_disabled.svg @@ -0,0 +1,65 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/metereological_data.svg b/Z/src/nglwidgets/icons/svg/metereological_data.svg new file mode 100755 index 000000000..9ab1ba594 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/metereological_data.svg @@ -0,0 +1,417 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/metereological_data_disabled.svg b/Z/src/nglwidgets/icons/svg/metereological_data_disabled.svg new file mode 100755 index 000000000..e94331f77 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/metereological_data_disabled.svg @@ -0,0 +1,91 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mgrs_grid.svg b/Z/src/nglwidgets/icons/svg/mgrs_grid.svg new file mode 100755 index 000000000..64de9363d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mgrs_grid.svg @@ -0,0 +1,504 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mgrs_grid_disabled.svg b/Z/src/nglwidgets/icons/svg/mgrs_grid_disabled.svg new file mode 100755 index 000000000..da7a521e2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mgrs_grid_disabled.svg @@ -0,0 +1,178 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barrier_corridor.svg b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor.svg new file mode 100755 index 000000000..a3318771c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor.svg @@ -0,0 +1,485 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barrier_corridor_disabled.svg b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor_disabled.svg new file mode 100755 index 000000000..e3dc437d3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor_disabled.svg @@ -0,0 +1,161 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barriers.svg b/Z/src/nglwidgets/icons/svg/mine_barriers.svg new file mode 100755 index 000000000..487111f2a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barriers.svg @@ -0,0 +1,490 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barriers_disabled.svg b/Z/src/nglwidgets/icons/svg/mine_barriers_disabled.svg new file mode 100755 index 000000000..6336466db --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barriers_disabled.svg @@ -0,0 +1,169 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mini_map.svg b/Z/src/nglwidgets/icons/svg/mini_map.svg new file mode 100755 index 000000000..5abd748c7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mini_map.svg @@ -0,0 +1,514 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mini_map_disabled.svg b/Z/src/nglwidgets/icons/svg/mini_map_disabled.svg new file mode 100755 index 000000000..6ecf294bd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mini_map_disabled.svg @@ -0,0 +1,191 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mlvs_control.svg b/Z/src/nglwidgets/icons/svg/mlvs_control.svg new file mode 100755 index 000000000..0c091060c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mlvs_control.svg @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mobile_video.svg b/Z/src/nglwidgets/icons/svg/mobile_video.svg new file mode 100755 index 000000000..7a8c5e5ab --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mobile_video.svg @@ -0,0 +1,409 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mobile_video_disabled.svg b/Z/src/nglwidgets/icons/svg/mobile_video_disabled.svg new file mode 100755 index 000000000..3cf44de7a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mobile_video_disabled.svg @@ -0,0 +1,82 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration.svg new file mode 100755 index 000000000..a92e7a999 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration.svg @@ -0,0 +1,440 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration_disabled.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration_disabled.svg new file mode 100755 index 000000000..07431ac94 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration_disabled.svg @@ -0,0 +1,111 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings.svg new file mode 100755 index 000000000..649beca11 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings.svg @@ -0,0 +1,474 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings_disabled.svg new file mode 100755 index 000000000..948e0dcbc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings_disabled.svg @@ -0,0 +1,145 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/network-wireless.svg b/Z/src/nglwidgets/icons/svg/network-wireless.svg new file mode 100755 index 000000000..3dcc638fe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/network-wireless.svg @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/new_documents.svg b/Z/src/nglwidgets/icons/svg/new_documents.svg new file mode 100755 index 000000000..e88f5a1d5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/new_documents.svg @@ -0,0 +1,885 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Z/src/nglwidgets/icons/svg/new_mail_indicator.svg b/Z/src/nglwidgets/icons/svg/new_mail_indicator.svg new file mode 100755 index 000000000..d759edd43 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/new_mail_indicator.svg @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/nuclear_agents.svg b/Z/src/nglwidgets/icons/svg/nuclear_agents.svg new file mode 100755 index 000000000..2dc41ba3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/nuclear_agents.svg @@ -0,0 +1,422 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/object-group.svg b/Z/src/nglwidgets/icons/svg/object-group.svg new file mode 100755 index 000000000..f82c93259 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/object-group.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/object-ungroup.svg b/Z/src/nglwidgets/icons/svg/object-ungroup.svg new file mode 100755 index 000000000..606246f1e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/object-ungroup.svg @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/objects_define_areas.svg b/Z/src/nglwidgets/icons/svg/objects_define_areas.svg new file mode 100755 index 000000000..36d137071 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/objects_define_areas.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/objects_define_areas_disabled.svg b/Z/src/nglwidgets/icons/svg/objects_define_areas_disabled.svg new file mode 100755 index 000000000..32ace712c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/objects_define_areas_disabled.svg @@ -0,0 +1,139 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_aar_preparation.svg b/Z/src/nglwidgets/icons/svg/oc_aar_preparation.svg new file mode 100755 index 000000000..ee39e7696 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_aar_preparation.svg @@ -0,0 +1,421 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_aar_preparation_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_aar_preparation_disabled.svg new file mode 100755 index 000000000..f9a2d977d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_aar_preparation_disabled.svg @@ -0,0 +1,94 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_composition.svg b/Z/src/nglwidgets/icons/svg/oc_composition.svg new file mode 100755 index 000000000..6080fd7fe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_composition.svg @@ -0,0 +1,479 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_composition_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_composition_disabled.svg new file mode 100755 index 000000000..1c1dfcb21 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_composition_disabled.svg @@ -0,0 +1,154 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes.svg b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes.svg new file mode 100755 index 000000000..3890ab265 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes.svg @@ -0,0 +1,457 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes_disabled.svg new file mode 100755 index 000000000..9f87bc67a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes_disabled.svg @@ -0,0 +1,135 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_player_configuration.svg b/Z/src/nglwidgets/icons/svg/oc_player_configuration.svg new file mode 100755 index 000000000..5a1963853 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_player_configuration.svg @@ -0,0 +1,488 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_player_configuration_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_player_configuration_disabled.svg new file mode 100755 index 000000000..2aa674fe3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_player_configuration_disabled.svg @@ -0,0 +1,163 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/operator_administration.svg b/Z/src/nglwidgets/icons/svg/operator_administration.svg new file mode 100755 index 000000000..3d335eed6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/operator_administration.svg @@ -0,0 +1,458 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/operator_administration_disabled.svg b/Z/src/nglwidgets/icons/svg/operator_administration_disabled.svg new file mode 100755 index 000000000..2d1a62843 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/operator_administration_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_documents.svg b/Z/src/nglwidgets/icons/svg/organize_documents.svg new file mode 100755 index 000000000..38cb93d56 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_documents.svg @@ -0,0 +1,420 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/organize_documents_disabled.svg new file mode 100755 index 000000000..0ce4eb0f5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_documents_disabled.svg @@ -0,0 +1,95 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_library.svg b/Z/src/nglwidgets/icons/svg/organize_library.svg new file mode 100755 index 000000000..3e1983811 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_library.svg @@ -0,0 +1,467 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_library_disabled.svg b/Z/src/nglwidgets/icons/svg/organize_library_disabled.svg new file mode 100755 index 000000000..e3037438d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_library_disabled.svg @@ -0,0 +1,151 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/overlay_plans.svg b/Z/src/nglwidgets/icons/svg/overlay_plans.svg new file mode 100755 index 000000000..22fd90fc7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/overlay_plans.svg @@ -0,0 +1,442 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/overlay_plans_disabled.svg b/Z/src/nglwidgets/icons/svg/overlay_plans_disabled.svg new file mode 100755 index 000000000..74067a9f0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/overlay_plans_disabled.svg @@ -0,0 +1,115 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/overlays.svg b/Z/src/nglwidgets/icons/svg/overlays.svg new file mode 100755 index 000000000..85a487c94 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/overlays.svg @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/phase_def.svg b/Z/src/nglwidgets/icons/svg/phase_def.svg new file mode 100755 index 000000000..430caed90 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/phase_def.svg @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_collapse.svg b/Z/src/nglwidgets/icons/svg/pi_force_collapse.svg new file mode 100755 index 000000000..76dae5f14 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_collapse.svg @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_expand.svg b/Z/src/nglwidgets/icons/svg/pi_force_expand.svg new file mode 100755 index 000000000..3780ee97c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_expand.svg @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_left.svg b/Z/src/nglwidgets/icons/svg/pi_force_left.svg new file mode 100755 index 000000000..8c1c1764c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_left.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_right.svg b/Z/src/nglwidgets/icons/svg/pi_force_right.svg new file mode 100755 index 000000000..f96098ff6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_right.svg @@ -0,0 +1,387 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_markup_3d.svg b/Z/src/nglwidgets/icons/svg/pi_markup_3d.svg new file mode 100755 index 000000000..4301cc243 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_markup_3d.svg @@ -0,0 +1,407 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_movementtrack.svg b/Z/src/nglwidgets/icons/svg/pi_movementtrack.svg new file mode 100755 index 000000000..b1f833788 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_movementtrack.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_nbc.svg b/Z/src/nglwidgets/icons/svg/pi_nbc.svg new file mode 100755 index 000000000..7bea5715f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_nbc.svg @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_set_player_mode.svg b/Z/src/nglwidgets/icons/svg/pi_set_player_mode.svg new file mode 100755 index 000000000..99419e6f9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_set_player_mode.svg @@ -0,0 +1,401 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_show_bite.svg b/Z/src/nglwidgets/icons/svg/pi_show_bite.svg new file mode 100755 index 000000000..7eed0bec3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_show_bite.svg @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_show_building.svg b/Z/src/nglwidgets/icons/svg/pi_show_building.svg new file mode 100755 index 000000000..ba8ea62e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_show_building.svg @@ -0,0 +1,472 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_tact_status_history.svg b/Z/src/nglwidgets/icons/svg/pi_tact_status_history.svg new file mode 100755 index 000000000..0a6074d3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_tact_status_history.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_type_weaponrange.svg b/Z/src/nglwidgets/icons/svg/pi_type_weaponrange.svg new file mode 100755 index 000000000..4dce0e5b5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_type_weaponrange.svg @@ -0,0 +1,752 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/planned_training_cycles.svg b/Z/src/nglwidgets/icons/svg/planned_training_cycles.svg new file mode 100755 index 000000000..611fa0bcc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/planned_training_cycles.svg @@ -0,0 +1,404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/plans.svg b/Z/src/nglwidgets/icons/svg/plans.svg new file mode 100755 index 000000000..933ebedd3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/plans.svg @@ -0,0 +1,410 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/plans_disabled.svg b/Z/src/nglwidgets/icons/svg/plans_disabled.svg new file mode 100755 index 000000000..e96bf9bb4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/plans_disabled.svg @@ -0,0 +1,81 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_audio.svg b/Z/src/nglwidgets/icons/svg/playback_audio.svg new file mode 100755 index 000000000..a9e152c2e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_audio.svg @@ -0,0 +1,426 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_audio_disabled.svg b/Z/src/nglwidgets/icons/svg/playback_audio_disabled.svg new file mode 100755 index 000000000..f351f8dbc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_audio_disabled.svg @@ -0,0 +1,100 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_situation.svg b/Z/src/nglwidgets/icons/svg/playback_situation.svg new file mode 100755 index 000000000..560613519 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_situation.svg @@ -0,0 +1,413 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_situation_disabled.svg b/Z/src/nglwidgets/icons/svg/playback_situation_disabled.svg new file mode 100755 index 000000000..62bc4696e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_situation_disabled.svg @@ -0,0 +1,87 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_video.svg b/Z/src/nglwidgets/icons/svg/playback_video.svg new file mode 100755 index 000000000..2acb360cf --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_video.svg @@ -0,0 +1,427 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_video_disabled.svg b/Z/src/nglwidgets/icons/svg/playback_video_disabled.svg new file mode 100755 index 000000000..2bf0300c4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_video_disabled.svg @@ -0,0 +1,101 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/player_equipment.svg b/Z/src/nglwidgets/icons/svg/player_equipment.svg new file mode 100755 index 000000000..02314867d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_equipment.svg @@ -0,0 +1,675 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Z/src/nglwidgets/icons/svg/player_equipment_check.svg b/Z/src/nglwidgets/icons/svg/player_equipment_check.svg new file mode 100755 index 000000000..37bcd9621 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_equipment_check.svg @@ -0,0 +1,425 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/player_equipment_check_disabled.svg b/Z/src/nglwidgets/icons/svg/player_equipment_check_disabled.svg new file mode 100755 index 000000000..caa410bd1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_equipment_check_disabled.svg @@ -0,0 +1,96 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/player_mode.svg b/Z/src/nglwidgets/icons/svg/player_mode.svg new file mode 100755 index 000000000..a64c09845 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_mode.svg @@ -0,0 +1,647 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Z/src/nglwidgets/icons/svg/preferences-web-browser-cache.svg b/Z/src/nglwidgets/icons/svg/preferences-web-browser-cache.svg new file mode 100755 index 000000000..604c98f8e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/preferences-web-browser-cache.svg @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/prepare_thp.svg b/Z/src/nglwidgets/icons/svg/prepare_thp.svg new file mode 100755 index 000000000..3bb0d4c83 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/prepare_thp.svg @@ -0,0 +1,452 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/prepare_thp_disabled.svg b/Z/src/nglwidgets/icons/svg/prepare_thp_disabled.svg new file mode 100755 index 000000000..500cf6039 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/prepare_thp_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/presets.svg b/Z/src/nglwidgets/icons/svg/presets.svg new file mode 100755 index 000000000..cced0bf24 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/presets.svg @@ -0,0 +1,476 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/presets_disabled.svg b/Z/src/nglwidgets/icons/svg/presets_disabled.svg new file mode 100755 index 000000000..8916051fd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/presets_disabled.svg @@ -0,0 +1,153 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_position.svg b/Z/src/nglwidgets/icons/svg/primary_map_position.svg new file mode 100755 index 000000000..1ac777b52 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_position.svg @@ -0,0 +1,407 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_position_disabled.svg b/Z/src/nglwidgets/icons/svg/primary_map_position_disabled.svg new file mode 100755 index 000000000..f50c3151b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_position_disabled.svg @@ -0,0 +1,81 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_toolbar.svg b/Z/src/nglwidgets/icons/svg/primary_map_toolbar.svg new file mode 100755 index 000000000..0cc2d8dab --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_toolbar.svg @@ -0,0 +1,448 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_toolbar_disabled.svg b/Z/src/nglwidgets/icons/svg/primary_map_toolbar_disabled.svg new file mode 100755 index 000000000..555468128 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_toolbar_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/proj_audio.svg b/Z/src/nglwidgets/icons/svg/proj_audio.svg new file mode 100755 index 000000000..7c39f53b1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/proj_audio.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/projection.svg b/Z/src/nglwidgets/icons/svg/projection.svg new file mode 100755 index 000000000..908755ff8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/projection.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/raster.svg b/Z/src/nglwidgets/icons/svg/raster.svg new file mode 100755 index 000000000..fcc4dce46 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/raster.svg @@ -0,0 +1,390 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/raster_disabled.svg b/Z/src/nglwidgets/icons/svg/raster_disabled.svg new file mode 100755 index 000000000..8113f995a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/raster_disabled.svg @@ -0,0 +1,68 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_left.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_left.svg new file mode 100755 index 000000000..15dce8e84 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_left.svg @@ -0,0 +1,431 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_left_disabled.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_left_disabled.svg new file mode 100755 index 000000000..baccaa1d8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_left_disabled.svg @@ -0,0 +1,107 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_resupply.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply.svg new file mode 100755 index 000000000..16d992ea0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply.svg @@ -0,0 +1,502 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_resupply_disabled.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply_disabled.svg new file mode 100755 index 000000000..98b7f8af3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply_disabled.svg @@ -0,0 +1,179 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_awes.svg b/Z/src/nglwidgets/icons/svg/report_awes.svg new file mode 100755 index 000000000..d4cd4eb63 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_awes.svg @@ -0,0 +1,493 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_awes_disabled.svg b/Z/src/nglwidgets/icons/svg/report_awes_disabled.svg new file mode 100755 index 000000000..e42b699a0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_awes_disabled.svg @@ -0,0 +1,168 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_effectiveness.svg b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness.svg new file mode 100755 index 000000000..92a74f79c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness.svg @@ -0,0 +1,480 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_effectiveness_disabled.svg b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness_disabled.svg new file mode 100755 index 000000000..5e51749a8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness_disabled.svg @@ -0,0 +1,155 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_power.svg b/Z/src/nglwidgets/icons/svg/report_combat_power.svg new file mode 100755 index 000000000..45f2beb59 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_power.svg @@ -0,0 +1,494 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_power_disabled.svg b/Z/src/nglwidgets/icons/svg/report_combat_power_disabled.svg new file mode 100755 index 000000000..a633d678e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_power_disabled.svg @@ -0,0 +1,168 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_explosive_devices.svg b/Z/src/nglwidgets/icons/svg/report_explosive_devices.svg new file mode 100755 index 000000000..998c8b761 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_explosive_devices.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_explosive_devices_disabled.svg b/Z/src/nglwidgets/icons/svg/report_explosive_devices_disabled.svg new file mode 100755 index 000000000..271ece621 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_explosive_devices_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_maintenance.svg b/Z/src/nglwidgets/icons/svg/report_maintenance.svg new file mode 100755 index 000000000..39fbaccd2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_maintenance.svg @@ -0,0 +1,432 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_maintenance_disabled.svg b/Z/src/nglwidgets/icons/svg/report_maintenance_disabled.svg new file mode 100755 index 000000000..c20f42e8f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_maintenance_disabled.svg @@ -0,0 +1,108 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mine_barrier.svg b/Z/src/nglwidgets/icons/svg/report_mine_barrier.svg new file mode 100755 index 000000000..e811b87cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mine_barrier.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mine_barrier_disabled.svg b/Z/src/nglwidgets/icons/svg/report_mine_barrier_disabled.svg new file mode 100755 index 000000000..89fd37a38 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mine_barrier_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mortar_firings.svg b/Z/src/nglwidgets/icons/svg/report_mortar_firings.svg new file mode 100755 index 000000000..d98602720 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mortar_firings.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mortar_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/report_mortar_firings_disabled.svg new file mode 100755 index 000000000..37b454005 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mortar_firings_disabled.svg @@ -0,0 +1,135 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nbc_events.svg b/Z/src/nglwidgets/icons/svg/report_nbc_events.svg new file mode 100755 index 000000000..2e767babd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nbc_events.svg @@ -0,0 +1,493 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nbc_events_disabled.svg b/Z/src/nglwidgets/icons/svg/report_nbc_events_disabled.svg new file mode 100755 index 000000000..d04d44f0f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nbc_events_disabled.svg @@ -0,0 +1,170 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nc_events.svg b/Z/src/nglwidgets/icons/svg/report_nc_events.svg new file mode 100755 index 000000000..c37190392 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nc_events.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nc_events_disabled.svg b/Z/src/nglwidgets/icons/svg/report_nc_events_disabled.svg new file mode 100755 index 000000000..157345f39 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nc_events_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatment.svg b/Z/src/nglwidgets/icons/svg/report_treatment.svg new file mode 100755 index 000000000..35c5b843b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatment.svg @@ -0,0 +1,449 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatment_disabled.svg b/Z/src/nglwidgets/icons/svg/report_treatment_disabled.svg new file mode 100755 index 000000000..2e3233a9a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatment_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance.svg b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance.svg new file mode 100755 index 000000000..5d24dbf0e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance.svg @@ -0,0 +1,460 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance_disabled.svg b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance_disabled.svg new file mode 100755 index 000000000..6ac9da8fd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance_disabled.svg @@ -0,0 +1,136 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/save_preferences.svg b/Z/src/nglwidgets/icons/svg/save_preferences.svg new file mode 100755 index 000000000..be9ac7655 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/save_preferences.svg @@ -0,0 +1,468 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/save_preferences_disabled.svg b/Z/src/nglwidgets/icons/svg/save_preferences_disabled.svg new file mode 100755 index 000000000..ef52c1173 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/save_preferences_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/screenshot.svg b/Z/src/nglwidgets/icons/svg/screenshot.svg new file mode 100755 index 000000000..908f73cdd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/screenshot.svg @@ -0,0 +1,398 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/screenshot_disabled.svg b/Z/src/nglwidgets/icons/svg/screenshot_disabled.svg new file mode 100755 index 000000000..c17f1f486 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/screenshot_disabled.svg @@ -0,0 +1,71 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_position.svg b/Z/src/nglwidgets/icons/svg/secondary_map_position.svg new file mode 100755 index 000000000..76b0d6ae3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_position.svg @@ -0,0 +1,420 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_position_disabled.svg b/Z/src/nglwidgets/icons/svg/secondary_map_position_disabled.svg new file mode 100755 index 000000000..5f47cc1ad --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_position_disabled.svg @@ -0,0 +1,96 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_toolbar.svg b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar.svg new file mode 100755 index 000000000..bc52549c3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_toolbar_disabled.svg b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar_disabled.svg new file mode 100755 index 000000000..deee01088 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_player.svg b/Z/src/nglwidgets/icons/svg/select_player.svg new file mode 100755 index 000000000..686e0d60d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_player.svg @@ -0,0 +1,474 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_player_disabled.svg b/Z/src/nglwidgets/icons/svg/select_player_disabled.svg new file mode 100755 index 000000000..afd5a48e5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_player_disabled.svg @@ -0,0 +1,159 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_areas.svg b/Z/src/nglwidgets/icons/svg/select_training_areas.svg new file mode 100755 index 000000000..f7d853b9c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_areas.svg @@ -0,0 +1,404 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_areas_disabled.svg b/Z/src/nglwidgets/icons/svg/select_training_areas_disabled.svg new file mode 100755 index 000000000..a7270398d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_areas_disabled.svg @@ -0,0 +1,77 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_cylces.svg b/Z/src/nglwidgets/icons/svg/select_training_cylces.svg new file mode 100755 index 000000000..d0c8d0c66 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_cylces.svg @@ -0,0 +1,442 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_cylces_disabled.svg b/Z/src/nglwidgets/icons/svg/select_training_cylces_disabled.svg new file mode 100755 index 000000000..5796cbcf5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_cylces_disabled.svg @@ -0,0 +1,114 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/send_player_message.svg b/Z/src/nglwidgets/icons/svg/send_player_message.svg new file mode 100755 index 000000000..fc451da51 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/send_player_message.svg @@ -0,0 +1,419 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/send_player_message_disabled.svg b/Z/src/nglwidgets/icons/svg/send_player_message_disabled.svg new file mode 100755 index 000000000..b03460762 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/send_player_message_disabled.svg @@ -0,0 +1,92 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_exercise_process.svg b/Z/src/nglwidgets/icons/svg/set_exercise_process.svg new file mode 100755 index 000000000..cb9db79e4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_exercise_process.svg @@ -0,0 +1,485 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_exercise_process_disabled.svg b/Z/src/nglwidgets/icons/svg/set_exercise_process_disabled.svg new file mode 100755 index 000000000..719db3855 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_exercise_process_disabled.svg @@ -0,0 +1,161 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_force_visibility.svg b/Z/src/nglwidgets/icons/svg/set_force_visibility.svg new file mode 100755 index 000000000..e9a9dd76c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_force_visibility.svg @@ -0,0 +1,477 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_force_visibility_disabled.svg b/Z/src/nglwidgets/icons/svg/set_force_visibility_disabled.svg new file mode 100755 index 000000000..cd63475a7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_force_visibility_disabled.svg @@ -0,0 +1,149 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_home_transparency.svg b/Z/src/nglwidgets/icons/svg/set_home_transparency.svg new file mode 100755 index 000000000..f5f87f569 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_home_transparency.svg @@ -0,0 +1,444 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_home_transparency_disabled.svg b/Z/src/nglwidgets/icons/svg/set_home_transparency_disabled.svg new file mode 100755 index 000000000..7c9712df8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_home_transparency_disabled.svg @@ -0,0 +1,119 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_situation.svg b/Z/src/nglwidgets/icons/svg/set_marker_situation.svg new file mode 100755 index 000000000..8687617f0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_situation.svg @@ -0,0 +1,445 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_situation_disabled.svg b/Z/src/nglwidgets/icons/svg/set_marker_situation_disabled.svg new file mode 100755 index 000000000..ea9574219 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_situation_disabled.svg @@ -0,0 +1,126 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_video.svg b/Z/src/nglwidgets/icons/svg/set_marker_video.svg new file mode 100755 index 000000000..def00415c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_video.svg @@ -0,0 +1,474 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_video_disabled.svg b/Z/src/nglwidgets/icons/svg/set_marker_video_disabled.svg new file mode 100755 index 000000000..7083a66e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_video_disabled.svg @@ -0,0 +1,155 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_markers_audio.svg b/Z/src/nglwidgets/icons/svg/set_markers_audio.svg new file mode 100755 index 000000000..49738a3aa --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_markers_audio.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_markers_audio_disabled.svg b/Z/src/nglwidgets/icons/svg/set_markers_audio_disabled.svg new file mode 100755 index 000000000..dbd4ccf1c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_markers_audio_disabled.svg @@ -0,0 +1,139 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_mode.svg b/Z/src/nglwidgets/icons/svg/set_player_mode.svg new file mode 100755 index 000000000..99419e6f9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_mode.svg @@ -0,0 +1,401 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_mode_disabled.svg b/Z/src/nglwidgets/icons/svg/set_player_mode_disabled.svg new file mode 100755 index 000000000..dc141325e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_mode_disabled.svg @@ -0,0 +1,73 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_status.svg b/Z/src/nglwidgets/icons/svg/set_player_status.svg new file mode 100755 index 000000000..885991ef1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_status.svg @@ -0,0 +1,391 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_status_disabled.svg b/Z/src/nglwidgets/icons/svg/set_player_status_disabled.svg new file mode 100755 index 000000000..13256964a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_status_disabled.svg @@ -0,0 +1,67 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_view_position.svg b/Z/src/nglwidgets/icons/svg/set_view_position.svg new file mode 100755 index 000000000..ff4c02741 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_view_position.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_view_position_disabled.svg b/Z/src/nglwidgets/icons/svg/set_view_position_disabled.svg new file mode 100755 index 000000000..620038960 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_view_position_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_building_configuration.svg b/Z/src/nglwidgets/icons/svg/show_building_configuration.svg new file mode 100755 index 000000000..2bc11ba20 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_building_configuration.svg @@ -0,0 +1,466 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_building_configuration_disabled.svg b/Z/src/nglwidgets/icons/svg/show_building_configuration_disabled.svg new file mode 100755 index 000000000..e78b52ad7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_building_configuration_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_distance_measure.svg b/Z/src/nglwidgets/icons/svg/show_distance_measure.svg new file mode 100755 index 000000000..9aecddd99 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_distance_measure.svg @@ -0,0 +1,455 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_distance_measure_disabled.svg b/Z/src/nglwidgets/icons/svg/show_distance_measure_disabled.svg new file mode 100755 index 000000000..43598b35b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_distance_measure_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_line_of_sight.svg b/Z/src/nglwidgets/icons/svg/show_line_of_sight.svg new file mode 100755 index 000000000..8fa74270c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_line_of_sight.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_line_of_sight_disabled.svg b/Z/src/nglwidgets/icons/svg/show_line_of_sight_disabled.svg new file mode 100755 index 000000000..e47630f85 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_line_of_sight_disabled.svg @@ -0,0 +1,126 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_terrain_profile.svg b/Z/src/nglwidgets/icons/svg/show_terrain_profile.svg new file mode 100755 index 000000000..8369fd64f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_terrain_profile.svg @@ -0,0 +1,439 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_terrain_profile_disabled.svg b/Z/src/nglwidgets/icons/svg/show_terrain_profile_disabled.svg new file mode 100755 index 000000000..f87cba6ca --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_terrain_profile_disabled.svg @@ -0,0 +1,113 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/simulated_players.svg b/Z/src/nglwidgets/icons/svg/simulated_players.svg new file mode 100755 index 000000000..160a8c90b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/simulated_players.svg @@ -0,0 +1,409 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/simulated_players_disabled.svg b/Z/src/nglwidgets/icons/svg/simulated_players_disabled.svg new file mode 100755 index 000000000..c0753761d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/simulated_players_disabled.svg @@ -0,0 +1,85 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/situation.svg b/Z/src/nglwidgets/icons/svg/situation.svg new file mode 100755 index 000000000..322407c51 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/situation.svg @@ -0,0 +1,431 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/situation_disabled.svg b/Z/src/nglwidgets/icons/svg/situation_disabled.svg new file mode 100755 index 000000000..68c3562a8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/situation_disabled.svg @@ -0,0 +1,106 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/status_bar.svg b/Z/src/nglwidgets/icons/svg/status_bar.svg new file mode 100755 index 000000000..8242e778c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/status_bar.svg @@ -0,0 +1,486 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/status_bar_disabled.svg b/Z/src/nglwidgets/icons/svg/status_bar_disabled.svg new file mode 100755 index 000000000..f83cbc2a3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/status_bar_disabled.svg @@ -0,0 +1,159 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/support_documents.svg b/Z/src/nglwidgets/icons/svg/support_documents.svg new file mode 100755 index 000000000..509995816 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/support_documents.svg @@ -0,0 +1,449 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/support_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/support_documents_disabled.svg new file mode 100755 index 000000000..949fb80ff --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/support_documents_disabled.svg @@ -0,0 +1,120 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_display.svg b/Z/src/nglwidgets/icons/svg/switch_display.svg new file mode 100755 index 000000000..9696386f5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_display.svg @@ -0,0 +1,435 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_display_disabled.svg b/Z/src/nglwidgets/icons/svg/switch_display_disabled.svg new file mode 100755 index 000000000..c52204798 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_display_disabled.svg @@ -0,0 +1,111 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_primary_map.svg b/Z/src/nglwidgets/icons/svg/switch_to_primary_map.svg new file mode 100755 index 000000000..0eb577e82 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_primary_map.svg @@ -0,0 +1,439 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_primary_map_disabled.svg b/Z/src/nglwidgets/icons/svg/switch_to_primary_map_disabled.svg new file mode 100755 index 000000000..a71629dbe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_primary_map_disabled.svg @@ -0,0 +1,110 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_sec_map.svg b/Z/src/nglwidgets/icons/svg/switch_to_sec_map.svg new file mode 100755 index 000000000..4cac60d52 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_sec_map.svg @@ -0,0 +1,447 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_sec_map_disabled.svg b/Z/src/nglwidgets/icons/svg/switch_to_sec_map_disabled.svg new file mode 100755 index 000000000..17f105295 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_sec_map_disabled.svg @@ -0,0 +1,120 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/symbol_display.svg b/Z/src/nglwidgets/icons/svg/symbol_display.svg new file mode 100755 index 000000000..1a3b62f01 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/symbol_display.svg @@ -0,0 +1,411 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/symbol_display_disabled.svg b/Z/src/nglwidgets/icons/svg/symbol_display_disabled.svg new file mode 100755 index 000000000..e1e4d2f67 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/symbol_display_disabled.svg @@ -0,0 +1,86 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/system_status.svg b/Z/src/nglwidgets/icons/svg/system_status.svg new file mode 100755 index 000000000..1bd6e4089 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/system_status.svg @@ -0,0 +1,456 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/system_status_disabled.svg b/Z/src/nglwidgets/icons/svg/system_status_disabled.svg new file mode 100755 index 000000000..96deaea44 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/system_status_disabled.svg @@ -0,0 +1,127 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_organization.svg b/Z/src/nglwidgets/icons/svg/tactical_organization.svg new file mode 100755 index 000000000..e0e5e4755 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_organization.svg @@ -0,0 +1,455 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_organization_disabled.svg b/Z/src/nglwidgets/icons/svg/tactical_organization_disabled.svg new file mode 100755 index 000000000..6a9b558b5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_organization_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_symbol.svg b/Z/src/nglwidgets/icons/svg/tactical_symbol.svg new file mode 100755 index 000000000..070ba182b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_symbol.svg @@ -0,0 +1,404 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_symbol_disabled.svg b/Z/src/nglwidgets/icons/svg/tactical_symbol_disabled.svg new file mode 100755 index 000000000..1f0136ce2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_symbol_disabled.svg @@ -0,0 +1,76 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/target.svg b/Z/src/nglwidgets/icons/svg/target.svg new file mode 100755 index 000000000..bc4dedd35 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/target.svg @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/terminal_window.svg b/Z/src/nglwidgets/icons/svg/terminal_window.svg new file mode 100755 index 000000000..c500ee50d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/terminal_window.svg @@ -0,0 +1,399 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/terminal_window_disabled.svg b/Z/src/nglwidgets/icons/svg/terminal_window_disabled.svg new file mode 100755 index 000000000..c28c6cfbe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/terminal_window_disabled.svg @@ -0,0 +1,70 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/toolbar_editor.svg b/Z/src/nglwidgets/icons/svg/toolbar_editor.svg new file mode 100755 index 000000000..64c2ea51b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/toolbar_editor.svg @@ -0,0 +1,480 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/toolbar_editor_disabled.svg b/Z/src/nglwidgets/icons/svg/toolbar_editor_disabled.svg new file mode 100755 index 000000000..f6fa9cd97 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/toolbar_editor_disabled.svg @@ -0,0 +1,157 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/translation_editor.svg b/Z/src/nglwidgets/icons/svg/translation_editor.svg new file mode 100755 index 000000000..380112458 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/translation_editor.svg @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/update_player_position.svg b/Z/src/nglwidgets/icons/svg/update_player_position.svg new file mode 100755 index 000000000..f2b3b3af4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/update_player_position.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/update_player_position_disabled.svg b/Z/src/nglwidgets/icons/svg/update_player_position_disabled.svg new file mode 100755 index 000000000..bfe38e8a2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/update_player_position_disabled.svg @@ -0,0 +1,97 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/video_menu.svg b/Z/src/nglwidgets/icons/svg/video_menu.svg new file mode 100755 index 000000000..84a23700c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/video_menu.svg @@ -0,0 +1,404 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/video_menu_disabled.svg b/Z/src/nglwidgets/icons/svg/video_menu_disabled.svg new file mode 100755 index 000000000..ece02d315 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/video_menu_disabled.svg @@ -0,0 +1,79 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/view-statistics.svg b/Z/src/nglwidgets/icons/svg/view-statistics.svg new file mode 100755 index 000000000..c336800c6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/view-statistics.svg @@ -0,0 +1,378 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/visible_teams.svg b/Z/src/nglwidgets/icons/svg/visible_teams.svg new file mode 100755 index 000000000..3be836387 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/visible_teams.svg @@ -0,0 +1,487 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication.svg b/Z/src/nglwidgets/icons/svg/voice_communication.svg new file mode 100755 index 000000000..94ef1bfea --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication.svg @@ -0,0 +1,470 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication_access.svg b/Z/src/nglwidgets/icons/svg/voice_communication_access.svg new file mode 100755 index 000000000..234cb72e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication_access.svg @@ -0,0 +1,455 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication_access_disabled.svg b/Z/src/nglwidgets/icons/svg/voice_communication_access_disabled.svg new file mode 100755 index 000000000..a78afc26a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication_access_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication_disabled.svg b/Z/src/nglwidgets/icons/svg/voice_communication_disabled.svg new file mode 100755 index 000000000..13e2f7706 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/weapon_firing.svg b/Z/src/nglwidgets/icons/svg/weapon_firing.svg new file mode 100755 index 000000000..6a85a50ef --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/weapon_firing.svg @@ -0,0 +1,438 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/weapon_firing_disabled.svg b/Z/src/nglwidgets/icons/svg/weapon_firing_disabled.svg new file mode 100755 index 000000000..240c136a8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/weapon_firing_disabled.svg @@ -0,0 +1,112 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/wireless.svg b/Z/src/nglwidgets/icons/svg/wireless.svg new file mode 100755 index 000000000..96ff4e729 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/wireless.svg @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/ngldialog.cpp b/Z/src/nglwidgets/ngldialog.cpp new file mode 100755 index 000000000..f7d6b3756 --- /dev/null +++ b/Z/src/nglwidgets/ngldialog.cpp @@ -0,0 +1,149 @@ + + +#include "ngldialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ngldialogbuttonbox.h" + +NGLDialog::NGLDialog(QWidget *parent, Qt::WindowFlags f) + : QDialog(parent, f) + , m_bReadOnly(false) +{ + setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde_16x16.png"))); +} + +void NGLDialog::setHelpContext(const QString &helpContext) +{ + m_helpContext = helpContext; +} + +void NGLDialog::showEvent(QShowEvent *e) +{ + NGLDialogButtonBox *bb = findChild(); + if (bb) + connect(bb, &NGLDialogButtonBox::onHelp, + this, &NGLDialog::onInvokeHelp, + Qt::UniqueConnection); + QDialog::showEvent(e); +} + +void NGLDialog::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_F1) + onInvokeHelp(); + if (e->key() == Qt::Key_P && + e->modifiers().testFlag(Qt::ControlModifier) && + e->modifiers().testFlag(Qt::AltModifier)) + printWidget(); + + QDialog::keyPressEvent(e); +} + +void NGLDialog::centerWidget(QWidget *widgetToCenter) +{ + if (!widgetToCenter) + return; + + QWidget *p = widgetToCenter->parentWidget(); + QPoint pPos; + QSize pSize; + if (p) + { + pPos = p->pos(); + pSize = p->size(); + } + else + { + QRect r = QGuiApplication::primaryScreen()->geometry(); + pPos = r.topLeft(); + pSize = r.size(); + } + + pPos.setX(pPos.x() + (pSize.width() / 2 - widgetToCenter->sizeHint().width() / 2)); + pPos.setY(pPos.y() + (pSize.height() / 2 - widgetToCenter->sizeHint().height() / 2)); + widgetToCenter->move(pPos); +} + +void NGLDialog::centerWidget() +{ + centerWidget(this); +} + +void NGLDialog::printWidget(QWidget *widgetToPrint) +{ + QRect r = widgetToPrint->frameGeometry(); + QPixmap pm = QApplication::desktop()->grab(r); + QString path = QString::fromLocal8Bit(qgetenv("GFS_PATH")); + if (path.isEmpty()) + path = QCoreApplication::applicationDirPath() + QLatin1String("/../images"); + time_t t = time(nullptr); + QString fn; + + NGLDialog *dlg = qobject_cast(widgetToPrint); + if (dlg && !dlg->m_helpContext.isEmpty()) + fn = path + QLatin1Char('/') + QString::number(t) + QLatin1Char('_') + dlg->m_helpContext + QLatin1String(".png"); + else + fn = path + QLatin1Char('/') + QString::number(t) + QLatin1String(".png"); + QDir d(path); + if (!d.exists()) + d.mkpath(path); + pm.save(fn, "PNG"); +} + +void NGLDialog::printWidget() +{ + printWidget(this); +} + +void NGLDialog::onInvokeHelp() +{ + NGLHelpEvent::sendHelpEvent(m_helpContext); +} + +void NGLDialog::setWindowTitle(const QString &title) +{ + m_realWindowTitle = title.trimmed(); + + QString newTitle = title; + if (m_bReadOnly) + { + if (!m_readOnlyReason.isEmpty()) + newTitle += QLatin1Char(' ') + tr("(locked by %1)").arg(m_readOnlyReason); + else + newTitle += QLatin1Char(' ') + tr("(read only)"); + } + newTitle += QLatin1String(" [*]"); + + QDialog::setWindowTitle(newTitle); +} + +QString NGLDialog::windowTitle() const +{ + return m_realWindowTitle; +} + +void NGLDialog::setDialogReadOnly(bool bReadOnly, const QString &reason) +{ + m_bReadOnly = bReadOnly; + if (bReadOnly && !reason.isEmpty()) + m_readOnlyReason = reason; + else + m_readOnlyReason.clear(); + + setWindowTitle(windowTitle()); +} + +bool NGLDialog::isDialogReadOnly() const +{ + return m_bReadOnly; +} diff --git a/Z/src/nglwidgets/ngldialog.h b/Z/src/nglwidgets/ngldialog.h new file mode 100755 index 000000000..97ebd239c --- /dev/null +++ b/Z/src/nglwidgets/ngldialog.h @@ -0,0 +1,62 @@ + + +#pragma once + +#include "nglwidgets_export.h" + +#include +#include "nglstandardbutton.h" + +class NGLWIDGETS_EXPORT NGLDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NGLDialog(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + + void setHelpContext(const QString &helpContext); + + + + static void centerWidget(QWidget *widgetToCenter); + + + + static void printWidget(QWidget *widgetToPrint); + + + + void setWindowTitle(const QString &title); + + + + QString windowTitle() const; + + + + void setDialogReadOnly(bool bReadOnly, const QString &reason = QString()); + + + + bool isDialogReadOnly() const; + +Q_SIGNALS: + + + void invokeHelp(const QString &helpContext); +protected: + virtual void showEvent(QShowEvent *e); + virtual void keyPressEvent(QKeyEvent *e); + void centerWidget(); + void printWidget(); +protected Q_SLOTS: + + + void onInvokeHelp(); + +private: + QString m_helpContext; + bool m_bReadOnly; + QString m_readOnlyReason; + QString m_realWindowTitle; +}; diff --git a/Z/src/nglwidgets/ngldialogbuttonbox.cpp b/Z/src/nglwidgets/ngldialogbuttonbox.cpp new file mode 100755 index 000000000..3d22e646a --- /dev/null +++ b/Z/src/nglwidgets/ngldialogbuttonbox.cpp @@ -0,0 +1,445 @@ +#include "ngldialogbuttonbox.h" + +#include +#include +#include + +NGLDialogButtonBox::NGLDialogButtonBox(QWidget *parent) + : NGLDialogButtonBox(Qt::Horizontal, parent) +{} + +NGLDialogButtonBox::NGLDialogButtonBox(Qt::Orientation orientation, + QWidget *parent) + : QWidget(parent) + , m_orientation(orientation) + , m_buttons(nullptr) + , m_line(nullptr) + , m_bSpacer2ContextAction(nullptr) + , m_bLineVisible(true) +{ + setFocusPolicy(Qt::StrongFocus); + init(); +} + +NGLDialogButtonBox::NGLDialogButtonBox(NGLStandardButton::StandardButtons buttons, + Qt::Orientation orientation, + QWidget *parent) + : QWidget(parent) + , m_orientation(orientation) + , m_buttons(buttons) + , m_line(nullptr) + , m_bSpacer2ContextAction(nullptr) + , m_bLineVisible(true) +{ + setFocusPolicy(Qt::StrongFocus); + setStandardButtons(m_buttons); +} + +Qt::Orientation NGLDialogButtonBox::orientation() const +{ + return m_orientation; +} + +void NGLDialogButtonBox::setOrientation(Qt::Orientation orientation) +{ + if (m_orientation == orientation) + return; + m_orientation = orientation; + init(); +} + +NGLStandardButton::StandardButtons NGLDialogButtonBox::standardButtons() const +{ + return m_buttons; +} + +void NGLDialogButtonBox::setStandardButtons(NGLStandardButton::StandardButtons buttons) +{ + m_buttons = buttons; + + QMap::const_iterator it = m_standardButtons.constBegin(); + QMap::const_iterator end = m_standardButtons.constEnd(); + for (; it != end; ++it) + { + const QList actions = it.value()->actions(); + for (QAction *a : actions) + removeAction(a); + delete it.value(); + } + m_standardButtons.clear(); + + NGLStandardButton::StandardButton i = NGLStandardButton::FirstButton; + while (i <= NGLStandardButton::LastButton) + { + if ((m_buttons & i) == i) + { + NGLStandardButton *button = new NGLStandardButton(i); + addButtonInternal(button); + if (i == NGLStandardButton::Ok) + { + button->setDefault(true); + button->setAutoDefault(true); + } + } + i = (NGLStandardButton::StandardButton)((int) i << 1); + } + + init(); +} + +void NGLDialogButtonBox::addButtonInternal(NGLStandardButton *button) +{ + button->setParent(this); + button->setDefault(false); + button->setAutoDefault(false); + + m_standardButtons.insertMulti(button->layoutPriority(), button); +} + +void NGLDialogButtonBox::addButton(NGLStandardButton *button) +{ + addButtonInternal(button); + init(); +} + +NGLStandardButton *NGLDialogButtonBox::addButton(NGLStandardButton::StandardButton button) +{ + NGLStandardButton *pb = new NGLStandardButton(button); + addButton(pb); + return pb; +} + +NGLStandardButton *NGLDialogButtonBox::button(NGLStandardButton::StandardButton button) +{ + QMap::const_iterator it = m_standardButtons.constBegin(); + QMap::const_iterator end = m_standardButtons.constEnd(); + for (; it != end; ++it) + { + if (it.value()->type() == button) + return it.value(); + } + return new NGLStandardButton(nullptr); +} + +void NGLDialogButtonBox::removeFromActionList(NGLStandardButton::StandardButton button) +{ + m_disabledActions |= button; + init(); +} + +bool NGLDialogButtonBox::setEnabled(NGLStandardButton::StandardButton button, bool enable) +{ + NGLStandardButton *b = this->button(button); + if (!b) + return false; + b->setEnabled(enable); + return true; +} + +bool NGLDialogButtonBox::isEnabled(NGLStandardButton::StandardButton button) +{ + NGLStandardButton *b = this->button(button); + if (!b) + return false; + return b->isEnabled(); +} + +bool NGLDialogButtonBox::lineVisible() const +{ + return m_bLineVisible; +} + +void NGLDialogButtonBox::setLineVisible(bool bVisible) +{ + if (m_bLineVisible == bVisible) + return; + m_bLineVisible = bVisible; + init(); +} + +bool NGLDialogButtonBox::setVisible(NGLStandardButton::StandardButton button, bool visible) +{ + NGLStandardButton *b = this->button(button); + if (!b) + return false; + b->setVisible(visible); + return true; +} + +void NGLDialogButtonBox::layoutPriorityChanged() +{ + QMap standardButtons = m_standardButtons; + m_standardButtons.clear(); + QMap::const_iterator it = standardButtons.constBegin(); + QMap::const_iterator end = standardButtons.constEnd(); + for (; it != end; ++it) + { + NGLStandardButton *button = it.value(); + m_standardButtons.insertMulti(button->layoutPriority(), button); + } + + init(); +} + +static void addSpacer2(QLayout *l, Qt::Orientation orientation) +{ + if (orientation == Qt::Horizontal) + l->addItem(new QSpacerItem(20, 1, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); + else + l->addItem(new QSpacerItem(1, 20, QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); +} + +void NGLDialogButtonBox::init() +{ + delete layout(); + delete m_line; m_line = nullptr; + if (m_bSpacer2ContextAction) + { + removeAction(m_bSpacer2ContextAction); + delete m_bSpacer2ContextAction; + m_bSpacer2ContextAction = nullptr; + } + + QBoxLayout *l; + QBoxLayout *lMain; + if (m_orientation == Qt::Horizontal) + { + lMain = new QVBoxLayout; + l = new QHBoxLayout; + } + else + { + lMain = new QHBoxLayout; + l = new QVBoxLayout; + } + lMain->setMargin(0); + if (m_bLineVisible) + { + m_line = new QFrame(this); + m_line->setFrameShape(m_orientation == Qt::Horizontal ? QFrame::HLine : QFrame::VLine); + m_line->setFrameShadow(QFrame::Sunken); + lMain->addWidget(m_line); + } + lMain->addLayout(l); + l->setDirection(m_orientation == Qt::Horizontal ? QBoxLayout::RightToLeft : QBoxLayout::BottomToTop); + l->setContentsMargins(0, 0, 0, 0); + setLayout(lMain); + + const auto actions = findChildren(); + for (auto a : actions) + a->disconnect(a, &QAction::triggered, this, &NGLDialogButtonBox::buttonClicked); + + bool bLowestPrioButton = false; + bool bSpacer1Added = false; + bool bSpacer2Added = false; + QMap::const_iterator it = m_standardButtons.constBegin(); + QMap::const_iterator end = m_standardButtons.constEnd(); + for (; it != end; ++it) + { + qint32 prio = it.key(); + NGLStandardButton *button = it.value(); + + if (prio < 30) + bLowestPrioButton = true; + if (prio >= 30 && !bSpacer1Added) + { + bSpacer1Added = true; + if (bLowestPrioButton) + { + + QSpacerItem *item = new QSpacerItem(7, 7, QSizePolicy::Fixed, QSizePolicy::Fixed); + l->addItem(item); + } + } + if (prio >= 100 && !bSpacer2Added) + { + bSpacer2Added = true; + addSpacer2(l, m_orientation); + } + + if (prio >= 30 && prio < 100) + { + + const QList actions = button->actions(); + for (QAction *a : actions) + removeAction(a); + + if ((m_disabledActions & button->type()) == 0) + { + if (prio >= 100 && !m_bSpacer2ContextAction) + { + m_bSpacer2ContextAction = new QAction(this); + m_bSpacer2ContextAction->setSeparator(true); + addAction(m_bSpacer2ContextAction); + } + addActions(actions); + } + } + l->addWidget(button); + + if (button->type() == NGLStandardButton::Library) + { + QAction *ex = button->findChild(QLatin1String("actionExport")); + if (ex) + { + connect(ex, &QAction::triggered, + this, &NGLDialogButtonBox::buttonClicked, Qt::UniqueConnection); + } + QAction *im = button->findChild(QLatin1String("actionImport")); + if (im) + { + connect(im, &QAction::triggered, + this, &NGLDialogButtonBox::buttonClicked, Qt::UniqueConnection); + } + } + else + { + connect(button, &NGLStandardButton::clicked, + this, &NGLDialogButtonBox::buttonClicked, Qt::UniqueConnection); + } + } + if (!bSpacer2Added) + addSpacer2(l, m_orientation); + + QMapIterator mapIt(m_standardButtons); + NGLStandardButton *prevButton = nullptr; + mapIt.toBack(); + while (mapIt.hasPrevious()) + { + NGLStandardButton *curButton = mapIt.previous().value(); + if (prevButton != nullptr) + setTabOrder(prevButton, curButton); + prevButton = curButton; + } +} + +void NGLDialogButtonBox::buttonClicked() +{ + NGLStandardButton *b = qobject_cast (sender()); + if (!b) + { + QAction *a = qobject_cast (sender()); + if (!a) + return; + if (a->objectName() == QLatin1String("actionExport")) + { + emit onLibraryExport(); + return; + } + if (a->objectName() == QLatin1String("actionImport")) + { + emit onLibraryImport(); + return; + } + return; + } + switch (b->type()) + { + case NGLStandardButton::Ok: + emit onOk(); + break; + case NGLStandardButton::Send: + emit onSend(); + break; + case NGLStandardButton::New: + emit onNew(); + break; + case NGLStandardButton::Delete: + emit onDelete(); + break; + case NGLStandardButton::Save: + emit onSave(); + break; + case NGLStandardButton::Open: + emit onOpen(); + break; + case NGLStandardButton::Yes: + emit onYes(); + break; + case NGLStandardButton::No: + emit onNo(); + break; + case NGLStandardButton::Close: + emit onClose(); + break; + case NGLStandardButton::Cancel: + emit onCancel(); + break; + case NGLStandardButton::Help: + emit onHelp(); + break; + case NGLStandardButton::Apply: + emit onApply(); + break; + case NGLStandardButton::Reset: + emit onReset(); + break; + case NGLStandardButton::Print: + emit onPrint(); + break; + case NGLStandardButton::Modify: + emit onModify(); + break; + case NGLStandardButton::Add: + emit onAdd(); + break; + case NGLStandardButton::Remove: + emit onRemove(); + break; + case NGLStandardButton::Edit: + emit onEdit(); + break; + case NGLStandardButton::Download: + emit onDownload(); + break; + case NGLStandardButton::Library: + break; + case NGLStandardButton::Show: + emit onShow(); + break; + case NGLStandardButton::ZoomIn: + emit onZoomIn(); + break; + case NGLStandardButton::ZoomOut: + emit onZoomOut(); + break; + case NGLStandardButton::Hide: + emit onHide(); + break; + default: + emit clicked(b); + break; + } +} + +void NGLDialogButtonBox::enableImport(bool ena) +{ + NGLStandardButton *b = button(NGLStandardButton::Library); + if (!b) + return; + + QAction *im = b->findChild(QLatin1String("actionImport")); + if (im) + { + im->setEnabled(ena); + QAction *ex = b->findChild(QLatin1String("actionExport")); + if (ex) + b->setEnabled(ena || ex->isEnabled()); + } +} + +void NGLDialogButtonBox::enableExport(bool ena) +{ + NGLStandardButton *b = button(NGLStandardButton::Library); + if (!b) + return; + + QAction *ex = b->findChild(QLatin1String("actionExport")); + if (ex) + { + ex->setEnabled(ena); + QAction *im = b->findChild(QLatin1String("actionImport")); + if (im) + b->setEnabled(ena || im->isEnabled()); + } +} diff --git a/Z/src/nglwidgets/ngldialogbuttonbox.h b/Z/src/nglwidgets/ngldialogbuttonbox.h new file mode 100755 index 000000000..21b535f48 --- /dev/null +++ b/Z/src/nglwidgets/ngldialogbuttonbox.h @@ -0,0 +1,189 @@ +#pragma once + +#include +#include + +#include "nglwidgets_export.h" +#include "nglstandardbutton.h" + +class QFrame; + + +class NGLWIDGETS_EXPORT NGLDialogButtonBox : public QWidget +{ + Q_OBJECT + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) + Q_PROPERTY(NGLStandardButton::StandardButtons standardButtons READ standardButtons WRITE setStandardButtons) + Q_PROPERTY(bool m_bLineVisible READ lineVisible WRITE setLineVisible) + +public: + + + explicit NGLDialogButtonBox(QWidget *parent = nullptr); + + + explicit NGLDialogButtonBox(Qt::Orientation orientation, QWidget *parent = nullptr); + + + NGLDialogButtonBox(NGLStandardButton::StandardButtons buttons, Qt::Orientation orientation = Qt::Horizontal, QWidget *parent = nullptr); + + + + Qt::Orientation orientation() const; + + + void setOrientation(Qt::Orientation orientation); + + + + NGLStandardButton::StandardButtons standardButtons() const; + + + void setStandardButtons(NGLStandardButton::StandardButtons buttons); + + + + void addButton(NGLStandardButton *button); + + + NGLStandardButton *addButton(NGLStandardButton::StandardButton button); + + + + NGLStandardButton *button(NGLStandardButton::StandardButton button); + + + + void removeFromActionList(NGLStandardButton::StandardButton button); + + + + bool setEnabled(NGLStandardButton::StandardButton button, bool enable); + + + + bool isEnabled(NGLStandardButton::StandardButton button); + + + + bool lineVisible() const; + + + + void setLineVisible(bool bVisible); + + + + bool setVisible(NGLStandardButton::StandardButton button, bool visible); + + + + void setVisible(bool visible) { QWidget::setVisible(visible); } + + + + void enableExport(bool ena); + + + + void enableImport(bool ena); + +public Q_SLOTS: + + + void layoutPriorityChanged(); +Q_SIGNALS: + + + void clicked(NGLStandardButton *button); + + + void onOk(); + + + void onSend(); + + + void onNew(); + + + void onDelete(); + + + void onSave(); + + + void onOpen(); + + + void onYes(); + + + void onNo(); + + + void onClose(); + + + void onCancel(); + + + void onHelp(); + + + void onApply(); + + + void onReset(); + + + void onPrint(); + + + void onModify(); + + + void onAdd(); + + + void onRemove(); + + + void onEdit(); + + + void onDownload(); + + + + void onLibraryImport(); + + + + void onLibraryExport(); + + void onShow(); + void onZoomIn(); + void onZoomOut(); + + + void onHide(); + +protected: + void init(); + void addButtonInternal(NGLStandardButton *button); + +protected Q_SLOTS: + void buttonClicked(); + +protected: + QMap m_standardButtons; + Qt::Orientation m_orientation; + NGLStandardButton::StandardButtons m_buttons; + NGLStandardButton::StandardButtons m_disabledActions; + QFrame *m_line; + QAction *m_bSpacer2ContextAction; + bool m_bLineVisible; +}; + + diff --git a/Z/src/nglwidgets/nglmainwindow.cpp b/Z/src/nglwidgets/nglmainwindow.cpp new file mode 100755 index 000000000..5d3337e3f --- /dev/null +++ b/Z/src/nglwidgets/nglmainwindow.cpp @@ -0,0 +1,107 @@ + + + +#include "nglmainwindow.h" + +#include +#include +#include +#include +#include +#include +#include + +NGLMainWindow::NGLMainWindow(QWidget *parent) + : QMainWindow(parent) + , m_helpProcess(nullptr) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("NGLMainWindow")) + , m_versionView(nullptr) + , m_menuBar(new QMenuBar(this)) +{ + m_menu[QLatin1String("File")] = m_menuBar->addMenu(tr("File")); + m_fileActionBefore = m_menu[QLatin1String("File")]->addSeparator(); + m_menu[QLatin1String("File")]->addAction(QIcon(QLatin1String(":/icons/16x16/application-exit.png")), tr("Quit"), + this, &NGLMainWindow::onExit, QKeySequence(tr("Ctrl+q"))); + + m_menu[QLatin1String("Help")] = m_menuBar->addMenu(tr("Help")); + m_menu[QLatin1String("Help")]->addAction(QIcon(QLatin1String(":/icons/16x16/help-contents.png")), + tr("Help"), this, &NGLMainWindow::onHelpIndex, QKeySequence(tr("F1"))); + m_menu[QLatin1String("Help")]->addSeparator(); + m_menu[QLatin1String("Help")]->addAction(QIcon(QLatin1String(":/icons/16x16/help-about.png")), + tr("About"), this, &NGLMainWindow::onHelpAbout); + + setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde_16x16.png"))); + setMenuBar(m_menuBar); +} + +void NGLMainWindow::onExit() +{ + + close(); +} + +void NGLMainWindow::onHelpIndex() +{ + onInvokeHelp(QLatin1String("Index")); +} + +void NGLMainWindow::onInvokeHelp(const QString &helpContext) +{ + + DEBUG_LOG(m_logger) << "onInvokeHelp " << helpContext ; + + if (!m_helpProcess) + { + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString lang = QString::fromLatin1(NGL::translationLocale()) + QLatin1String(".UTF-8"); + env.insert(QLatin1String("LANG"), lang); + m_helpProcess = new QProcess(this); + m_helpProcess->setProcessEnvironment(env); + QStringList args; + QString fn = QString::fromLatin1(NGL::translationLocale()) + QLatin1String(".qhc"); + args << QLatin1String("-collectionFile") + << QCoreApplication::applicationDirPath() + QLatin1String("/../help/scms/") + fn + << QLatin1String("-enableRemoteControl"); + DEBUG_LOG(m_logger) << "Attempting to invoke help at URL: " << args.join(QLatin1String(" ")) ; + m_helpProcess->start(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/assistant"), args); + if (!m_helpProcess->waitForStarted()) + { + ERROR_LOG(m_logger) << "Could not start help browser (error: " + << m_helpProcess->error() + << " )" ; + delete m_helpProcess; + m_helpProcess = nullptr; + return; + } + connect(m_helpProcess, QOverload::of(&QProcess::finished), + this, &NGLMainWindow::onHelpFinished); + } + QTextStream str(m_helpProcess); + + str << QLatin1String("activateIdentifier ") + helpContext << QLatin1Char('\0') << endl; +} + +void NGLMainWindow::onHelpFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + if (exitStatus != QProcess::NormalExit) + { + WARNING_LOG(m_logger) << "help browser exited with status " + << exitStatus << " code " + << exitCode << "!" ; + } + delete m_helpProcess; + m_helpProcess = nullptr; +} + +void NGLMainWindow::onHelpAbout() +{ + if (m_versionView) + m_versionView->show(); +} + +void NGLMainWindow::onVersionViewDeleted() +{ + m_versionView = nullptr; + setVersionView(); +} diff --git a/Z/src/nglwidgets/nglmainwindow.h b/Z/src/nglwidgets/nglmainwindow.h new file mode 100755 index 000000000..39bec5aa4 --- /dev/null +++ b/Z/src/nglwidgets/nglmainwindow.h @@ -0,0 +1,46 @@ + + + +#pragma once + +#include +#include +#include +#include "nglwidgets_export.h" + +namespace NGL +{ +class INGLLogger; +} + +class NGLWIDGETS_EXPORT NGLMainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit NGLMainWindow(QWidget *parent = nullptr); + + virtual void setVersionView() = 0; + +public slots: + + void onHelpIndex(); + void onHelpAbout(); + void onInvokeHelp(const QString &); + void onHelpFinished(int exitCode, QProcess::ExitStatus exitStatus); + +private: + QProcess *m_helpProcess; + +protected: + NGL::INGLLogger &m_logger; + QWidget *m_versionView; + QMenuBar *m_menuBar; + QMap m_menu; + QAction *m_fileActionBefore; + +protected slots: + void onVersionViewDeleted(); + void onExit(); + +}; + diff --git a/Z/src/nglwidgets/nglpdfdocument.cpp b/Z/src/nglwidgets/nglpdfdocument.cpp new file mode 100755 index 000000000..8f0854878 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfdocument.cpp @@ -0,0 +1,332 @@ +#include "nglpdfdocument.h" +#include "nglpdfpage.h" + +#include +#include +#include +#include +#include +#include + +#include + +namespace NGL +{ +PDFDocument::PDFDocument(QWidget *parent) + : QWidget(parent) + , m_doc(nullptr) + , m_currentPage(0) + , m_maxCachedPages(20) + , m_scaleFactor(1.0) + , m_widthFactor(1.0) + , m_rotation(Poppler::Page::Rotate0) +{ + QVBoxLayout *lay = new QVBoxLayout(this); + lay->setMargin(0); + lay->setSpacing(0); + + m_pdfLabel = new QWidget(this); + m_pdfLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + QVBoxLayout *l = new QVBoxLayout(m_pdfLabel); + l->setMargin(l->margin() * 2); + l->setSpacing(l->margin()); + l->setSizeConstraint(QLayout::SetFixedSize); + + m_scrollArea = new QScrollArea(this); + m_scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + + m_scrollArea->setWidgetResizable(true); + m_scrollArea->setWidget(m_pdfLabel); + + lay->addWidget(m_scrollArea); +} + +PDFDocument::~PDFDocument() +{ + qDeleteAll(m_pages); + m_pages.clear(); + delete m_doc; +} + +bool PDFDocument::showPDF(const QUrl &url) +{ + return showPDF(url.toLocalFile()); +} + +bool PDFDocument::showPDF(const QString &path) +{ + if (path.isEmpty()) + return false; + + if (path == m_currentPath) + { + m_scaleFactor = 0; + m_widthFactor = 1; + setZoomFactor(1.0); + setRotation(Poppler::Page::Rotate0); + return true; + } + + delete m_doc; + m_doc = Poppler::Document::load(path); + if (!m_doc) + return false; + m_currentPath = path; + + return showPDFInternal(); +} + +bool PDFDocument::showPDF(const QByteArray &pdf) +{ + m_currentPath.clear(); + + delete m_doc; + m_doc = Poppler::Document::loadFromData(pdf); + if (!m_doc) + return false; + + return showPDFInternal(); +} + +bool PDFDocument::showPDFInternal() +{ + disconnect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this, &PDFDocument::onVSliderValueChanged); + + m_doc->setRenderHint(Poppler::Document::Antialiasing); + m_doc->setRenderHint(Poppler::Document::TextAntialiasing); + m_doc->setRenderHint(Poppler::Document::TextHinting); + m_doc->setRenderHint(Poppler::Document::TextSlightHinting); + + m_scrollArea->horizontalScrollBar()->setSliderPosition(0); + m_scrollArea->verticalScrollBar()->setSliderPosition(0); + + m_renderedPages.clear(); + qDeleteAll(m_pages); + m_pages.clear(); + m_ranges.clear(); + + QVBoxLayout *l = qobject_cast (m_pdfLabel->layout()); + const int cnt = m_doc->numPages(); + m_pages.reserve(cnt); + for (int i = 0; i < cnt; ++i) + { + PDFPage *p = new PDFPage(m_pdfLabel); + p->setZoomFactor(m_scaleFactor); + p->setRotation(m_rotation); + p->setPopplerPage(m_doc->page(i)); + connect(p, &PDFPage::pageRendered, + this, &PDFDocument::onPageRendered); + connect(p, &PDFPage::externalLinkClicked, + this, &PDFDocument::linkClicked); + connect(p, &PDFPage::linkClicked, + this, &PDFDocument::onLinkClicked); + m_pages += p; + + l->addWidget(p); + } + rebuildRanges(); + + m_currentPage = std::min(m_currentPage, m_ranges.count() - 1); + + ensureCurPageVisible(); + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + connect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this, &PDFDocument::onVSliderValueChanged); + return true; +} + +void PDFDocument::resizePdfToWidth() +{ + double scale = m_scaleFactor; + + m_widthFactor = double(m_pdfLabel->size().width()) / size().width() * 1.03; + + m_scaleFactor = 0; + setZoomFactor(scale); +} + +int PDFDocument::curPage() const +{ + return m_currentPage + 1; +} + +int PDFDocument::numPages() const +{ + return m_doc ? m_doc->numPages() : -1; +} + +void PDFDocument::setZoomFactor(double zoom) +{ + if (qFuzzyCompare(m_scaleFactor, zoom)) + return; + m_scaleFactor = zoom; + + for (PDFPage *p : qAsConst(m_pages)) + p->setZoomFactor(m_scaleFactor / m_widthFactor); + + rebuildRanges(); +} + +void PDFDocument::setRotation(Poppler::Page::Rotation rot) +{ + if (m_rotation == rot) + return; + m_rotation = rot; + if (m_pages.isEmpty()) + return; + + for (PDFPage *p : qAsConst(m_pages)) + p->setRotation(m_rotation); + + rebuildRanges(); + emit currentPageChanged(m_currentPage+1, m_ranges.count()); + emit rotationChanged(m_rotation); +} + +bool PDFDocument::setPage(int page) +{ + page--; + if (m_currentPage == page) + { + ensureCurPageVisible(); + return true; + } + if (m_pages.isEmpty()) + { + m_currentPage = page; + return true; + } + if (page < 0 || numPages() < 0 || page >= m_doc->numPages()) + return false; + + m_currentPage = page; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(); + return true; +} + +bool PDFDocument::nextPage() +{ + if (m_doc == nullptr || m_currentPage >= m_doc->numPages() - 1) + return false; + m_currentPage++; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(); + return true; +} + +bool PDFDocument::previousPage() +{ + if (m_doc == nullptr || m_currentPage < 1) + return false; + m_currentPage--; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(); + return true; +} + +void PDFDocument::onVSliderValueChanged(int y) +{ + + y += m_scrollArea->height() / 2; + int curPage = m_ranges.count() - 1; + for (int i = 0; i < m_ranges.count(); ++i) + { + if (m_ranges.at(i) > y) + { + curPage = i - 1; + break; + } + } + if (curPage != m_currentPage && curPage >= 0) + { + m_currentPage = curPage; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + } +} + +void PDFDocument::onPageRendered() +{ + PDFPage *p = qobject_cast (sender()); + if (m_renderedPages.contains(p)) + return; + + while (m_renderedPages.count() > m_maxCachedPages - 1) + { + p = m_renderedPages.takeFirst(); + if (p) + p->clearPixmap(); + } + m_renderedPages.push_back(p); +} + +void PDFDocument::onLinkClicked(const Poppler::LinkDestination &dest) +{ + PDFPage *p = qobject_cast(sender()); + if (!p) + return; + m_currentPage = dest.pageNumber() - 1; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(qRound(dest.right() * p->width()), + qRound(dest.top() * p->height())); +} + +QVector PDFDocument::getPrintableImages(int resolution) const +{ + QVector imageList; + imageList.reserve(m_pages.size()); + for (const PDFPage *p : m_pages) + imageList.append(p->getPrintableImage(resolution)); + return imageList; +} + +QImage PDFDocument::getPrintableImage(int pageNum, int resolution) const +{ + if (pageNum < 0 || pageNum >= m_pages.size()) + return QImage(); + return m_pages[pageNum]->getPrintableImage(resolution); +} + +void PDFDocument::ensureCurPageVisible(int xOfs, int yOfs) +{ + if (m_currentPage >= m_ranges.size() || m_currentPage < 0) + return; + + + + if (m_scrollArea->verticalScrollBar()->maximum() == 0) + { + QTimer::singleShot(50, this, [this, xOfs, yOfs]() { ensureCurPageVisible(xOfs, yOfs); }); + return; + } + + + + int y = m_ranges.at(m_currentPage) + yOfs; + + y -= m_pdfLabel->layout()->spacing() * 2; + + int x = m_scrollArea->horizontalScrollBar()->value() + xOfs; + + + m_scrollArea->ensureVisible(x, y, 0, 0); + y += m_scrollArea->height(); + + m_scrollArea->ensureVisible(x, y, 0, 0); +} + +void PDFDocument::rebuildRanges() +{ + QVBoxLayout *l = qobject_cast (m_pdfLabel->layout()); + m_ranges.clear(); + int height = l->contentsMargins().top(); + for (PDFPage *p : qAsConst(m_pages)) + { + m_ranges += height; + height += p->height(); + height += l->spacing(); + } + m_pdfLabel->resize(m_pdfLabel->sizeHint()); + m_pdfLabel->setMinimumSize(m_pdfLabel->sizeHint()); +} + +} diff --git a/Z/src/nglwidgets/nglpdfdocument.h b/Z/src/nglwidgets/nglpdfdocument.h new file mode 100755 index 000000000..827804e94 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfdocument.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "nglwidgets_export.h" + +namespace Poppler +{ +class Document; +class LinkDestination; +} +class QUrl; +class QScrollArea; +namespace NGL +{ +class PDFPage; + + +class NGLWIDGETS_EXPORT PDFDocument : public QWidget +{ + Q_OBJECT +public: + + + explicit PDFDocument(QWidget *parent = nullptr); + + + virtual ~PDFDocument(); + + + + int curPage() const; + + + int numPages() const; + +public Q_SLOTS: + + + bool showPDF(const QString &path); + + + + bool showPDF(const QUrl &url); + + + + bool showPDF(const QByteArray &pdf); + + + + void setZoomFactor(double zoom); + + void setRotation(Poppler::Page::Rotation rot); + + + + bool setPage(int page); + + + bool nextPage(); + + + bool previousPage(); + + void resizePdfToWidth(); + +public: + Poppler::Page::Rotation getRotation() const { return m_rotation; } + + + + QVector getPrintableImages(int resolution = 300) const; + + + + QImage getPrintableImage(int pageNum, int resolution = 300) const; + +Q_SIGNALS: + + + void currentPageChanged(int cur, int max); + + + void rotationChanged(Poppler::Page::Rotation rot); + + + void linkClicked(const QString &url); + +protected Q_SLOTS: + void onVSliderValueChanged(int y); + void onPageRendered(); + void onLinkClicked(const Poppler::LinkDestination &dest); + +protected: + bool showPDFInternal(); + void ensureCurPageVisible(int xOfs = 0, int yOfs = 0); + void rebuildRanges(); + + Poppler::Document *m_doc; + int m_currentPage; + int m_maxCachedPages; + double m_scaleFactor; + double m_widthFactor; + QString m_currentPath; + + QWidget *m_pdfLabel; + QScrollArea *m_scrollArea; + QVector m_pages; + QVector m_ranges; + QVector > m_renderedPages; + Poppler::Page::Rotation m_rotation; +}; +} diff --git a/Z/src/nglwidgets/nglpdfpage.cpp b/Z/src/nglwidgets/nglpdfpage.cpp new file mode 100755 index 000000000..8c25eb453 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfpage.cpp @@ -0,0 +1,203 @@ +#include "nglpdfpage.h" + +#include +#include +#include +#include +#include + +namespace NGL +{ +template +static inline T getRotatedSize(const T &in, Poppler::Page::Rotation rot) +{ + switch (rot) + { + case Poppler::Page::Rotate0: + case Poppler::Page::Rotate180: + return in; + case Poppler::Page::Rotate90: + case Poppler::Page::Rotate270: + return in.transposed(); + } + Q_ASSERT(false); + return in; +} + +PDFPage::PDFPage(QWidget *parent) + : QWidget(parent) + , m_page(nullptr) + , m_scaleFactor(1.0) + , m_rotation(Poppler::Page::Rotate0) +{ + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + setMouseTracking(true); +} + +PDFPage::~PDFPage() +{ + delete m_page; +} + +void PDFPage::setPopplerPage(Poppler::Page *page) +{ + if (m_page == page) + return; + delete m_page; + m_page = page; + m_links.clear(); + m_linkRects.clear(); + if (!m_page) + return; + + const QList links = m_page->links(); + for (const auto link : links) + { + if (link->linkType() == Poppler::Link::Browse || + link->linkType() == Poppler::Link::Goto) + m_links += link; + else + std::cerr << "linktype: " << link->linkType() << std::endl; + } + + rebuildInternalData(); +} + +void PDFPage::setZoomFactor(double zoom) +{ + if (qFuzzyCompare(m_scaleFactor, zoom)) + return; + m_scaleFactor = zoom; + rebuildInternalData(); +} + +void PDFPage::setRotation(Poppler::Page::Rotation rot) +{ + if (m_rotation == rot) + return; + m_rotation = rot; + rebuildInternalData(); +} + +void PDFPage::clearPixmap() +{ + m_pdfPixmap = QPixmap(); +} + +QImage PDFPage::getPrintableImage(int resolution) const +{ + if (!m_page) + return QImage(); + + + Poppler::Page::Rotation rot = Poppler::Page::Rotate0; + + if (m_page->orientation() == Poppler::Page::Landscape) + rot = Poppler::Page::Rotate270; + else if (m_page->orientation() == Poppler::Page::Seascape) + rot = Poppler::Page::Rotate90; + else if (m_page->orientation() == Poppler::Page::UpsideDown) + rot = Poppler::Page::Rotate180; + Q_UNUSED(rot) + + + return m_page->renderToImage(resolution, resolution, -1, -1, -1, -1, m_rotation); +} + +QSize PDFPage::sizeHint() const +{ + if (!m_page) + return QSize(); + return getRotatedSize(m_page->pageSize(), m_rotation); +} + +void PDFPage::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + if (!m_page) + return; + if (m_pdfPixmap.isNull()) + { + const QImage img = m_page->renderToImage(m_scaleFactor * 72, m_scaleFactor * 72, -1, -1, -1, -1, m_rotation); + m_pdfPixmap = QPixmap::fromImage(img); + emit pageRendered(); + } + QPainter p(this); + p.drawPixmap(0, 0, m_pdfPixmap); + p.end(); +} + +void PDFPage::mouseMoveEvent(QMouseEvent *event) +{ + const QPointF pos = event->localPos(); + for (const auto &linkRect : qAsConst(m_linkRects)) + { + if (linkRect.contains(pos)) + { + setCursor(Qt::PointingHandCursor); + return; + } + } + setCursor(Qt::ArrowCursor); + QWidget::mouseMoveEvent(event); +} + +void PDFPage::mouseReleaseEvent(QMouseEvent *event) +{ + const QPointF pos = event->localPos(); + for (int i = 0; i < m_linkRects.size(); ++i) + { + if (m_linkRects.at(i).contains(pos)) + { + const auto *link = m_links.at(i); + if (link->linkType() == Poppler::Link::Browse) + { + const Poppler::LinkBrowse *linkBrowse = static_cast(link); + emit externalLinkClicked(linkBrowse->url()); + return; + } + else if (link->linkType() == Poppler::Link::Goto) + { + const Poppler::LinkGoto *linkGoto = static_cast(link); + if (linkGoto->isExternal()) + { + const QUrl url = QUrl::fromLocalFile(linkGoto->fileName()); + emit externalLinkClicked(url.toString()); + return; + } + emit linkClicked(linkGoto->destination()); + return; + } + } + } + QWidget::mouseReleaseEvent(event); +} + +void PDFPage::rebuildInternalData() +{ + clearPixmap(); + + if (!m_page) + return; + + const QSizeF s(rotatedPageSize()); + const int w = qRound(s.width() * m_scaleFactor); + const int h = qRound(s.height() * m_scaleFactor); + setMinimumSize(w, h); + resize(sizeHint()); + + + m_linkRects.clear(); + m_linkRects.reserve(m_links.size()); + for (const auto link : qAsConst(m_links)) + { + const QRectF r = link->linkArea(); + m_linkRects += QRectF(r.x() * w, r.y() * h, r.width() * w, r.height() * h); + } +} + +QSizeF PDFPage::rotatedPageSize() const +{ + return m_page ? getRotatedSize(m_page->pageSizeF(), m_rotation) : QSizeF(); +} +} diff --git a/Z/src/nglwidgets/nglpdfpage.h b/Z/src/nglwidgets/nglpdfpage.h new file mode 100755 index 000000000..be39dbf77 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfpage.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Poppler +{ +class Page; +class Link; +class LinkDestination; +} + +namespace NGL +{ + + +class PDFPage final : public QWidget +{ + Q_OBJECT +public: + explicit PDFPage(QWidget *parent = nullptr); + virtual ~PDFPage(); + + void setPopplerPage(Poppler::Page *page); + void setZoomFactor(double zoom); + void setRotation(Poppler::Page::Rotation rot); + void clearPixmap(); + QImage getPrintableImage(int resolution = 300) const; + QSize sizeHint() const override; +Q_SIGNALS: + void pageRendered(); + + void externalLinkClicked(const QString &url); + + void linkClicked(const Poppler::LinkDestination &dest); +protected: + void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; +private: + void rebuildInternalData(); + QSizeF rotatedPageSize() const; +protected: + Poppler::Page *m_page; + double m_scaleFactor; + QPixmap m_pdfPixmap; + QList< Poppler::Link * > m_links; + QList< QRectF > m_linkRects; + Poppler::Page::Rotation m_rotation; +}; +} diff --git a/Z/src/nglwidgets/nglpdfwidget.cpp b/Z/src/nglwidgets/nglpdfwidget.cpp new file mode 100755 index 000000000..0f13d721a --- /dev/null +++ b/Z/src/nglwidgets/nglpdfwidget.cpp @@ -0,0 +1,151 @@ + + +#include "nglpdfwidget.h" +#include "ui_nglpdfwidget.h" + +static const double s_maxZoom = 3.0; +static const double s_minZoom = 1.0; + +namespace NGL +{ +PDFWidget::PDFWidget(QWidget *parent) + : QWidget(parent) + , m_zoomFactor(1.0) + , ui(new Ui::pdfWidget) +{ + ui->setupUi(this); + ui->zoomFull->setVisible(false); + ui->zoom100->setVisible(false); + ui->pageLabel->setAutoFillBackground(true); + + connect(ui->previousPage, &QToolButton::clicked, ui->pdfDocument, &PDFDocument::previousPage); + connect(ui->nextPage, &QToolButton::clicked, ui->pdfDocument, &PDFDocument::nextPage); + connect(ui->zoom100, &QToolButton::clicked, this, &PDFWidget::onZoomDefault); + connect(ui->zoomMinus, &QToolButton::clicked, this, &PDFWidget::onZoomMinus); + connect(ui->zoomPlus, &QToolButton::clicked, this, &PDFWidget::onZoomPlus); + connect(ui->zoomFull, &QToolButton::clicked, this, &PDFWidget::onZoomFull); + + + connect(ui->pdfDocument, &PDFDocument::currentPageChanged, this, &PDFWidget::pageChanged); + connect(ui->rotateDoc, &QToolButton::clicked, this, &PDFWidget::rotate); + connect(ui->pdfDocument, &PDFDocument::currentPageChanged, this, &PDFWidget::currentPageChanged); + connect(ui->pdfDocument, &PDFDocument::rotationChanged, this, &PDFWidget::rotationChanged); +} + +PDFWidget::~PDFWidget() +{ + delete ui; +} + +bool PDFWidget::showPDF(const QUrl &pdf) +{ + return ui->pdfDocument->showPDF(pdf); +} + +bool PDFWidget::showPDF(const QByteArray &pdf) +{ + return ui->pdfDocument->showPDF(pdf); +} + +void PDFWidget::setZoomFactor(double newZoomFactor) +{ + m_zoomFactor = newZoomFactor; + ui->pdfDocument->setZoomFactor(newZoomFactor); +} + +void PDFWidget::setRotation(Poppler::Page::Rotation rot) +{ + ui->pdfDocument->setRotation(rot); +} + +bool PDFWidget::setPage(int newPage) +{ + return ui->pdfDocument->setPage(newPage); +} + +int PDFWidget::numPages() const +{ + return ui->pdfDocument->numPages(); +} + +int PDFWidget::curPage() const +{ + return ui->pdfDocument->curPage(); +} + +QVector PDFWidget::getPrintableImages(int resolution) const +{ + return ui->pdfDocument->getPrintableImages(resolution); +} + +void PDFWidget::resizePdfToWidth() +{ + ui->pdfDocument->resizePdfToWidth(); +} + +void PDFWidget::pageChanged(int cur, int max) +{ + if (cur < 1) + { + ui->pdfDocument->setPage(1); + return; + } + ui->pageLabel->setText(tr("Page %1 of %2").arg(cur).arg(max)); + ui->nextPage->setEnabled(cur < max); + ui->previousPage->setEnabled(cur > 1); +} + +void PDFWidget::rotate() +{ + Poppler::Page::Rotation rot0 = ui->pdfDocument->getRotation(); + Poppler::Page::Rotation rot1 = rot0; + switch (rot0) + { + case Poppler::Page::Rotate0: + rot1 = Poppler::Page::Rotate90; + break; + case Poppler::Page::Rotate90: + rot1 = Poppler::Page::Rotate180; + break; + case Poppler::Page::Rotate180: + rot1 = Poppler::Page::Rotate270; + break; + case Poppler::Page::Rotate270: + rot1 = Poppler::Page::Rotate0; + break; + } + ui->pdfDocument->setRotation(rot1); +} + +void PDFWidget::onZoomDefault() +{ + ui->pdfDocument->setZoomFactor(1.0); + m_zoomFactor = 1.0; +} +void PDFWidget::onZoomFull() +{ + ui->pdfDocument->resizePdfToWidth(); + m_zoomFactor = 1.0; +} + + +void PDFWidget::onZoomMinus() +{ + if (m_zoomFactor > s_minZoom) + m_zoomFactor -= 0.20; + if (m_zoomFactor < s_minZoom) + m_zoomFactor = s_minZoom; + ui->pdfDocument->setZoomFactor(m_zoomFactor); +} + +void PDFWidget::onZoomPlus() +{ + if (m_zoomFactor < s_maxZoom) + m_zoomFactor += 0.20; + if(m_zoomFactor > s_maxZoom) + m_zoomFactor = s_maxZoom; + ui->pdfDocument->setZoomFactor(m_zoomFactor); + +} + +} diff --git a/Z/src/nglwidgets/nglpdfwidget.h b/Z/src/nglwidgets/nglpdfwidget.h new file mode 100755 index 000000000..16aca38ff --- /dev/null +++ b/Z/src/nglwidgets/nglpdfwidget.h @@ -0,0 +1,48 @@ + + +#pragma once +#include +#include + +#include "nglwidgets_export.h" + +class QUrl; +namespace Ui +{ +class pdfWidget; +} + +namespace NGL +{ +class NGLWIDGETS_EXPORT PDFWidget : public QWidget +{ + Q_OBJECT +public: + explicit PDFWidget(QWidget *parent = nullptr); + ~PDFWidget(); + + bool showPDF(const QUrl &pdf); + bool showPDF(const QByteArray &pdf); + void setZoomFactor(double newZoomFactor); + void setRotation(Poppler::Page::Rotation rot); + bool setPage(int newPage); + QVector getPrintableImages(int resolution = 300) const; + void resizePdfToWidth(); + int numPages() const; + int curPage() const; + +Q_SIGNALS: + void currentPageChanged(int cur, int max); + void rotationChanged(Poppler::Page::Rotation newRotation); +protected Q_SLOTS: + void pageChanged(int cur, int max); + void rotate(); + void onZoomDefault(); + void onZoomFull(); + void onZoomMinus(); + void onZoomPlus(); +protected: + double m_zoomFactor; + Ui::pdfWidget *ui; +}; +} diff --git a/Z/src/nglwidgets/nglpdfwidget.ui b/Z/src/nglwidgets/nglpdfwidget.ui new file mode 100755 index 000000000..ad7119619 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfwidget.ui @@ -0,0 +1,253 @@ + + + pdfWidget + + + + 0 + 0 + 580 + 396 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 202 + 20 + + + + + + + + Qt::Horizontal + + + + 201 + 20 + + + + + + + + + + + 0 + 30 + + + + + + + + :/style/media-seek-backward.svg:/style/media-seek-backward.svg + + + Ctrl+P + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + - + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 0 + 30 + + + + + + + + :/style/media-seek-forward.svg:/style/media-seek-forward.svg + + + + 16 + 16 + + + + Ctrl+N + + + + + + + + + + + :/style/restart.svg:/style/restart.svg + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + - + + + + :/icons/16x16/zoom-out.png:/icons/16x16/zoom-out.png + + + + + + + + 0 + 0 + + + + + 16777215 + 32 + + + + 1:1 + + + + + + + ... + + + + :/icons/16x16/view-fullscreen.png:/icons/16x16/view-fullscreen.png + + + + + + + + + + + + :/icons/16x16/zoom-in.png:/icons/16x16/zoom-in.png + + + + + + + + + + NGL::PDFDocument + QWidget +

nglwidgets/nglpdfdocument.h
+ 1 + + + + + + + + + + diff --git a/Z/src/nglwidgets/nglresources.qrc b/Z/src/nglwidgets/nglresources.qrc new file mode 100755 index 000000000..57fe99851 --- /dev/null +++ b/Z/src/nglwidgets/nglresources.qrc @@ -0,0 +1,669 @@ + + + icons/32x32/hand_grenade_locations.png + icons/svg/switch_display_disabled.svg + icons/svg/switch_display.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/announcement_menu_disabled.svg + icons/svg/announcement_menu.svg + icons/svg/mortar_ammunition_firings_disabled.svg + icons/svg/mortar_ammunition_firings.svg + icons/svg/mortar_ammunition_administration_disabled.svg + icons/svg/mortar_ammunition_administration.svg + icons/svg/arrow_back_disabled.svg + icons/svg/arrow_back.svg + icons/svg/filter_barriers_disabled.svg + icons/svg/filter_barriers.svg + icons/svg/chemical_agents_disabled.svg + icons/svg/chemical_agents.svg + icons/svg/define_border_lines_disabled.svg + icons/svg/define_border_lines.svg + icons/svg/filter_collapse_expand_disabled.svg + icons/svg/filter_collapse_expand.svg + icons/svg/create_distance_measure_disabled.svg + icons/svg/create_distance_measure.svg + icons/svg/show_distance_measure_disabled.svg + icons/svg/show_distance_measure.svg + icons/svg/organize_documents_disabled.svg + icons/svg/organize_documents.svg + icons/svg/configure_buildings_disabled.svg + icons/svg/configure_buildings.svg + icons/svg/edit-cut.svg + icons/svg/evaluation_elements_disabled.svg + icons/svg/evaluation_elements.svg + icons/svg/electronical_warfare_measures_disabled.svg + icons/svg/electronical_warfare_measures.svg + icons/svg/define_training_cycles_disabled.svg + icons/svg/define_training_cycles.svg + icons/svg/select_training_cylces_disabled.svg + icons/svg/select_training_cylces.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/exercise_purpose_disabled.svg + icons/svg/exercise_purpose.svg + icons/svg/set_exercise_process_disabled.svg + icons/svg/set_exercise_process.svg + icons/svg/export_documents_disabled.svg + icons/svg/export_documents.svg + icons/svg/filter_border_lines_disabled.svg + icons/svg/filter_border_lines.svg + icons/svg/filter_firings_disabled.svg + icons/svg/filter_firings.svg + icons/svg/load_global_filter_disabled.svg + icons/svg/load_global_filter.svg + icons/svg/filter_player_disabled.svg + icons/svg/filter_player.svg + icons/svg/filter_teams_disabled.svg + icons/svg/filter_teams.svg + icons/svg/force_composition_disabled.svg + icons/svg/force_composition.svg + icons/svg/exercise_force_disabled.svg + icons/svg/exercise_force.svg + icons/svg/force_organization_disabled.svg + icons/svg/force_organization.svg + icons/svg/force_player_configuration_disabled.svg + icons/svg/force_player_configuration.svg + icons/svg/freq_plan.svg + icons/svg/config_gobal_alarms_disabled.svg + icons/svg/global_alarms_history_disabled.svg + icons/svg/global_alarms_history.svg + icons/svg/config_gobal_alarms.svg + icons/svg/global_exercise_settings_disabled.svg + icons/svg/global_exercise_settings.svg + icons/svg/plans_disabled.svg + icons/svg/plans.svg + icons/svg/import_documents_disabled.svg + icons/svg/import_documents.svg + icons/svg/import_pdf_document_disabled.svg + icons/svg/import_pdf_document.svg + icons/svg/import_images_disabled.svg + icons/svg/import_images.svg + icons/svg/organize_library_disabled.svg + icons/svg/organize_library.svg + icons/svg/default_operator_rights_disabled.svg + icons/svg/default_operator_rights.svg + icons/svg/define_tactical_symbols_disabled.svg + icons/svg/define_tactical_symbols.svg + icons/svg/define_force_templates_disabled.svg + icons/svg/define_force_templates.svg + icons/svg/configure_line_of_sight_disabled.svg + icons/svg/configure_line_of_sight.svg + icons/svg/show_line_of_sight_disabled.svg + icons/svg/show_line_of_sight.svg + icons/svg/configure_line_of_sight_disabled.svg + icons/svg/configure_line_of_sight.svg + icons/svg/map_context_menu_disabled.svg + icons/svg/map_context_menu.svg + icons/svg/marker-end.svg + icons/svg/edit_evaluation_marker_disabled.svg + icons/svg/edit_evaluation_marker.svg + icons/svg/metereological_data_disabled.svg + icons/svg/metereological_data.svg + icons/svg/mine_barrier_corridor_disabled.svg + icons/svg/mine_barrier_corridor.svg + icons/svg/mine_barriers_disabled.svg + icons/svg/mine_barriers.svg + icons/svg/define_movement_simulation_disabled.svg + icons/svg/define_movement_simulation.svg + icons/svg/filter_nc_agents_disabled.svg + icons/svg/filter_nbc_agents.svg + icons/svg/oc_aar_preparation_disabled.svg + icons/svg/oc_aar_preparation.svg + icons/svg/oc_evaluation_schemes_disabled.svg + icons/svg/oc_evaluation_schemes.svg + icons/svg/display_oc_evaluations_disabled.svg + icons/svg/display_oc_evaluations.svg + icons/svg/oc_player_configuration_disabled.svg + icons/svg/oc_player_configuration.svg + icons/svg/organize_documents_disabled.svg + icons/svg/organize_documents.svg + icons/svg/operator_administration_disabled.svg + icons/svg/operator_administration.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/plans_disabled.svg + icons/svg/plans.svg + icons/svg/organize_documents_disabled.svg + icons/svg/organize_documents.svg + icons/svg/plans_disabled.svg + icons/svg/plans.svg + icons/svg/overlay_plans_disabled.svg + icons/svg/overlay_plans.svg + icons/svg/define_border_lines_disabled.svg + icons/svg/define_border_lines.svg + icons/svg/player_equipment_check_disabled.svg + icons/svg/player_equipment_check.svg + icons/svg/send_player_message_disabled.svg + icons/svg/send_player_message.svg + icons/svg/set_player_mode_disabled.svg + icons/svg/set_player_mode.svg + icons/svg/player_mode.svg + icons/svg/update_player_position_disabled.svg + icons/svg/update_player_position.svg + icons/svg/select_player_disabled.svg + icons/svg/select_player.svg + icons/svg/set_player_status_disabled.svg + icons/svg/set_player_status.svg + icons/svg/define_presentation_disabled.svg + icons/svg/define_presentation.svg + icons/svg/execute_presentation_disabled.svg + icons/svg/execute_presentation.svg + icons/svg/primary_map_position_disabled.svg + icons/svg/primary_map_position.svg + icons/svg/create_terrain_profile_disabled.svg + icons/svg/create_terrain_profile.svg + icons/svg/show_terrain_profile_disabled.svg + icons/svg/show_terrain_profile.svg + icons/svg/report_ammunition_left_disabled.svg + icons/svg/report_ammunition_left.svg + icons/svg/report_ammunition_resupply_disabled.svg + icons/svg/report_ammunition_resupply.svg + icons/svg/report_awes_disabled.svg + icons/svg/report_awes.svg + icons/svg/report_combat_power_disabled.svg + icons/svg/report_combat_power.svg + icons/svg/display_reports_disabled.svg + icons/svg/display_reports.svg + icons/svg/report_explosive_devices_disabled.svg + icons/svg/report_explosive_devices.svg + icons/svg/report_maintenance_disabled.svg + icons/svg/report_maintenance.svg + icons/svg/report_mine_barrier_disabled.svg + icons/svg/report_mine_barrier.svg + icons/svg/report_nbc_events_disabled.svg + icons/svg/report_nbc_events.svg + icons/svg/report_nc_events_disabled.svg + icons/svg/report_nc_events.svg + icons/svg/report_treatment_disabled.svg + icons/svg/report_treatment.svg + icons/svg/report_mortar_firings_disabled.svg + icons/svg/report_mortar_firings.svg + icons/svg/secondary_map_position_disabled.svg + icons/svg/secondary_map_position.svg + icons/svg/select_training_areas_disabled.svg + icons/svg/select_training_areas.svg + icons/svg/system_status.svg + icons/svg/change_password_disabled.svg + icons/svg/change_password.svg + icons/svg/show_building_configuration_disabled.svg + icons/svg/show_building_configuration.svg + icons/svg/simulated_players_disabled.svg + icons/svg/simulated_players.svg + icons/svg/create_snapshot_disabled.svg + icons/svg/create_snapshot.svg + icons/svg/system_status_disabled.svg + icons/svg/system_status.svg + icons/svg/configure_symbol_attributes_disabled.svg + icons/svg/configure_symbol_attributes.svg + icons/svg/symbol_display_disabled.svg + icons/svg/symbol_display.svg + icons/svg/tactical_organization_disabled.svg + icons/svg/tactical_organization.svg + icons/svg/tactical_symbol_disabled.svg + icons/svg/tactical_symbol.svg + icons/svg/objects_define_areas_disabled.svg + icons/svg/objects_define_areas.svg + icons/svg/define_teams_disabled.svg + icons/svg/define_teams.svg + icons/svg/terminal_window_disabled.svg + icons/svg/terminal_window.svg + icons/svg/create_thp_disabled.svg + icons/svg/create_thp.svg + icons/svg/delete_thp_disabled.svg + icons/svg/delete_thp.svg + icons/svg/prepare_thp_disabled.svg + icons/svg/prepare_thp.svg + icons/svg/filter_map_settings_disabled.svg + icons/svg/filter_map_settings.svg + icons/svg/toolbar_editor_disabled.svg + icons/svg/toolbar_editor.svg + icons/svg/translation_editor.svg + icons/svg/translation_editor.svg + icons/svg/help_index_disabled.svg + icons/svg/help_index.svg + icons/svg/define_player_types_disabled.svg + icons/svg/define_player_types.svg + icons/svg/announcement_disabled.svg + icons/svg/announcement.svg + icons/svg/access_rights_disabled.svg + icons/svg/access_rights.svg + icons/svg/mgrs_grid_disabled.svg + icons/svg/mgrs_grid.svg + icons/svg/import_video_disabled.svg + icons/svg/import_video.svg + icons/svg/video_menu_disabled.svg + icons/svg/video_menu.svg + icons/svg/filter_effect_simulation_disabled.svg + icons/svg/filter_effect_simulation.svg + icons/16x16/application-pdf.png + icons/16x16/arrow-left.png + icons/16x16/arrow-right.png + icons/16x16/audio-x-generic.png + icons/16x16/bg.gif + icons/16x16/camera-photo.png + icons/16x16/configure.png + icons/16x16/dialog-close.png + icons/16x16/dialog-ok-apply.png + icons/16x16/dialog-ok.png + icons/16x16/dirs.png + icons/16x16/document-edit.png + icons/16x16/document-import.png + icons/16x16/document-new.png + icons/16x16/document-open-data.png + icons/16x16/document-open.png + icons/16x16/document-preview.png + icons/16x16/document-print.png + icons/16x16/document-properties.png + icons/16x16/document-save-all.png + icons/16x16/document-save-as.png + icons/16x16/document-save.png + icons/16x16/download.png + icons/16x16/draw-bezier-curves.png + icons/16x16/draw-ellipse.png + icons/16x16/draw-line.png + icons/16x16/draw-polygon.png + icons/16x16/draw-polyline.png + icons/16x16/draw-rectangle.png + icons/16x16/draw-text.png + icons/16x16/edit-clear-locationbar-rtl.png + icons/16x16/edit-copy.png + icons/16x16/edit-cut.png + icons/16x16/edit-delete.png + icons/16x16/edit-paste.png + icons/16x16/edit-redo.png + icons/16x16/edit-rename.png + icons/16x16/edit-select.png + icons/16x16/edit-undo.png + icons/16x16/fill-color.png + icons/16x16/format-justify-center.png + icons/16x16/format-justify-fill.png + icons/16x16/format-justify-left.png + icons/16x16/format-justify-right.png + icons/16x16/format-stroke-color.png + icons/16x16/format-text-bold.png + icons/16x16/format-text-italic.png + icons/16x16/format-text-underline.png + icons/16x16/freu.gif + icons/16x16/go-down.png + icons/16x16/go-home.png + icons/16x16/go-next.png + icons/16x16/go-previous.png + icons/16x16/go-up.png + icons/16x16/help-about.png + icons/16x16/help-contents.png + icons/16x16/image-x-generic.png + icons/16x16/internet-mail.png + icons/16x16/led-blue-on.png + icons/16x16/led-gray-on.png + icons/16x16/led-green-on.png + icons/16x16/led-red-on.png + icons/16x16/led-yellow-on.png + icons/16x16/list-add.png + icons/16x16/list-add-user.png + icons/16x16/list-remove.png + icons/16x16/list-remove-user.png + icons/16x16/mail-mark-read.png + icons/16x16/mail-mark-unread.png + icons/16x16/mail-message-new.png + icons/16x16/mail-send.png + icons/16x16/media-eject.png + icons/16x16/media-flash.png + icons/16x16/media-playback-pause.png + icons/16x16/media-playback-start.png + icons/16x16/media-playback-stop.png + icons/16x16/media-play-faster.png + icons/16x16/media-play-normal.png + icons/16x16/media-play-slower.png + icons/16x16/media-record.png + icons/16x16/media-seek-backward.png + icons/16x16/media-seek-forward.png + icons/16x16/media-skip-backward.png + icons/16x16/media-skip-forward.png + icons/16x16/object-group.png + icons/16x16/object-ungroup.png + icons/16x16/oO.gif + icons/16x16/ooo-calc.png + icons/16x16/ooo-impress.png + icons/16x16/ooo-writer.png + icons/16x16/preferences-desktop-font.png + icons/16x16/preferences-web-browser-cache.png + icons/16x16/printer.png + icons/16x16/process-stop.png + icons/16x16/rde_16x16.png + icons/16x16/rde.ico + icons/16x16/system-help.png + icons/16x16/text-plain.png + icons/16x16/transform-move.png + icons/16x16/transform-rotate.png + icons/16x16/transform-scale.png + icons/16x16/traurig.gif + icons/16x16/video-x-generic.png + icons/16x16/view-fullscreen.png + icons/16x16/view-statistics.png + icons/16x16/weinend.gif + icons/16x16/x-office-address-book.png + icons/16x16/yellow-off-16.png + icons/16x16/yellow-on-16.png + icons/16x16/zoom-in.png + icons/16x16/zoom-out.png + icons/16x16/zunge.gif + icons/16x16/zwinker.gif + icons/22x22/dialogbuttonbox.png + icons/22x22/edit-redo.png + icons/22x22/format-justify-center.png + icons/22x22/format-justify-fill.png + icons/22x22/format-justify-left.png + icons/22x22/format-justify-right.png + icons/22x22/format-stroke-color.png + icons/22x22/format-text-bold.png + icons/22x22/format-text-italic.png + icons/22x22/format-text-underline.png + icons/22x22/kdialog.png + icons/22x22/klineedit.png + icons/22x22/layer.png + icons/22x22/pushbutton.png + icons/22x22/scricon.png + icons/32x32/marker-end.png + icons/32x32/marker-start.png + icons/32x32/media-eject.png + icons/32x32/media-playback-pause.png + icons/32x32/media-playback-start.png + icons/32x32/media-playback-start-single.png + icons/32x32/media-playback-stop.png + icons/32x32/media-play-backward.png + icons/32x32/media-play-faster.png + icons/32x32/media-play-normal.png + icons/32x32/media-play-slower.png + icons/32x32/media-record.png + icons/32x32/media-seek-backward.png + icons/32x32/media-seek-forward.png + icons/32x32/media-skip-backward.png + icons/32x32/media-skip-forward.png + icons/32x32/media-vcr-nopause.png + icons/32x32/media-vcr-normal.png + icons/32x32/media-vcr-repeat.png + icons/32x32/media-vcr-withpause.png + icons/32x32/service_message.png + icons/32x32/wireless.png + icons/png/add_disabled.png + icons/png/add.png + icons/png/address_book.png + icons/png/add_tactical_sign_act_disabled.png + icons/png/add_tactical_sign_act.png + icons/png/add_text_act_disabled.png + icons/png/add_text_act.png + icons/png/big_letters_act_disabled.png + icons/png/big_letters_act.png + icons/png/camera_arrow_down.png + icons/png/camera_arrow_left.png + icons/png/camera_arrow_right.png + icons/png/camera_arrow_up.png + icons/png/center_object_in_map_act_disabled.png + icons/png/center_object_in_map_act.png + icons/png/clear_plan_act_disabled.png + icons/png/clear_plan_act.png + icons/png/copy_exercise_disabled.png + icons/png/copy_exercise.png + icons/png/deleteall.png + icons/png/delete_disabled.png + icons/png/delete_exercise_disabled.png + icons/png/delete_exercise.png + icons/png/delete_graphic_eass_disabled.png + icons/png/delete_graphic_eass.png + icons/png/delete.png + icons/png/download.png + icons/png/draw_ellipse_act_disabled.png + icons/png/draw_ellipse_act.png + icons/png/draw_line_disabled.png + icons/png/draw_line.png + icons/png/draw_polygon_act_disabled.png + icons/png/draw_polygon_act.png + icons/png/draw_rectangle_act_disabled.png + icons/png/draw_rectangle_act.png + icons/png/draw_spline_disabled.png + icons/png/draw_spline.png + icons/png/eass_line_disabled.png + icons/png/eass_line.png + icons/png/eass_polygon_disabled.png + icons/png/eass_polygon.png + icons/png/edit_element_act_disabled.png + icons/png/edit_element_act.png + icons/png/edith_graphic_eass_disabled.png + icons/png/edith_graphic_eass.png + icons/png/fast_playback_backward_disabled.png + icons/png/fast_playback_backward.png + icons/png/fast_playback_disabled.png + icons/png/fast_playback.png + icons/png/fill_colour_act_disabled.png + icons/png/fill_colour_act.png + icons/png/folder_open.png + icons/png/kosy_audio_control_act_disabled.png + icons/png/kosy_audio_control_act.png + icons/png/kosy_radio_error_act_disabled.png + icons/png/kosy_radio_error_act.png + icons/png/kosy_remote_control_act_disabled.png + icons/png/kosy_remote_control_act.png + icons/png/line_color.png + icons/png/marker_left_disabled.png + icons/png/marker_left.png + icons/png/marker_right_disabled.png + icons/png/marker_right.png + icons/png/messages_new.png + icons/png/missionmarch_disabled.png + icons/png/missionmarch.png + icons/png/normal_letters_act_disabled.png + icons/png/normal_letters_act.png + icons/png/ok_disabled.png + icons/png/ok.png + icons/png/paste_exercise_disabled.png + icons/png/paste_exercise.png + icons/png/pause_playback_disabled.png + icons/png/pause_playback.png + icons/png/polygonmap_disabled.png + icons/png/polygonmap.png + icons/png/position_map_disabled.png + icons/png/position_map.png + icons/png/preview.png + icons/png/printer.png + icons/png/redo_disabled.png + icons/png/redo.png + icons/png/remove_disabled.png + icons/png/remove.png + icons/png/rename_exercise_disabled.png + icons/png/rename_exercise.png + icons/png/save_as.png + icons/png/save.png + icons/png/settings_disabled.png + icons/png/settings.png + icons/png/start_playback_disabled.png + icons/png/start_playback.png + icons/png/stop_playback_disabled.png + icons/png/stop_playback.png + icons/png/stop.png + icons/png/thick_line_act_disabled.png + icons/png/thick_line_act.png + icons/png/undo_act_disabled.png + icons/png/undo_act.png + icons/png/zoom_in_disabled.png + icons/png/zoom_in.png + icons/png/zoom_out_disabled.png + icons/png/zoom_out.png + icons/svg/3d_viewer_config_disabled.svg + icons/svg/3d_viewer_config.svg + icons/svg/3d_viewer_disabled.svg + icons/svg/3d_viewer.svg + icons/svg/about_disabled.svg + icons/svg/about.svg + icons/svg/ac_adapter_plugged_in.svg + icons/svg/aircraft_sim.svg + icons/svg/application-exit.svg + icons/svg/artillery_firings_disabled.svg + icons/svg/artillery_firings.svg + icons/svg/audio-volume-high.svg + icons/svg/audio-volume-low.svg + icons/svg/audio-volume-medium.svg + icons/svg/audio-volume-muted.svg + icons/svg/battery_mode.svg + icons/svg/camera_control_disabled.svg + icons/svg/camera_control.svg + icons/svg/chat_disabled.svg + icons/svg/chat.svg + icons/svg/configure_arrow.svg + icons/svg/configure_tunnels_disabled.svg + icons/svg/configure_tunnels.svg + icons/svg/create_evaluation_topic.svg + icons/svg/create_image_topic.svg + icons/svg/create_lecture_topic.svg + icons/svg/create_pdf_topic.svg + icons/svg/danger_areas.svg + icons/svg/debug-execute-from-cursor.svg + icons/svg/debug-execute-to-cursor.svg + icons/svg/define_position_system_disabled.svg + icons/svg/define_position_system.svg + icons/svg/dialog-close.svg + icons/svg/dialog-ok-apply.svg + icons/svg/dialog-ok.svg + icons/svg/document-edit.svg + icons/svg/document-new.svg + icons/svg/document-open-data.svg + icons/svg/document-open.svg + icons/svg/document-properties.svg + icons/svg/download.svg + icons/svg/draw-bezier-curves.svg + icons/svg/evaluate_disabled.svg + icons/svg/evaluate.svg + icons/svg/fill_pattern.svg + icons/svg/filter_line_of_sight_disabled.svg + icons/svg/filter_line_of_sight.svg + icons/svg/filter_map_settings_load_disabled.svg + icons/svg/filter_map_settings_load.svg + icons/svg/filter_maps_settings_save_disabled.svg + icons/svg/filter_maps_settings_save.svg + icons/svg/filter_nbc_agents_disabled.svg + icons/svg/fixed_video_announcement_disabled.svg + icons/svg/fixed_video_announcement.svg + icons/svg/function_key_toolbar_disabled.svg + icons/svg/function_key_toolbar.svg + icons/svg/getpos.svg + icons/svg/go-home.svg + icons/svg/hand_grenade_locations.svg + icons/svg/import_msdl.svg + icons/svg/insert_script.svg + icons/svg/karte.svg + icons/svg/layer.svg + icons/svg/line_styles.svg + icons/svg/list-add-user.svg + icons/svg/list-remove-user.svg + icons/svg/load_disabled.svg + icons/svg/load.svg + icons/svg/logout_disabled.svg + icons/svg/logout.svg + icons/svg/map_settings_disabled.svg + icons/svg/map_settings.svg + icons/svg/marker-start.svg + icons/svg/marke.svg + icons/svg/media-flash.svg + icons/svg/media-play-backward.svg + icons/svg/media-play-slower.svg + icons/svg/media-record.svg + icons/svg/media-seek-backward.svg + icons/svg/media-seek-forward.svg + icons/svg/media-skip-backward.svg + icons/svg/media-skip-forward.svg + icons/svg/media-vcr-nopause.svg + icons/svg/media-vcr-normal.svg + icons/svg/media-vcr-withpause.svg + icons/svg/messages_disabled.svg + icons/svg/messages.svg + icons/svg/mini_map_disabled.svg + icons/svg/mini_map.svg + icons/svg/mlvs_control.svg + icons/svg/mobile_video_disabled.svg + icons/svg/mobile_video.svg + icons/svg/network-wireless.svg + icons/svg/new_documents.svg + icons/svg/new_mail_indicator.svg + icons/svg/nuclear_agents.svg + icons/svg/object-group.svg + icons/svg/object-ungroup.svg + icons/svg/oc_composition_disabled.svg + icons/svg/oc_composition.svg + icons/svg/overlays.svg + icons/svg/phase_def.svg + icons/svg/pi_force_collapse.svg + icons/svg/pi_force_expand.svg + icons/svg/pi_force_left.svg + icons/svg/pi_force_right.svg + icons/svg/pi_markup_3d.svg + icons/svg/pi_movementtrack.svg + icons/svg/pi_nbc.svg + icons/svg/pi_show_bite.svg + icons/svg/pi_tact_status_history.svg + icons/svg/pi_type_weaponrange.svg + icons/svg/planned_training_cycles.svg + icons/svg/playback_audio_disabled.svg + icons/svg/playback_audio.svg + icons/svg/playback_situation_disabled.svg + icons/svg/playback_situation.svg + icons/svg/playback_video_disabled.svg + icons/svg/playback_video.svg + icons/svg/player_equipment.svg + icons/svg/preferences-web-browser-cache.svg + icons/svg/presets_disabled.svg + icons/svg/presets.svg + icons/svg/primary_map_toolbar_disabled.svg + icons/svg/primary_map_toolbar.svg + icons/svg/proj_audio.svg + icons/svg/projection.svg + icons/svg/raster_disabled.svg + icons/svg/raster.svg + icons/svg/report_combat_effectiveness_disabled.svg + icons/svg/report_combat_effectiveness.svg + icons/svg/report_treatmentmaintanance_disabled.svg + icons/svg/report_treatmentmaintanance.svg + icons/svg/save_preferences_disabled.svg + icons/svg/save_preferences.svg + icons/svg/screenshot_disabled.svg + icons/svg/screenshot.svg + icons/svg/secondary_map_toolbar_disabled.svg + icons/svg/secondary_map_toolbar.svg + icons/svg/set_force_visibility_disabled.svg + icons/svg/set_force_visibility.svg + icons/svg/set_home_transparency_disabled.svg + icons/svg/set_home_transparency.svg + icons/svg/set_markers_audio_disabled.svg + icons/svg/set_markers_audio.svg + icons/svg/set_marker_situation_disabled.svg + icons/svg/set_marker_situation.svg + icons/svg/set_marker_video_disabled.svg + icons/svg/set_marker_video.svg + icons/svg/set_view_position_disabled.svg + icons/svg/set_view_position.svg + icons/svg/situation_disabled.svg + icons/svg/situation.svg + icons/svg/status_bar_disabled.svg + icons/svg/status_bar.svg + icons/svg/support_documents_disabled.svg + icons/svg/support_documents.svg + icons/svg/switch_to_primary_map_disabled.svg + icons/svg/switch_to_primary_map.svg + icons/svg/switch_to_sec_map_disabled.svg + icons/svg/switch_to_sec_map.svg + icons/svg/target.svg + icons/svg/view-statistics.svg + icons/svg/visible_teams.svg + icons/svg/voice_communication_access_disabled.svg + icons/svg/voice_communication_access.svg + icons/svg/voice_communication_disabled.svg + icons/svg/voice_communication.svg + icons/svg/weapon_firing_disabled.svg + icons/svg/weapon_firing.svg + icons/svg/wireless.svg + + icons/svg/voice_communication_access.svg + icons/svg/voice_communication_disabled.svg + + diff --git a/Z/src/nglwidgets/nglstandardbutton.cpp b/Z/src/nglwidgets/nglstandardbutton.cpp new file mode 100755 index 000000000..30e9f24f2 --- /dev/null +++ b/Z/src/nglwidgets/nglstandardbutton.cpp @@ -0,0 +1,336 @@ + + +#include "nglstandardbutton.h" +#include +#include +#include +#include + +NGLStandardButton::NGLStandardButton(QWidget *parent) + : NGLStandardButton(NoButton, parent) +{} + +NGLStandardButton::NGLStandardButton(StandardButton type, QWidget *parent) + : QPushButton(parent) + , m_type(type) + , m_layoutPriority(-1) +{ + init(); +} + +void NGLStandardButton::init() +{ + setType(m_type); +} + +NGLStandardButton::StandardButton NGLStandardButton::type() const +{ + return m_type; +} + +void NGLStandardButton::setType(StandardButton t) +{ + m_type = t; + qDeleteAll(m_actionList); + m_actionList.clear(); + const char *iconName = nullptr; + QString text; + QString actionText; + QKeySequence key; + const char *objectName = nullptr; + switch (t) + { + case Ok: + iconName = ":icons/png/ok.png"; + text = tr("&Ok"); + objectName = "btnOk"; + break; + case Send: + iconName = ":icons/svg/messages.svg"; + text = tr("&Send"); + key = QKeySequence(Qt::CTRL + Qt::Key_Return); + objectName = "btnSend"; + break; + case New: + iconName = ":icons/png/messages_new.png"; + text = tr("&New"); + key = QKeySequence::New; + objectName = "btnNew"; + break; + case Delete: + iconName = ":icons/png/deleteall.png"; + text = tr("&Delete"); + key = QKeySequence::Delete; + objectName = "btnDelete"; + break; + case Save: + iconName = ":icons/png/save.png"; + text = tr("Sa&ve"); + key = QKeySequence::Save; + objectName = "btnSave"; + break; + case Open: + iconName = ":icons/png/address_book.png"; + text = tr("&Open"); + key = QKeySequence::Open; + objectName = "btnOpen"; + break; + case Yes: + iconName = ":icons/png/ok.png"; + text = tr("&Yes"); + objectName = "btnYes"; + break; + case No: + iconName = ":icons/png/delete.png"; + text = tr("&No"); + objectName = "btnNo"; + break; + case Close: + iconName = ":icons/png/delete_exercise.png"; + text = tr("&Close"); + objectName = "btnClose"; + break; + case Cancel: + iconName = ":icons/png/delete_exercise.png"; + text = tr("&Cancel"); + objectName = "btnCancel"; + break; + case Help: + iconName = ":icons/svg/ueb_index.svg"; + text = QString(); + actionText = tr("Help"); + setMaximumWidth(sizeHint().height()); + key = QKeySequence::HelpContents; + objectName = "btnHelp"; + break; + case Apply: + iconName = ":icons/png/ok.png"; + text = tr("&Apply"); + objectName = "btnApply"; + break; + case Reset: + iconName = ":icons/png/undo_act.png"; + text = tr("Re&set"); + objectName = "btnReset"; + break; + case Print: + iconName = ":icons/png/printer.png"; + text = QString(); + actionText = tr("Print"); + setMaximumWidth(sizeHint().height()); + key = QKeySequence::Print; + objectName = "btnPrint"; + break; + case Add: + iconName = ":icons/png/add.png"; + text = tr("A&dd"); + objectName = "btnAdd"; + break; + case Remove: + iconName = ":icons/png/remove.png"; + text = tr("Re&move"); + objectName = "btnRemove"; + break; + case Edit: + iconName = ":icons/png/rename_exercise.png"; + text = tr("&Edit"); + objectName = "btnEdit"; + break; + case Modify: + iconName = ":icons/png/ok.png"; + text = tr("Modify"); + objectName = "btnModify"; + break; + case Hide: + iconName = ":icons/png/ok.png"; + text = tr("Hide"); + objectName = "btnHide"; + break; + case Download: + iconName = ":icons/png/download.png"; + text = tr("Download"); + objectName = "btnDownload"; + break; + case Library: + { + iconName = ":icons/png/address_book.png"; + text.clear(); + setMaximumWidth(minimumSizeHint().width() * 4 / 5); + QMenu *menu = new QMenu(this); + setMenu(menu); + + QAction *actionImport = menu->addAction(QIcon(QLatin1String(":icons/svg/import_docs.svg")), tr("Import from library")); + actionImport->setObjectName(QLatin1String("actionImport")); + connect(actionImport, &QAction::triggered, + this, QOverload::of(&QAbstractButton::clicked), Qt::QueuedConnection); + m_actionList += actionImport; + + QAction *actionExport = menu->addAction(QIcon(QLatin1String(":icons/svg/export_docs.svg")), tr("Export to library")); + actionExport->setObjectName(QLatin1String("actionExport")); + connect(actionExport, &QAction::triggered, + this, QOverload::of(&QAbstractButton::clicked), Qt::QueuedConnection); + m_actionList += actionExport; + + objectName = "btnLibrary"; + break; + } + case Show: + { + iconName = ":icons/png/preview.png"; + text = tr("Show"); + objectName = "btnShow"; + break; + } + case ZoomIn: + { + iconName = ":icons/png/zoom_in.png"; + text.clear(); + objectName = "btnZoomIn"; + break; + } + case ZoomOut: + { + iconName = ":icons/png/zoom_out.png"; + text.clear(); + objectName = "btnZoomOut"; + break; + } + default: + text = QLatin1String("ButtonText"); + break; + }; + if (!m_defaultText.isEmpty()) + text = tr(m_defaultText.constData()); + if (!m_defaultToolTip.isEmpty()) + { + QString toolTip = tr(m_defaultToolTip.constData()); + setToolTip(toolTip); + } + if (iconName) + setIcon(QIcon(QString::fromLatin1(iconName))); + setText(text); + if (!key.isEmpty()) + setShortcut(key); + if (objectName) + setObjectName(QString::fromUtf8(objectName)); + + if (m_actionList.isEmpty()) + { + QAction *action = new QAction(this); + action->setText(text.isEmpty() ? actionText : text); + action->setIcon(icon()); + action->setEnabled(isEnabled()); + action->setToolTip(toolTip()); + action->setWhatsThis(whatsThis()); + connect(action, &QAction::triggered, this, + QOverload::of(&QAbstractButton::clicked), Qt::QueuedConnection); + m_actionList += action; + } +} + +void NGLStandardButton::setLayoutPriority(qint32 priority) +{ + m_layoutPriority = priority; +} + +qint32 NGLStandardButton::layoutPriority() const +{ + + + if (m_layoutPriority >= 0) + return m_layoutPriority; + switch (m_type) + { + case Close: + return 10; + case Cancel: + return 11; + case Apply: + return 13; + case Ok: + return 15; + case No: + return 31; + case Yes: + return 32; + case ZoomIn: + return 36; + case ZoomOut: + return 37; + case Show: + return 38; + case Download: + return 44; + case Save: + return 45; + case Open: + return 47; + case Reset: + return 50; + case Send: + return 50; + case Modify: + return 51; + case Hide: + return 52; + case Delete: + return 55; + case Remove: + return 56; + case New: + return 60; + case Add: + return 61; + case Edit: + return 63; + case Library: + return 105; + case Print: + return 110; + case Help: + return 120; + default: + break; + }; + return 50; +} + +void NGLStandardButton::changeEvent(QEvent *e) +{ + switch (e->type()) + { + case QEvent::LanguageChange: + setType(m_type); + break; + case QEvent::EnabledChange: + { + QAction *a = findChild(); + if (a) + a->setEnabled(isEnabled()); + break; + } + default: + break; + } + QPushButton::changeEvent(e); +} + +QList NGLStandardButton::actions() const +{ + return m_actionList; +} + +void NGLStandardButton::setDefaultText(const char *text) +{ + m_defaultText = QByteArray(text); + if (!m_defaultText.isEmpty()) + setText(tr(m_defaultText.constData())); +} + +void NGLStandardButton::setDefaultToolTip(const char *toolTip) +{ + m_defaultToolTip = QByteArray(toolTip); + if (!m_defaultToolTip.isEmpty()) + setToolTip(tr(m_defaultToolTip.constData())); +} + diff --git a/Z/src/nglwidgets/nglstandardbutton.h b/Z/src/nglwidgets/nglstandardbutton.h new file mode 100755 index 000000000..d621ca2e7 --- /dev/null +++ b/Z/src/nglwidgets/nglstandardbutton.h @@ -0,0 +1,105 @@ + + +#pragma once + +#include + +#include "nglwidgets_export.h" + + + + +class NGLWIDGETS_EXPORT NGLStandardButton : public QPushButton +{ + Q_OBJECT + Q_PROPERTY(StandardButton standardButton READ type WRITE setType) + Q_PROPERTY(qint32 layoutPriority READ layoutPriority WRITE setLayoutPriority) + +public: + + + enum StandardButton + { + NoButton = 0x00000000, + Ok = 0x00000001, + Save = 0x00000002, + Open = 0x00000004, + Yes = 0x00000008, + No = 0x00000010, + Close = 0x00000020, + Cancel = 0x00000040, + Help = 0x00000080, + Apply = 0x00000100, + Reset = 0x00000200, + Print = 0x00000400, + Add = 0x00000800, + Remove = 0x00002000, + Edit = 0x00008000, + Send = 0x00010000, + New = 0x00020000, + Delete = 0x00040000, + Download = 0x00080000, + Library = 0x00100000, + Show = 0x00200000, + ZoomIn = 0x00400000, + ZoomOut = 0x00800000, + Modify = 0x01000000, + Hide = 0x02000000, + +#ifndef Q_MOC_RUN + FirstButton = Ok, + LastButton = Hide +#endif + }; + Q_ENUM(StandardButton) + Q_DECLARE_FLAGS(StandardButtons, StandardButton) + Q_FLAG(StandardButtons) + + + + explicit NGLStandardButton(QWidget *parent = nullptr); + + + explicit NGLStandardButton(StandardButton type, QWidget *parent = nullptr); + + + + StandardButton type() const; + + + void setType(StandardButton t); + + + + void setLayoutPriority(qint32 priority); + + + + virtual qint32 layoutPriority() const; + + + + QList actions() const; + + + + void setDefaultText(const char *text); + + + + void setDefaultToolTip(const char *toolTip); + +protected: + StandardButton m_type; + qint32 m_layoutPriority; + QByteArray m_defaultText; + QByteArray m_defaultToolTip; + QList m_actionList; + + virtual void changeEvent(QEvent *e); +private: + void init(); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(NGLStandardButton::StandardButtons) + + diff --git a/Z/src/nglwidgets/ngltreeitem.cpp b/Z/src/nglwidgets/ngltreeitem.cpp new file mode 100755 index 000000000..4d7d52be0 --- /dev/null +++ b/Z/src/nglwidgets/ngltreeitem.cpp @@ -0,0 +1,131 @@ + + + +#include "ngltreeitem.h" + + +NGLTreeItem::~NGLTreeItem() +{ + qDeleteAll(m_childItems); +} + + + +NGLTreeItem::NGLTreeItem(const NGLTreeItem &orig) +{ + set(orig); +} + + + +NGLTreeItem &NGLTreeItem::operator=(const NGLTreeItem &orig) +{ + set(orig); + return *this; +} + + + +void NGLTreeItem::set(const NGLTreeItem &orig) +{ + m_parentItem = orig.m_parentItem; + m_modified = orig.m_modified; + m_data = orig.m_data; + m_icon = orig.m_icon; + const auto origChildren = orig.children(); + for (NGLTreeItem *origChild : origChildren) + appendChild(new NGLTreeItem(*origChild)); +} + + +bool NGLTreeItem::insertChild(int row, NGLTreeItem *item) +{ + if ((row >= 0) && (row <= childCount())) + { + item->m_parentItem = this; + m_childItems.insert(row, item); + return true; + } + return false; +} + + +void NGLTreeItem::appendChild(NGLTreeItem *item) +{ + item->m_parentItem = this; + m_childItems.push_back(item); +} + + + +NGLTreeItem *NGLTreeItem::takeChild(int row) +{ + return validRow(row) ? m_childItems.takeAt(row) : nullptr; +} + + +bool NGLTreeItem::removeChild(int row) +{ + if (!validRow(row)) + return false; + + delete m_childItems.takeAt(row); + return true; +} + + +bool NGLTreeItem::removeChild(const NGLTreeItem *child) +{ + for (int row = 0; row < m_childItems.size(); ++row) + { + if (m_childItems.at(row) == child) + { + removeChild(row); + return true; + } + } + return false; +} + + +bool NGLTreeItem::removeChildren(int row, int count) +{ + int lastRow = row + count - 1; + if (validRow(row) && + (lastRow >= 0) && (lastRow < childCount())) + { + while (lastRow >= row) + { + delete m_childItems.takeAt(row); + --lastRow; + } + return true; + } + return false; +} + + +bool NGLTreeItem::removeAllChildren() +{ + qDeleteAll(m_childItems); + m_childItems.clear(); + return true; +} + + +int NGLTreeItem::row() const +{ + if (m_parentItem) + return m_parentItem->m_childItems.indexOf(const_cast(this)); + return 0; +} + + +void NGLTreeItem::setData(const QVariant &data) +{ + if (m_data != data) + { + m_data = data; + setModified(true); + } +} diff --git a/Z/src/nglwidgets/ngltreeitem.h b/Z/src/nglwidgets/ngltreeitem.h new file mode 100755 index 000000000..51da5e2ab --- /dev/null +++ b/Z/src/nglwidgets/ngltreeitem.h @@ -0,0 +1,72 @@ + + + +#pragma once + +#include +#include +#include + +#include "nglwidgets_export.h" + + + + + +class NGLWIDGETS_EXPORT NGLTreeItem +{ +public: + + + NGLTreeItem(const QVariant &data, const QIcon &icon = QIcon()) + : m_data(data) + , m_icon(icon) + {} + + + + virtual ~NGLTreeItem(); + + + + NGLTreeItem(const NGLTreeItem &orig); + + + + NGLTreeItem &operator=(const NGLTreeItem &orig); + + + + bool insertChild(int row, NGLTreeItem *item); + void appendChild(NGLTreeItem *item); + NGLTreeItem *takeChild(int row); + bool removeChild(const NGLTreeItem *child); + bool removeChild(int row); + bool removeChildren(int row, int count); + bool removeAllChildren(); + + NGLTreeItem *child(int row) const { return validRow(row) ? m_childItems.value(row) : nullptr; } + QVector children() const { return m_childItems; } + const QVector constChildren() const { return m_childItems; } + int childCount() const { return m_childItems.size(); } + int row() const; + NGLTreeItem *parent() const { return m_parentItem; } + + void setModified(bool modified) { m_modified = modified; } + bool modified() const { return m_modified; } + virtual void setData(const QVariant &data); + virtual QVariant data() const { return m_data; } + virtual void setIcon(const QIcon &icon) { m_icon = icon; } + virtual QIcon icon() const { return m_icon; } + +private: + void set(const NGLTreeItem &orig); + bool validRow(int row) const { return ((row >= 0) && (row < childCount())); } + +private: + QVector m_childItems; + QVariant m_data; + QIcon m_icon; + NGLTreeItem *m_parentItem = nullptr; + bool m_modified = false; +}; diff --git a/Z/src/nglwidgets/ngltreemodel.cpp b/Z/src/nglwidgets/ngltreemodel.cpp new file mode 100755 index 000000000..13d88b1ea --- /dev/null +++ b/Z/src/nglwidgets/ngltreemodel.cpp @@ -0,0 +1,458 @@ + + + +#include "ngltreemodel.h" +#include "ngltreeitem.h" + +#include +#include +#include +#include +#include + + +NGLTreeModel::NGLTreeModel(QObject *parent, NGLTreeItem *rootItem, + const QStringList &titles) + : QAbstractItemModel(parent) + , m_rootItem(rootItem) + , m_titles(titles) + , m_mimeType(QStringLiteral("NGLTreeModel/dragDrop")) + , m_bMimeDataWithicon(true) +{ + connect(this, &NGLTreeModel::dataChanged, + this, &NGLTreeModel::modelDataChanged); + connect(this, &NGLTreeModel::rowsInserted, + this, &NGLTreeModel::modelDataChanged); + connect(this, &NGLTreeModel::rowsMoved, + this, &NGLTreeModel::modelDataChanged); + connect(this, &NGLTreeModel::rowsRemoved, + this, &NGLTreeModel::modelDataChanged); +} + + +NGLTreeModel::~NGLTreeModel() +{ + resetModel(); + delete m_rootItem; +} + + +void NGLTreeModel::setRootItem(NGLTreeItem *rootItem) +{ + resetModel(); + delete m_rootItem; + m_rootItem = nullptr; + beginResetModel(); + endResetModel(); + m_rootItem = rootItem; +} + + +NGLTreeItem *NGLTreeModel::getRootItem() const +{ + return m_rootItem; +} + + +NGLTreeItem *NGLTreeModel::createItem(const QVariant &data, const QIcon &icon) const +{ + return new NGLTreeItem(data, icon); +} + + +void NGLTreeModel::resetModel() +{ + if (m_rootItem) + { + beginResetModel(); + m_rootItem->removeAllChildren(); + endResetModel(); + } +} + + +Qt::ItemFlags NGLTreeModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); + if (index.isValid()) + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; + return defaultFlags; +} + + +QVariant NGLTreeModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + { + if ((section >= 0) && (section < m_titles.size())) + return m_titles.at(section); + } + return QVariant(); +} + + +QModelIndex NGLTreeModel::index(int row, int column, + const QModelIndex &parent) const + +{ + if (!hasIndex(row, column, parent)) + { + return QModelIndex(); + } + NGLTreeItem *parentItem = privateData(parent); + NGLTreeItem *childItem = parentItem->child(row); + if (childItem) + { + return createIndex(row, column, childItem); + } + return QModelIndex(); +} + + +QModelIndex NGLTreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + NGLTreeItem *childItem = privateData(index); + NGLTreeItem *parentItem = childItem->parent(); + if (!parentItem || parentItem == m_rootItem) + return QModelIndex(); + return createIndex(parentItem->row(), 0, parentItem); +} + + +int NGLTreeModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return m_titles.size(); +} + + +int NGLTreeModel::rowCount(const QModelIndex &parent) const +{ + if (parent.column() > 0) + return 0; + NGLTreeItem *ti = privateData(parent); + if (!ti) + return 0; + return ti->childCount(); +} + + +bool NGLTreeModel::setData(const QModelIndex &index, const QVariant &value, + int role) +{ + Q_UNUSED(index) + Q_UNUSED(value) + Q_UNUSED(role) + return false; +} + + +void NGLTreeModel::setMimeType(const QString &mimeType) +{ + m_mimeType = mimeType; +} + + +void NGLTreeModel::resetModifedFlag(NGLTreeItem *rootItem) +{ + if (!rootItem) + return; + rootItem->setModified(false); + for (int i = 0; i < rootItem->childCount(); ++i) + resetModifedFlag(rootItem->child(i)); +} + + + +bool NGLTreeModel::setItemData(const QModelIndex &index, const QVariant &value, + const QIcon &icon) +{ + if (!index.isValid()) + return false; + + NGLTreeItem *item = privateData(index); + item->setData(value); + item->setIcon(icon); + item->setModified(true); + emit dataChanged(index, index); + return true; +} + + +QVariant NGLTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if (role == Qt::DecorationRole) + { + if (index.column() == 0) + { + NGLTreeItem *item = privateData(index); + if (item) + return item->icon(); + } + } + return QVariant(); +} + + +QMimeData *NGLTreeModel::mimeData(const QModelIndexList &indexes) const +{ + return getMimeData(indexes, m_mimeType); +} + + +QMimeData *NGLTreeModel::getMimeData(const QModelIndexList &indexes, + const QString &mimeType) const +{ + QMimeData *mimeData = new QMimeData(); + QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + + stream << m_bMimeDataWithicon; + + bool dataStreamed = false; + for (const QModelIndex &index : indexes) + { + if (index.isValid() && (index.column() == 0)) + { + streamAddChilds(stream, privateData(index)); + dataStreamed = true; + } + } + if (dataStreamed) + mimeData->setData(mimeType, encodedData); + return mimeData; +} + + +void NGLTreeModel::streamAddChilds(QDataStream &stream, const NGLTreeItem *item) const +{ + stream << qint64(item->parent()) << qint64(item) << getItemData(item); + if (m_bMimeDataWithicon) + stream << item->icon(); + + for (int i = 0; i < item->childCount(); i++) + streamAddChilds(stream, item->child(i)); +} + + +bool NGLTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + qDebug() << "dropMimeData: action = " << action + << ", row = " << row + << ", column = " << column + << ", parent: valid = " << parent.isValid(); + + if ((action != Qt::MoveAction) && (action != Qt::CopyAction)) + return false; + if (!data->hasFormat(m_mimeType)) + return false; + + int beginRow; + QModelIndex parentR; + if (row != -1) + { + + parentR = parent; + beginRow = row; + } + else if (parent.isValid()) + { + + + parentR = parent; + + beginRow = rowCount(parentR); + + + } + else + { + + parentR = QModelIndex(); + beginRow = rowCount(parentR); + } + return insertMimeData(data, m_mimeType, parentR, beginRow); +} + + +bool NGLTreeModel::insertMimeData(const QMimeData *data, const QString &mimeType, + QModelIndex parentR, int beginRow) +{ + bool bStreamContainsIcons; + + QByteArray encodedData = data->data(mimeType); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + + qint64 idParent, idItem; + QHash rowCache; + QVariant itemData; + QIcon icon; + + stream >> bStreamContainsIcons; + + bool first = true; + qint64 prevIdParent = 0; + while (!stream.atEnd()) + { + stream >> idParent >> idItem >> itemData; + if (bStreamContainsIcons) + stream >> icon; + + NGLTreeItem *item = createItem(itemData, icon); + + if (first) + { + first = false; + rowCache.insert(idParent, parentR); + } + else if (idParent == prevIdParent) + { + parentR = rowCache[idParent]; + beginRow++; + } + else + { + parentR = rowCache[idParent]; + beginRow = privateData(rowCache[idParent])->childCount(); + } + prevIdParent = idParent; + + if (!insertRow(beginRow, parentR, item)) + { + delete item; + return false; + } + rowCache.insert(idItem, index(beginRow, 0, parentR)); + emit signalDataDropped(beginRow, parentR); + } + return true; +} + + +QVector NGLTreeModel::getMimeDataItems(const QMimeData *data, + const QString &mimeType) const +{ + QVector ret; + QByteArray encodedData = data->data(mimeType); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + + qint64 idParent, idItem; + QVariant itemData; + QIcon icon; + bool bStreamContainsIcons; + + stream >> bStreamContainsIcons; + while (!stream.atEnd()) + { + stream >> idParent >> idItem >> itemData; + if (bStreamContainsIcons) + stream >> icon; + ret += createItem(itemData, icon); + } + return ret; +} + + +NGLTreeItem *NGLTreeModel::privateData(const QModelIndex &index) const +{ + if (!index.isValid()) + return m_rootItem; + Q_ASSERT(index.model() == this); + return static_cast(index.internalPointer()); +} + + +bool NGLTreeModel::moveRow(const QModelIndex &sourceParent, int sourceRow, + const QModelIndex &destParent, int destRow) +{ + Q_ASSERT(sourceParent.column() == 0 || !sourceParent.isValid()); + Q_ASSERT(destParent.column() == 0 || !destParent.isValid()); + + NGLTreeItem *sourceParentItem = privateData(sourceParent); + NGLTreeItem *destParentItem = privateData(destParent); + if ((sourceRow >= 0) && (sourceRow < sourceParentItem->childCount()) && + (destRow >= 0) && (destRow < destParentItem->childCount())) + { + beginRemoveRows(sourceParent, sourceRow, sourceRow); + NGLTreeItem *item = sourceParentItem->takeChild(sourceRow); + endRemoveRows(); + if (item) + { + beginInsertRows(destParent, destRow, destRow); + bool ret = destParentItem->insertChild(destRow, item); + endInsertRows(); + return ret; + } + } + return false; +} + + +bool NGLTreeModel::removeRows(int row, int count, const QModelIndex &parent) +{ + qDebug() << "removeRows: row = " << row << ", " + << "count = " << count; + NGLTreeItem *parentItem = privateData(parent); + if ((row < 0 && row >= parentItem->childCount()) || count <= 0) + return false; + Q_ASSERT(parent.column() == 0 || !parent.isValid()); + if (parent.column() != 0 && parent.isValid()) + return false; + beginRemoveRows(parent, row, row + count - 1); + bool ret = parentItem->removeChildren(row, count); + if (ret) + { + for (int r = row; r < parentItem->childCount(); ++r) + parentItem->child(r)->setModified(true); + } + endRemoveRows(); + return ret; +} + + +bool NGLTreeModel::insertRow(int row, const QModelIndex &parent, NGLTreeItem *item) +{ + NGLTreeItem *parentItem = privateData(parent); + if (!parentItem) + return false; + + Q_ASSERT(parent.column() == 0 || !parent.isValid()); + if (parent.column() != 0 && parent.isValid()) + return false; + + + + + + parentItem->setModified(true); + beginInsertRows(parent, row, row); + bool ret = parentItem->insertChild(row, item); + for (int r = row; r < parentItem->childCount(); ++r) + parentItem->child(r)->setModified(true); + endInsertRows(); + return ret; +} + + +QModelIndex NGLTreeModel::indexFromItem(const NGLTreeItem *item, int column) const +{ + if (item == m_rootItem || item == nullptr) + return QModelIndex(); + const NGLTreeItem *parent = item->parent(); + const QModelIndex parentIdx = indexFromItem(parent); + return index(item->row(), column, parentIdx); +} + + +QVariant NGLTreeModel::getItemData(const NGLTreeItem *item) const +{ + return item->data(); +} diff --git a/Z/src/nglwidgets/ngltreemodel.h b/Z/src/nglwidgets/ngltreemodel.h new file mode 100755 index 000000000..409c7a50c --- /dev/null +++ b/Z/src/nglwidgets/ngltreemodel.h @@ -0,0 +1,98 @@ + + + +#pragma once + +#include +#include +#include "nglwidgets_export.h" + +class NGLTreeItem; + + + + + +class NGLWIDGETS_EXPORT NGLTreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + NGLTreeModel(QObject *parent, NGLTreeItem *rootItem, + const QStringList &titles); + virtual ~NGLTreeModel(); + void resetModel(); + + Qt::ItemFlags flags(const QModelIndex &index) const override; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::EditRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::EditRole) override; + QStringList mimeTypes() const override { return { m_mimeType }; } + + Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } + QMimeData *mimeData(const QModelIndexList &indexes) const override; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) override; + + bool removeRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + + + NGLTreeItem *privateData(const QModelIndex &index) const; + void setMimeType(const QString &mimeType); + + + bool setItemData(const QModelIndex &index, const QMap &roles) override + { + return QAbstractItemModel::setItemData(index, roles); + } + +protected: + + void setMimeDataWithIcon(bool bWithIcon) { m_bMimeDataWithicon = bWithIcon; } + + + void resetModifedFlag(NGLTreeItem *rootItem); + + bool setItemData(const QModelIndex &index, const QVariant &value, + const QIcon &icon); + QMimeData *getMimeData(const QModelIndexList &indexes, + const QString &mimeType) const; + bool insertMimeData(const QMimeData *data, const QString &mimeType, + QModelIndex parentR, int beginRow); + + QVector getMimeDataItems(const QMimeData *data, + const QString &mimeType) const; + + bool moveRow(const QModelIndex &sourceParent, int sourceRow, + const QModelIndex &destParent, int destRow); + bool insertRow(int row, const QModelIndex &parent, NGLTreeItem *item); + + void setRootItem(NGLTreeItem *rootItem); + NGLTreeItem *getRootItem() const; + + virtual NGLTreeItem *createItem(const QVariant &data, const QIcon &icon) const; + + void streamAddChilds(QDataStream &stream, const NGLTreeItem *item) const; + + QModelIndex indexFromItem(const NGLTreeItem *item, int column = 0) const; + + virtual QVariant getItemData(const NGLTreeItem *item) const; +Q_SIGNALS: + void signalDataDropped(int row, const QModelIndex &parent); + void modelDataChanged(); + +protected: + NGLTreeItem *m_rootItem; + QStringList m_titles; + QString m_mimeType; + bool m_bMimeDataWithicon; +}; diff --git a/Z/src/nglwidgets/nglwidgets_export.h b/Z/src/nglwidgets/nglwidgets_export.h new file mode 100755 index 000000000..ef4b4d8fb --- /dev/null +++ b/Z/src/nglwidgets/nglwidgets_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLWIDGETS_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLWIDGETS_EXPORT +# else +# if defined(MAKE_NGLWIDGETS_LIB) +# define NGLWIDGETS_EXPORT Q_DECL_EXPORT +# else +# define NGLWIDGETS_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/qsql_informix/CMakeLists.txt b/Z/src/qsql_informix/CMakeLists.txt new file mode 100755 index 000000000..eae1e3087 --- /dev/null +++ b/Z/src/qsql_informix/CMakeLists.txt @@ -0,0 +1,49 @@ +# CMake script for informix sql driver +CMAKE_MINIMUM_REQUIRED(VERSION 3.5) + +SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED 11) +SET(CMAKE_CXX_VISIBILITY_PRESET hidden) +SET(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_VISIBILITY_INLINES_HIDDEN ON) +SET(CMAKE_POSITION_INDEPENDENT_CODE ON) +SET(CMAKE_AUTOMOC TRUE) +SET(QT_USE_IMPORTED_TARGETS TRUE) +FIND_PACKAGE(Qt5 5.9.0 COMPONENTS Core Sql Test REQUIRED) + +FIND_PACKAGE(IClientSDK REQUIRED) + +ADD_DEFINITIONS(-DQT_NO_CAST_FROM_ASCII) +ADD_DEFINITIONS(-DIT_DO_NOT_SIMULATE_BOOL) +INCLUDE_DIRECTORIES(${ICLIENT_SDK_INCLUDE_DIR}) +SET(ifx_SRCS + qsql_informix.cpp + qsql_informix.h + qsql_informix_plugin.cpp + qsql_informix_utils.cpp + qsql_informix_utils.h +) + +ADD_LIBRARY(qsql_informix SHARED ${ifx_SRCS}) +TARGET_LINK_LIBRARIES(qsql_informix + Qt5::Core + Qt5::Sql + ${ICLIENT_SDK_LIBRARIES} + ${ICLIENT_SDK_LIBRARIES_CPP} + ${ICLIENT_SDK_ESQL_OBJECT_FILE} +) +TARGET_COMPILE_DEFINITIONS(qsql_informix PRIVATE MAKE_QSQL_INFORMIX_LIB) +INSTALL(TARGETS qsql_informix DESTINATION lib/sqldrivers) + +SET(test_SRCS + qsql_informix_test.cpp +) +ADD_EXECUTABLE(qsql_informix_test ${test_SRCS}) +TARGET_LINK_LIBRARIES(qsql_informix_test + qsql_informix + Qt5::Test + dl +) +ADD_TEST(NAME qsql_informix_test COMMAND $) diff --git a/Z/src/qsql_informix/FindCrypt.cmake b/Z/src/qsql_informix/FindCrypt.cmake new file mode 100755 index 000000000..6cf85a570 --- /dev/null +++ b/Z/src/qsql_informix/FindCrypt.cmake @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) + SET(CRYPT_FOUND TRUE) +ELSE(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) + FIND_PATH(CRYPT_INCLUDE_DIR crypt.h) + FIND_LIBRARY(CRYPT_LIBRARY crypt) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Crypt DEFAULT_MSG CRYPT_LIBRARY CRYPT_INCLUDE_DIR) + + MARK_AS_ADVANCED(CRYPT_INCLUDE_DIR CRYPT_LIBRARY) +ENDIF(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) diff --git a/Z/src/qsql_informix/FindIClientSDK.cmake b/Z/src/qsql_informix/FindIClientSDK.cmake new file mode 100755 index 000000000..8b3567ec2 --- /dev/null +++ b/Z/src/qsql_informix/FindIClientSDK.cmake @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(NOT WIN32) + IF(IClientSDK_FIND_REQUIRED) + FIND_PACKAGE(Crypt REQUIRED) + ELSE() + FIND_PACKAGE(Crypt) + ENDIF() +ENDIF() + +INCLUDE(FindPackageHandleStandardArgs) + +IF(NOT ICLIENT_SDK_DIR) + FIND_PROGRAM(ICLIENT_ESQL_EXECUTABLE bin/esql PATHS "$ENV{INFORMIXDIR}" "$ENV{INFORMIXDIR}/csdk") + IF(IClientSDK_FIND_REQUIRED) + IF(NOT ICLIENT_ESQL_EXECUTABLE) + MESSAGE(FATAL_ERROR "Could not find Informix Client SDK - $INFORMIXDIR not set?") + ENDIF() + ENDIF() + IF(ICLIENT_ESQL_EXECUTABLE) + GET_FILENAME_COMPONENT(ICLIENT_SDK_DIR_tmp ${ICLIENT_ESQL_EXECUTABLE} PATH) + GET_FILENAME_COMPONENT(ICLIENT_SDK_DIR ${ICLIENT_SDK_DIR_tmp} PATH CACHE) + ENDIF() + MESSAGE(STATUS "Using Informix Client SDK directory ${ICLIENT_SDK_DIR}") +ENDIF() + +FIND_PATH(ICLIENT_SDK_INCLUDE_DIR_INTERNAL NAMES c++/it.h cpp/it.h HINTS ${ICLIENT_SDK_DIR}/incl) + +IF(ICLIENT_SDK_INCLUDE_DIR_INTERNAL) + SET(ICLIENT_SDK_INCLUDE_DIR + ${CRYPT_INCLUDE_DIR} + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL} + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/c++ + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/cpp + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/cli + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/dmi + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/esql + CACHE INTERNAL "All IClient SDK include dirs needed" + ) + SET(ICLIENT_SDK_LIBRARY_DIRS + ${ICLIENT_SDK_DIR}/lib/ + ${ICLIENT_SDK_DIR}/lib/c++ + ${ICLIENT_SDK_DIR}/lib/cpp + ${ICLIENT_SDK_DIR}/lib/cli + ${ICLIENT_SDK_DIR}/lib/client + ${ICLIENT_SDK_DIR}/lib/dmi + ${ICLIENT_SDK_DIR}/lib/esql + CACHE INTERNAL "All IClient SDK library dirs" + ) +ENDIF() + +MACRO(ICLIENT_FIND_LIBRARY lib varname) + SET(LIBNAME ICLIENT_SDK_${lib}_LIBRARY) + FIND_LIBRARY(${LIBNAME} ${lib} ${f} + PATHS ${ICLIENT_SDK_DIR}/lib/ + ${ICLIENT_SDK_DIR}/lib/c++ + ${ICLIENT_SDK_DIR}/lib/cpp + ${ICLIENT_SDK_DIR}/lib/cli + ${ICLIENT_SDK_DIR}/lib/client + ${ICLIENT_SDK_DIR}/lib/dmi + ${ICLIENT_SDK_DIR}/lib/esql + ) + LIST(APPEND ${varname} ${${LIBNAME}}) + MARK_AS_ADVANCED(${LIBNAME}) + IF(IClientSDK_FIND_REQUIRED) + SET(ICLIENT_SDK_${LIBNAME}_FIND_REQUIRED TRUE) + SET(ICLIENT_SDK_${LIBNAME}_FIND_QUIETLY TRUE) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(ICLIENT_SDK_${LIBNAME} DEFAULT_MSG ${LIBNAME}) + ENDIF() +ENDMACRO() + +IF(WIN32) + ICLIENT_FIND_LIBRARY( libthdmi ICLIENT_SDK_LIBRARIES ) + ICLIENT_FIND_LIBRARY( libthc++ ICLIENT_SDK_LIBRARIES ) + ICLIENT_FIND_LIBRARY( isqlt09a ICLIENT_SDK_LIBRARIES ) + ICLIENT_FIND_LIBRARY( isqlt09s ICLIENT_SDK_LIBRARIES ) +ELSE() + ICLIENT_FIND_LIBRARY("ifc++" ICLIENT_SDK_LIBRARIES_CPP) + SET(iclient_libs + asf + gen + gls + os + sql + ) + SET(iclient_libs_if_only + dmi + glx + ) + SET(iclient_prefix + if + ix + ) + SET(ICLIENT_SDK_LIBRARIES CACHE INTERNAL "All IClient SDK libraries needed") + IF(CRYPT_FOUND) + SET(ICLIENT_SDK_LIBRARIES ${CRYPT_LIBRARY}) + ENDIF() + + MARK_AS_ADVANCED(ICLIENT_SDK_LIBRARIES) + FOREACH(pre ${iclient_prefix}) + FOREACH(f ${iclient_libs}) + ICLIENT_FIND_LIBRARY( "${pre}${f}" ICLIENT_SDK_LIBRARIES) + ENDFOREACH() + ENDFOREACH() + FOREACH(f ${iclient_libs_if_only}) + ICLIENT_FIND_LIBRARY( "if${f}" ICLIENT_SDK_LIBRARIES) + ENDFOREACH() + LIST(APPEND ICLIENT_SDK_LIBRARIES "dl") + + FIND_PATH(ICLIENT_SDK_ESQL_OBJECT_FILE_PATH checkapi.o PATHS ${ICLIENT_SDK_DIR}/lib/esql) + SET(ICLIENT_SDK_ESQL_OBJECT_FILE ${ICLIENT_SDK_ESQL_OBJECT_FILE_PATH}/checkapi.o CACHE INTERNAL "") +ENDIF() + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(IClientSDK DEFAULT_MSG ICLIENT_SDK_LIBRARIES ICLIENT_SDK_INCLUDE_DIR_INTERNAL) + +IF(ICLIENTSDK_FOUND) + SET(ICLIENT_SDK_DIR ${ICLIENT_SDK_DIR} CACHE INTERNAL "Informix Client SDK directory") +ENDIF() + + +MACRO(MacroInstallIClientSDK) + IF(NOT ICLIENT_SDK_DIR) + MESSAGE(FATAL_ERROR "ICLIENT_SDK_DIR nicht gesetzt - Installation von IClient SDK nicht moeglich!") + ENDIF() + + SET(iclient_bin_dir "${ICLIENT_SDK_DIR}/bin/") + SET(iclient_lib_dir "${ICLIENT_SDK_DIR}/lib/") + SET(INSTALL_BIN ON) + SET(INSTALL_LIB ON) + + SET(doing_prefix OFF) + SET(iclient_prefix "") + FOREACH(args ${ARGN}) + IF(doing_prefix) + SET(doing_prefix OFF) + SET(iclient_prefix "${args}/") + ENDIF() + IF("${args}" STREQUAL "no-bin") + SET(INSTALL_BIN OFF) + ENDIF() + IF("${args}" STREQUAL "no-lib") + SET(INSTALL_LIB OFF) + ENDIF() + IF("${args}" STREQUAL "prefix") + SET(doing_prefix ON) + ENDIF("${args}" STREQUAL "prefix") + ENDFOREACH() + + IF(INSTALL_BIN) + INSTALL(DIRECTORY ${iclient_bin_dir} DESTINATION ${iclient_prefix}bin PATTERN .svn EXCLUDE) + ENDIF() + IF(INSTALL_LIB) + INSTALL(DIRECTORY ${iclient_lib_dir} DESTINATION ${iclient_prefix}lib PATTERN .svn EXCLUDE) + ENDIF() +ENDMACRO() + +MACRO(ICLIENT_ESQL_PREPROCESS outlist) + FIND_PROGRAM(ESQLC_EXECUTABLE esqlc PATHS ${ICLIENT_SDK_DIR}/lib ${ICLIENT_SDK_DIR}/lib/esql/) + IF(ESQLC_EXECUTABLE) + FOREACH(infile ${ARGN}) + GET_FILENAME_COMPONENT(ext ${infile} EXT) + GET_FILENAME_COMPONENT(output ${infile} NAME_WE) + GET_FILENAME_COMPONENT(input ${infile} ABSOLUTE) + SET(extension "c") + IF("${ext}" STREQUAL ".ecpp") + SET(extension "C") + ENDIF("${ext}" STREQUAL ".ecpp") + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${output}.${extension} + COMMAND ${ESQLC_EXECUTABLE} + ARGS -local ${input} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${input} + ) + LIST(APPEND ${outlist} ${CMAKE_CURRENT_BINARY_DIR}/${output}.${extension}) + ENDFOREACH(infile) + ELSE() + MESSAGE(FATAL_ERROR "Could not find esql executable!") + ENDIF() +ENDMACRO() diff --git a/Z/src/qsql_informix/qsql_informix.cpp b/Z/src/qsql_informix/qsql_informix.cpp new file mode 100755 index 000000000..c4ccfc3ab --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix.cpp @@ -0,0 +1,1333 @@ + + + +#include "qsql_informix.h" + + +#include +#include +#include +#include + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + +#define DEBUG_FUNCTION + +#ifdef Q_CC_MSVC +float truncf(float in) +{ + return in < 0 ? in + 0.5 : in - 0.5; +} +#endif + +Q_DECLARE_METATYPE(ITConnection *) +Q_DECLARE_METATYPE(ITSet *) + + + + +class QInformixDriverPrivate +{ +public: + QInformixDriverPrivate(QInformixDriver *parent) + : connection(0) + , driver(parent) + , dbLocale(0) + , openCount(0) + , connTimeout(-1) + , connectOnFirstUse(false) + { + connectionTimeoutTimer.setSingleShot(true); + QObject::connect(&connectionTimeoutTimer, SIGNAL(timeout()), + driver, SLOT(timeout())); + } + + ITConnection *connection; + QInformixDriver *driver; + QTextCodec *dbLocale; + ITDBInfo conn_params; + QMutex connCountMutex; + QAtomicInt openCount; + int connTimeout; + bool connectOnFirstUse; + QTimer connectionTimeoutTimer; + + inline ITString toInformixEncoding(const QString &str) const + { + return ITString(dbLocale->fromUnicode(str).constData(), true); + } + + inline QByteArray toInformixEncodingBA(const QString &str) const + { + return dbLocale->fromUnicode(str).constData(); + } + + inline QString fromInformixEncoding(const ITString &str) const + { + return dbLocale->toUnicode(str.Data()).trimmed(); + } + + inline QString fromInformixEncoding(const QByteArray &str) const + { + return dbLocale->toUnicode(str); + } + + void addConnection() + { + QMutexLocker l(&connCountMutex); + checkOpen(); + openCount.ref(); +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s opencount: %d\n", this, __PRETTY_FUNCTION__, (int)openCount); +#endif + } + + void removeConnection() + { + QMutexLocker l(&connCountMutex); + if (openCount.deref() == false && connTimeout >= 0) + { +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p singleShot timeout: %d, driver: %p\n", this, connTimeout, driver); +#endif + connectionTimeoutTimer.start(connTimeout); + } +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s opencount: %d\n", this, __PRETTY_FUNCTION__, (int)openCount); +#endif + } + + void closeConnection(); + + void checkOpen() + { + if (!connection) + { + if (connectOnFirstUse) + { + connectOnFirstUse = false; + if (!driver->openDatabaseInternal()) + return; + } + else + return; + } + if (!connection->IsOpen()) + connection->Open(conn_params); + } +}; + +void QInformixDriverPrivate::closeConnection() +{ + QMutexLocker l(&connCountMutex); +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s\n", this, __PRETTY_FUNCTION__); +#endif + if (!driver->isOpen()) + return; +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p opencount: %d\n", this, (int)openCount); +#endif + if (openCount > 0) + return; + connection->Close(); +} + +static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, + const QInformixDriverPrivate *p) +{ + const char *e = p->connection->ErrorText(); + QString msg = QStringLiteral("IFX Error: ") + QLatin1String(e ? e : ""); +#ifdef DEBUG_QSQL_INFORMIX + fprintf(stderr, "qMakeError: %s\n", qPrintable(msg)); +#endif + const struct sqlca_s *my_sqlca = &sqlca; + return QSqlError(QStringLiteral("QInformix: %1").arg(err), msg, type, my_sqlca->sqlcode); +} + +static QVariant::Type qSqlType2Variant(int t) +{ + t &= SQLTYPE; + switch (t) + { + case SQLSMINT: + case SQLINT: + case SQLINTERVAL: + case SQLSERIAL: + return QVariant::Int; + case SQLINT8: + case SQLSERIAL8: + return QVariant::LongLong; + case SQLFLOAT: + case SQLSMFLOAT: + case SQLDECIMAL: + case SQLMONEY: + return QVariant::Double; + case SQLDATE: + return QVariant::Date; + case SQLDTIME: + return QVariant::DateTime; + case SQLBYTES: + return QVariant::ByteArray; + case SQLCHAR: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLLVARCHAR: + case SQLTEXT: + return QVariant::String; + default: + break; + } + qWarning("Unknown sql data type %d", t); + return QVariant::Invalid; +} + +static int qIfxType2SqlType(const char *typeName) +{ + switch (typeName[0]) + { + case 'b': + if (strcmp(typeName, "byte") == 0) + return SQLBYTES; + break; + case 'c': + if (strcmp(typeName, "clob") == 0) + return SQLBYTES; + if (strcmp(typeName, "char") == 0) + return SQLCHAR; + break; + case 'd': + if (strcmp(typeName, "date") == 0) + return SQLDATE; + if (strcmp(typeName, "datetime") == 0) + return SQLDTIME; + if (strcmp(typeName, "decimal") == 0) + return SQLDECIMAL; + break; + case 'f': + if (strcmp(typeName, "float") == 0) + return SQLFLOAT; + break; + case 'i': + if (strcmp(typeName, "integer") == 0) + return SQLINT; + if (strcmp(typeName, "int8") == 0) + return SQLINT8; + break; + case 'l': + if (strcmp(typeName, "lvarchar") == 0) + return SQLLVARCHAR; + break; + case 'n': + if (strcmp(typeName, "nchar") == 0) + return SQLNCHAR; + if (strcmp(typeName, "nvarchar") == 0) + return SQLNVCHAR; + break; + case 's': + if (strcmp(typeName, "serial") == 0) + return SQLSERIAL; + if (strcmp(typeName, "serial8") == 0) + return SQLSERIAL8; + if (strcmp(typeName, "smallint") == 0) + return SQLSMINT; + if (strcmp(typeName, "smallfloat") == 0) + return SQLFLOAT; + break; + case 't': + if (strcmp(typeName, "text") == 0) + return SQLTEXT; + break; + case 'v': + if (strcmp(typeName, "varchar") == 0) + return SQLVCHAR; + break; + default: + break; + } + qWarning("Unknown informix data type '%s'", typeName); + return -1; +} + + +static inline qint64 getLastSerial(ITConnection *itconn) +{ + MI_CONNECTION *conn = itconn->CheckOutConn(); + + mi_integer lastSerial; + mi_last_serial(conn, &lastSerial); + if (lastSerial != 0) + { + itconn->CheckInConn(); + return lastSerial; + } + mi_int8 lastSerial8; + mi_last_serial8(conn, &lastSerial8); + itconn->CheckInConn(); + const quint64 low = static_cast(lastSerial8.data[0]); + const quint64 high = static_cast(lastSerial8.data[1]); + qint64 ret = (high << 32) + low; + return lastSerial8.sign == -1 ? -ret : ret; +} + + + + +class QInformixResultPrivate +{ +public: + QInformixResultPrivate(QInformixResult *qq) + : q(qq) + , driverPrivate(NULL) + , query(NULL) + , result(NULL) + , row(NULL) + , preparedStmt(NULL) + , preparedCursor(NULL) + , currentSize(-1) + , numAffectedRows(-1) + , lastInsertId(-1) + {} + + QInformixResult *q; + QInformixDriverPrivate *driverPrivate; + + ITQuery *query; + + ITSet *result; + + ITRow *row; + + + ITStatement *preparedStmt; + + ITCursor *preparedCursor; + + int currentSize; + int numAffectedRows; + qint64 lastInsertId; + + inline ITConnection *getConnection() const + { + return driverPrivate->connection; + } + void cleanupInternal() + { + q->cleanup(); + if (preparedStmt) + { + preparedStmt->Drop(); + delete preparedStmt; + preparedStmt = NULL; + } + if (preparedCursor) + { + preparedCursor->Drop(); + preparedCursor->Close(); + delete preparedCursor; + preparedCursor = NULL; + } + } +}; + + + + +QInformixResult::QInformixResult(const QInformixDriver *db, QInformixDriverPrivate *p) + : QSqlResult(db) +{ + DEBUG_FUNCTION + + p->addConnection(); + d = new QInformixResultPrivate(this); + d->driverPrivate = p; +} + +QInformixResult::~QInformixResult() +{ + DEBUG_FUNCTION + + d->cleanupInternal(); + d->driverPrivate->removeConnection(); + delete d; +} + +QVariant QInformixResult::handle() const +{ + DEBUG_FUNCTION + + return qVariantFromValue(d->result); +} + +void QInformixResult::cleanup() +{ + DEBUG_FUNCTION + + if (d->query) + { + d->query->Finish(); + delete d->query; + d->query = NULL; + } + if (d->result) + { + d->result->Close(); + d->result->Release(); + d->result = NULL; + } + if (d->row) + { + d->row->Release(); + d->row = NULL; + } + + setActive(false); +} + +bool QInformixResult::fetch(int i) +{ + + + if (!isActive()) + return false; + if (i < 0) + return false; + if (at() == i) + return true; + + if (d->row) + { + d->row->Release(); + d->row = NULL; + } + + if (d->result) + { + if (i >= d->currentSize) + return false; + + ITValue *value = d->result->Fetch(NULL, ITPositionAbsolute, i + 1); + + if (!value) + { + qDebug("QInformixResult::fetch(%d): Fetch failed\n", i); + return false; + } + + int ret = value->QueryInterface(ITRowIID, (void **) & d->row); + if (ret == IT_QUERYINTERFACE_FAILED) + { + value->Release(); + return false; + } + value->Release(); + } + else + { + if (!d->preparedCursor) + return false; + + if (isForwardOnly()) + d->row = d->preparedCursor->NextRow(); + else + d->row = d->preparedCursor->NextRow(NULL, ITPositionAbsolute, i + 1); + if (!d->row) + return false; + } + + setAt(i); + return true; +} + +bool QInformixResult::fetchFirst() +{ + return fetch(0); +} + +bool QInformixResult::fetchLast() +{ + return fetch(d->currentSize - 1); +} + +QVariant QInformixResult::data(int i) +{ + + + if (!d->row) + return QVariant(); + + if (i >= d->row->NumColumns()) + { + qWarning("QInformixResult::data: column %d out of range", i); + return QVariant(); + } + + ITValue *col = d->row->Column(i); + if (!col) + { + qWarning("QInformixResult::data: column %d out of range", i); + return QVariant(); + } + + const int sqlType = qIfxType2SqlType(col->TypeOf().Name()); + if (col->IsNull()) + { + col->Release(); + return QVariant(qSqlType2Variant(sqlType)); + } + + + + QVariant variant; + switch (sqlType) + { + case SQLBYTES: + { + ITDatum *lobj = NULL; + col->QueryInterface(ITDatumIID, (void **) &lobj); + variant = QByteArray((const char *) lobj->Data(), lobj->DataLength()); + lobj->Release(); + break; + } + case SQLTEXT: + { + ITDatum *lobj = NULL; + col->QueryInterface(ITDatumIID, (void **) &lobj); + const QByteArray ba = QByteArray((const char *) lobj->Data()); + variant = d->driverPrivate->fromInformixEncoding(ba); + lobj->Release(); + break; + } + case SQLCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLVCHAR: + case SQLLVARCHAR: + variant = QVariant(d->driverPrivate->fromInformixEncoding(col->Printable())); + break; + case SQLDATE: + { + ITDateTime *dt = NULL; + col->QueryInterface(ITDateTimeIID, (void **) &dt); + variant = QVariant(QDate(dt->Year(), dt->Month(), dt->Day())); + dt->Release(); + break; + } + case SQLDTIME: + { + ITDateTime *dt = NULL; + col->QueryInterface(ITDateTimeIID, (void **) &dt); + const QDate date(QDate(dt->Year(), dt->Month(), dt->Day())); + const int seconds = (int) truncf(dt->Second()); + const int msecs = (int) truncf((dt->Second() - seconds) * 1000); + const QTime time(QTime(dt->Hour(), dt->Minute(), seconds, msecs)); + variant = QVariant(QDateTime(date, time)); + dt->Release(); + break; + } + case SQLDECIMAL: + case SQLFLOAT: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + double dbl; + conv->ConvertTo(dbl); + variant = QVariant(dbl); + conv->Release(); + break; + } + case SQLSERIAL: + case SQLINT: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + int int32; + conv->ConvertTo(int32); + variant = QVariant(int32); + conv->Release(); + break; + } + case SQLSERIAL8: + case SQLINT8: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + long int int64; + conv->ConvertTo(int64); + variant = QVariant((qint64) int64); + conv->Release(); + break; + } + case SQLSMINT: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + short int int16; + conv->ConvertTo(int16); + variant = QVariant(int16); + conv->Release(); + break; + } + default: + variant = QVariant(qSqlType2Variant(sqlType)); + qWarning("QInformixResult::data: Unknown sql data type %d at row %d\n", sqlType, i); + break; + } + col->Release(); + + return variant; +} + +bool QInformixResult::isNull(int i) +{ + DEBUG_FUNCTION + + if (!d->row) + return true; + + if (i >= d->row->NumColumns()) + { + qWarning("QInformixResult::isNull: column %d out of range", i); + return true; + } + + ITValue *col = d->row->Column(i); + if (!col) + { + qWarning("QInformixResult::isNull: column %d out of range", i); + return false; + } + return col->IsNull(); +} + +bool QInformixResult::reset(const QString &query) +{ +#ifdef DEBUG_QSQL_INFORMIX + fprintf(stderr, " QInformixResult::reset(%s)\n", qPrintable(query)); +#endif + + d->cleanupInternal(); + + if (!driver()) + return false; + if (!driver()->isOpen() || driver()->isOpenError()) + return false; + + d->currentSize = -1; + d->numAffectedRows = -1; + d->lastInsertId = -1; + setSelect(false); + + d->query = new ITQuery(*d->getConnection()); + bool bIsSelect = query.trimmed().startsWith(QLatin1String("SELECT"), Qt::CaseInsensitive); + + try + { + if (bIsSelect) + { + d->result = d->query->ExecToSet(d->driverPrivate->toInformixEncoding(query)); + + if (!d->result || !d->result->Open()) + throw false; + + } + else + { + bool bOk = d->query->ExecForStatus(d->driverPrivate->toInformixEncoding(query)); + if (!bOk) + throw false; + } + + if (d->query->Error()) + throw false; + + } + catch (bool bOk) + { + if (!bOk) + { + setLastError(qMakeError(QObject::tr("Unable to create query"), + QSqlError::StatementError, d->driverPrivate)); + return false; + } + } + + setSelect(bIsSelect); + setActive(true); + if (bIsSelect) + d->currentSize = d->query->RowCount(); + else + d->numAffectedRows = d->query->RowCount(); + d->lastInsertId = getLastSerial(d->getConnection()); + + return true; +} + +int QInformixResult::size() +{ + return d->currentSize; +} + +int QInformixResult::numRowsAffected() +{ + DEBUG_FUNCTION + + return d->numAffectedRows; +} + +QVariant QInformixResult::lastInsertId() const +{ + return d->lastInsertId ? QVariant(d->lastInsertId) : QVariant(); +} + +QSqlRecord QInformixResult::record() const +{ + DEBUG_FUNCTION + + QSqlRecord info; + if (!isActive() || !isSelect()) + return info; + + if (!d->query && !d->preparedCursor) + return info; + + const ITTypeInfo *rowInfo = d->query ? d->query->RowType() : d->preparedCursor->RowType(); + const int count = rowInfo->ColumnCount(); + QSqlField f; + for (int i = 0; i < count; ++i) + { + const ITTypeInfo *colInfo = rowInfo->ColumnType(i); + const char *typeName = colInfo->Name(); + const int len = colInfo->Size(); + const int prec = colInfo->Precision(); + const int sqlType = qIfxType2SqlType(typeName); + + f.setName(d->driverPrivate->fromInformixEncoding(rowInfo->ColumnName(i))); + f.setLength(len == -1 ? prec : len); + f.setPrecision(len == -1 ? len : prec); + f.setType(qSqlType2Variant(sqlType)); + f.setSqlType(sqlType); + + if (f.type() == QVariant::Invalid) + qWarning("QInformixResult::record(): Unknown datatype %s", typeName); + + info.append(f); + } + return info; +} + + + +inline QString replaceAt(const QString &str) +{ + QString ret(str); + QChar *data = ret.data(); + const int len = str.length(); + + for (int i = 0; i < len; ++i) + { + if (data[i] == QLatin1Char('@')) + data[i] = QLatin1Char(':'); + } + return ret; +} + +bool QInformixResult::prepare(const QString &_query) +{ + QString query = replaceAt(_query.trimmed()); +#ifdef DEBUG_QSQL_INFORMIX + fprintf(stderr, "QInformixResult::prepare(%s)\n", qPrintable(query)); +#endif + + d->cleanupInternal(); + + bool bIsSelect = query.startsWith(QLatin1String("SELECT"), Qt::CaseInsensitive); + setSelect(bIsSelect); + if (bIsSelect) + { + d->preparedCursor = new ITCursor(*d->getConnection()); + + if (!d->preparedCursor->Prepare(d->driverPrivate->toInformixEncoding(query))) + { + setLastError(qMakeError(QObject::tr("Unable to prepare statement"), + QSqlError::StatementError, d->driverPrivate)); + delete d->preparedCursor; + d->preparedCursor = NULL; + return false; + } + } + else + { + d->preparedStmt = new ITStatement(*d->getConnection()); + + if (!d->preparedStmt->Prepare(d->driverPrivate->toInformixEncoding(query))) + { + setLastError(qMakeError(QObject::tr("Unable to prepare statement"), + QSqlError::StatementError, d->driverPrivate)); + delete d->preparedStmt; + d->preparedStmt = NULL; + return false; + } + } + setActive(true); + + return true; +} + +template +bool bindValues(T *prep, const QVector &boundValues, const QInformixResultPrivate *p, const QSqlDriver *driver) +{ + const int cnt = boundValues.count(); + + if (cnt != prep->NumParams()) + return false; + + QSqlField f; + for (int i = 0; i < cnt; ++i) + { + const QVariant &val = boundValues.at(i); + ITValue *param = prep->Param(i); + + if (val.type() == QVariant::ByteArray) + { + ITDatum *lobj; + + ITTypeInfo ti(*p->getConnection(), "byte"); + + ITMVDesc desc; + desc.vf_origtypeinfo = &ti; + desc.vf_connection = p->getConnection(); + desc.vf_typedesc = NULL; + desc.vf_preservedata = NULL; + desc.vf_outerunknown = NULL; + desc.vf_datalength = ti.Size(); + desc.vf_libmivaluetype = MI_NULL_VALUE; + desc.vf_data = NULL; + ITValue *v = ITFactoryList::DatumToValue(desc); + v->QueryInterface(ITDatumIID, (void **) & lobj); + + QByteArray ba = val.toByteArray(); + if (ba.size()) + lobj->SetData(ba.data(), ba.size()); + else + lobj->SetNull(); + prep->SetParam(i, lobj); + v->Release(); + lobj->Release(); + + } + else + { + const char *t = param->TypeOf().Name(); + if (strcmp(t, "text") == 0) + { + ITDatum *lobj; + + + + ITTypeInfo ti(*p->getConnection(), "byte"); + + ITMVDesc desc; + desc.vf_origtypeinfo = &ti; + desc.vf_connection = p->getConnection(); + desc.vf_typedesc = NULL; + desc.vf_preservedata = NULL; + desc.vf_outerunknown = NULL; + desc.vf_datalength = ti.Size(); + desc.vf_libmivaluetype = MI_NULL_VALUE; + desc.vf_data = NULL; + ITValue *v = ITFactoryList::DatumToValue(desc); + v->QueryInterface(ITDatumIID, (void **) & lobj); + + QByteArray ba = p->driverPrivate->toInformixEncodingBA(val.toString()); + if (ba.size()) + lobj->SetData(ba.data(), ba.size()); + else + lobj->SetNull(); + lobj->FromPrintable(ba.data()); + prep->SetParam(i, lobj); + v->Release(); + lobj->Release(); + + } + else + { + f.setType(val.type()); + f.setValue(val); + if (!param->FromPrintable(p->driverPrivate->toInformixEncoding(driver->formatValue(f)))) + return false; + } + } + param->Release(); + } + return true; +} + +bool QInformixResult::exec() +{ + DEBUG_FUNCTION + + if (isSelect()) + { + if (d->query) + return false; + if (!d->preparedCursor) + return false; + + cleanup(); + + setActive(true); + + const int openMode = isForwardOnly() ? ITCursor::ReadOnly : ITCursor::ReadOnly + ITCursor::Scrollable; + if (!bindValues(d->preparedCursor, boundValues(), d, driver()) || + !d->preparedCursor->Open(openMode)) + { + setLastError(qMakeError(QObject::tr("Unable to execute statement"), + QSqlError::StatementError, d->driverPrivate)); + d->preparedCursor->Drop(); + d->preparedCursor->Close(); + delete d->preparedCursor; + d->preparedCursor = NULL; + return false; + } + d->lastInsertId = -1; + d->numAffectedRows = -1; + d->currentSize = -1; + } + else + { + if (!d->preparedStmt) + return false; + + cleanup(); + + setActive(true); + + if (!bindValues(d->preparedStmt, boundValues(), d, driver()) || + !d->preparedStmt->Exec()) + { + setLastError(qMakeError(QObject::tr("Unable to execute statement"), + QSqlError::StatementError, d->driverPrivate)); + d->preparedStmt->Drop(); + delete d->preparedStmt; + d->preparedStmt = NULL; + return false; + } + d->currentSize = -1; + d->lastInsertId = getLastSerial(d->getConnection()); + d->numAffectedRows = d->preparedStmt->RowCount(); + } + return true; +} + + + + +QInformixDriver::QInformixDriver(QObject *parent) + : QSqlDriver(parent) +{ + init(); +} + +void QInformixDriver::init() +{ + d = new QInformixDriverPrivate(this); +} + +QInformixDriver::~QInformixDriver() +{ + if (d->connection) + close(); + delete d; +} + +QVariant QInformixDriver::handle() const +{ + return qVariantFromValue(d->connection); +} + +bool QInformixDriver::hasFeature(DriverFeature f) const +{ + switch (f) + { + case LastInsertId: + case Transactions: + case QuerySize: + case PreparedQueries: + return true; + case LowPrecisionNumbers: + case EventNotifications: + case SimpleLocking: + case FinishQuery: + case MultipleResultSets: + case PositionalPlaceholders: + case BatchOperations: + case NamedPlaceholders: + case CancelQuery: + return false; + case BLOB: + case Unicode: + return true; + } + return false; +} + +bool QInformixDriver::open(const QString &db, + const QString &user, + const QString &password, + const QString &host, + int port, + const QString &connOpts) +{ + Q_UNUSED(port) + const QVector options = connOpts.splitRef(QLatin1Char(';')); + QString dbLocale = QStringLiteral("UTF-8"); + + d->connTimeout = -1; + d->connectOnFirstUse = false; + for (const QStringRef &opt : options) + { + if (opt.startsWith(QLatin1String("DB_LOCALE="))) + dbLocale = opt.mid(strlen("DB_LOCALE=")).toString(); + if (opt.startsWith(QLatin1String("CONN_TIMEOUT="))) + { + bool bOk; + d->connTimeout = opt.mid(strlen("CONN_TIMEOUT=")).toInt(&bOk); + if (bOk && d->connTimeout > 0) + { + d->connTimeout *= 1000; + QTimer::singleShot(d->connTimeout, this, SLOT(timeout())); + } + else + d->connTimeout = -1; + } + if (opt.startsWith(QLatin1String("CONNECT_ON_FIRST_USE="))) + { + bool bOk; + int val = opt.mid(strlen("CONNECT_ON_FIRST_USE=")).toInt(&bOk); + if (bOk) + d->connectOnFirstUse = (val != 0); + else + d->connectOnFirstUse = false; + } + } +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s connTimeout: %d\n", this, __PRETTY_FUNCTION__, d->connTimeout); +#endif + d->dbLocale = QTextCodec::codecForName(dbLocale.toUtf8()); + if (!d->dbLocale) + { + setLastError(qMakeError(tr("Can't create Codec for Name %1").arg(dbLocale), QSqlError::ConnectionError, d)); + setOpenError(true); + return false; + } + + if (isOpen()) + close(); + + if (!host.isEmpty()) + d->conn_params.SetSystem(d->toInformixEncoding(host)); + if (!db.isEmpty()) + d->conn_params.SetDatabase(d->toInformixEncoding(db)); + if (!user.isEmpty()) + d->conn_params.SetUser(d->toInformixEncoding(user)); + if (!password.isEmpty()) + d->conn_params.SetPassword(d->toInformixEncoding(password)); + d->conn_params.Freeze(); + + d->connection = new ITConnection(); + + if (d->connectOnFirstUse) + return true; + + return openDatabaseInternal(); +} + +bool QInformixDriver::openDatabaseInternal() +{ + int ret = d->connection->Open(d->conn_params); + + if (!ret || !d->connection->IsOpen()) + { + setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d)); + setOpenError(true); + d->connection->Close(); + delete d->connection; + d->connection = 0; + return false; + } + + setOpen(true); + setOpenError(false); + return true; +} + +void QInformixDriver::close() +{ + DEBUG_FUNCTION + + if (isOpen()) + { + d->connection->Close(); + setOpen(false); + setOpenError(false); + } + delete d->connection; + d->connection = 0; +} + +bool QInformixDriver::isOpen() const +{ + return (d->connection); + +} + +QSqlResult *QInformixDriver::createResult() const +{ + return new QInformixResult(this, d); +} + +QStringList QInformixDriver::tables(QSql::TableType type) const +{ + DEBUG_FUNCTION + + QStringList tl; + if (!isOpen()) + return tl; + QSqlQuery t(createResult()); + t.setForwardOnly(true); + + if (type == 0) + type = QSql::Tables; + QString cmd; + if ((type & (QSql::SystemTables | QSql::Tables)) == (QSql::SystemTables | QSql::Tables)) + cmd = QStringLiteral("select tabname from systables where tabid >= 0"); + else if ((type & QSql::SystemTables) == QSql::SystemTables) + cmd = QStringLiteral("select tabname from systables where tabid < 100"); + else + cmd = QStringLiteral("select tabname from systables where tabid >= 100"); + + if ((type & (QSql::Tables | QSql::Views)) == (QSql::Tables | QSql::Views)) + cmd += QStringLiteral(" and (tabtype = 'T' or tabtype = 'V')"); + else if ((type & QSql::Tables) == QSql::Tables) + cmd += QStringLiteral(" and tabtype = 'T'"); + else if ((type & QSql::Views) == QSql::Views) + cmd += QStringLiteral(" and tabtype = 'V'"); + cmd += QStringLiteral(" order by tabid"); + + t.exec(cmd); + while (t.next()) + tl.append(t.value(0).toString()); + + return tl; +} + +static void qSplitTableName(QString &tablename, QString &schema) +{ + int dot = tablename.indexOf(QLatin1Char('.')); + if (dot == -1) + return; + schema = tablename.left(dot); + tablename = tablename.mid(dot + 1); +} + +QSqlIndex QInformixDriver::primaryIndex(const QString &tablename) const +{ + QSqlIndex idx(tablename); + if (!isOpen()) + return idx; + QSqlQuery i(createResult()); + + QString tbl = tablename; + QString schema; + qSplitTableName(tbl, schema); + + QString cmd(QStringLiteral("select syscolumns.colname, syscolumns.coltype, si.idxname " + "from syscolumns " + "left outer join sysindexes si on syscolumns.tabid = si.tabid " + "where syscolumns.tabid = (select tabid from systables where tabname='%1') " + "and colno = (select part1 from sysindexes where tabid = ( " + "select tabid from systables where tabname='%1') " + "and idxname = (select idxname from sysconstraints where tabid=( " + "select tabid from systables where tabname='%1') " + "and constrtype='P'))" + )); + + i.exec(cmd.arg(tbl.toLower())); + while (i.isActive() && i.next()) + { + QSqlField f(i.value(0).toString(), qSqlType2Variant(i.value(1).toInt())); + idx.append(f); + idx.setName(i.value(2).toString()); + } + + return idx; +} + +QSqlRecord QInformixDriver::record(const QString &tablename) const +{ + QSqlRecord info; + if (!isOpen()) + return info; + + QString tbl = tablename; + QString schema; + qSplitTableName(tbl, schema); + + QString cmd(QStringLiteral("select " + "syscolumns.colname, syscolumns.coltype, syscolumns.collength " + "from systables, syscolumns " + "where systables.tabname = '%1' " + "and systables.tabid = syscolumns.tabid")); + + QSqlQuery query(createResult()); + query.exec(cmd.arg(tbl.toLower())); + + while (query.next()) + { + const int sqltype = query.value(1).toInt(); + QSqlField f(query.value(0).toString(), qSqlType2Variant(sqltype)); + f.setRequired((sqltype & SQLNONULL) == SQLNONULL); + f.setLength(query.value(2).toInt()); + + + f.setSqlType(sqltype & SQLTYPE); + f.setAutoValue((sqltype & SQLTYPE) == SQLSERIAL || (sqltype & SQLTYPE) == SQLSERIAL8); + + info.append(f); + } + + return info; +} + +QString QInformixDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const +{ + QString res = identifier; + res.replace(QLatin1Char('"'), QStringLiteral("\"\"")); + res.replace(QLatin1Char('.'), QStringLiteral("\".\"")); + return res; +} + +QString QInformixDriver::formatValue(const QSqlField &field, bool trimStrings) const +{ + QString r; + switch (field.type()) + { + case QVariant::DateTime: + if (field.value().toDateTime().isValid()) + { + const QDate dt = field.value().toDateTime().date(); + const QTime tm = field.value().toDateTime().time(); + + r = QString::number(dt.year()) + QLatin1Char('-') + + QString::number(dt.month()).rightJustified(2, QLatin1Char('0')) + QLatin1Char('-') + + QString::number(dt.day()).rightJustified(2, QLatin1Char('0')) + QLatin1Char(' ') + + tm.toString(); + + } + else + r = QStringLiteral("NULL"); + break; + case QVariant::Date: + if (field.value().toDate().isValid()) + { + const QDate dt = field.value().toDateTime().date(); + + r = QString::number(dt.year()) + QLatin1Char('-') + + QString::number(dt.month()).rightJustified(2, QLatin1Char('0')) + QLatin1Char('-') + + QString::number(dt.day()).rightJustified(2, QLatin1Char('0')); + + } + else + r = QStringLiteral("NULL"); + break; + case QVariant::String: + return trimStrings ? field.value().toString().trimmed() : field.value().toString(); + default: + return QSqlDriver::formatValue(field, trimStrings); + } + return r; +} + +bool QInformixDriver::beginTransaction() +{ + if (!isOpen()) + { + qWarning("QInformixDriver::beginTransaction: Database not open"); + return false; + } + d->addConnection(); + + if (!d->connection->SetTransaction(ITConnection::Begin)) + { + setLastError(qMakeError(tr("Could not begin transaction"), + QSqlError::TransactionError, d)); + d->removeConnection(); + return false; + } + return true; +} + +bool QInformixDriver::commitTransaction() +{ + if (!isOpen()) + { + qWarning("QInformixDriver::commitTransaction: Database not open"); + return false; + } + + if (!d->connection->SetTransaction(ITConnection::Commit)) + { + setLastError(qMakeError(tr("Could not commit transaction"), + QSqlError::TransactionError, d)); + d->removeConnection(); + return false; + } + d->removeConnection(); + return true; +} + +bool QInformixDriver::rollbackTransaction() +{ + if (!isOpen()) + { + qWarning("QInformixDriver::rollbackTransaction: Database not open"); + return false; + } + + if (!d->connection->SetTransaction(ITConnection::Abort)) + { + setLastError(qMakeError(tr("Could not rollback transaction"), + QSqlError::TransactionError, d)); + d->removeConnection(); + return false; + } + d->removeConnection(); + return true; +} + +void QInformixDriver::timeout() +{ +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s private: %p\n", this, __PRETTY_FUNCTION__, d); +#endif + d->closeConnection(); +} diff --git a/Z/src/qsql_informix/qsql_informix.h b/Z/src/qsql_informix/qsql_informix.h new file mode 100755 index 000000000..e1561105d --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix.h @@ -0,0 +1,88 @@ + + + +#pragma once + +#include +#include + +#ifndef Q_EXPORT_SQLDRIVER_INFORMIX +# ifdef MAKE_QSQL_INFORMIX_LIB +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_EXPORT +# else +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_IMPORT +# endif +#endif + +class QInformixResultPrivate; +class QInformixDriverPrivate; +class QInformixDriver; + +class QInformixResult final : public QSqlResult +{ + friend class QInformixResultPrivate; +public: + QInformixResult(const QInformixDriver *db, QInformixDriverPrivate *p); + ~QInformixResult(); + + QVariant handle() const; + +protected: + void cleanup(); + bool fetch(int i); + bool fetchFirst(); + bool fetchLast(); + QVariant data(int i); + bool isNull(int field); + bool reset(const QString &query); + int size(); + int numRowsAffected(); + QSqlRecord record() const; + QVariant lastInsertId() const; + bool prepare(const QString &query); + bool exec(); + +private: + QInformixResultPrivate *d; +}; + +class Q_EXPORT_SQLDRIVER_INFORMIX QInformixDriver final : public QSqlDriver +{ + Q_OBJECT +public: + + explicit QInformixDriver(QObject *parent = nullptr); + ~QInformixDriver(); + bool hasFeature(DriverFeature f) const; + bool open(const QString &db, + const QString &user, + const QString &password, + const QString &host, + int port, + const QString &connOpts); + bool isOpen() const; + void close(); + + QSqlResult *createResult() const; + QStringList tables(QSql::TableType) const; + QSqlIndex primaryIndex(const QString &tablename) const; + QSqlRecord record(const QString &tablename) const; + + QVariant handle() const; + + QString escapeIdentifier(const QString &identifier, IdentifierType type) const; + QString formatValue(const QSqlField &field, bool trimStrings) const; + +protected: + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); + +private: + void init(); + bool openDatabaseInternal(); + QInformixDriverPrivate *d; + friend class QInformixDriverPrivate; +private Q_SLOTS: + void timeout(); +}; diff --git a/Z/src/qsql_informix/qsql_informix.json b/Z/src/qsql_informix/qsql_informix.json new file mode 100755 index 000000000..1079715d6 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "QInformix" ] +} diff --git a/Z/src/qsql_informix/qsql_informix_plugin.cpp b/Z/src/qsql_informix/qsql_informix_plugin.cpp new file mode 100755 index 000000000..28a5dbe69 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_plugin.cpp @@ -0,0 +1,28 @@ + + + +#include +#include "qsql_informix.h" + +class QInformixDriverPlugin final : public QSqlDriverPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "qsql_informix.json") +public: + QInformixDriverPlugin() = default; + + QSqlDriver *create(const QString &); +}; + +QSqlDriver *QInformixDriverPlugin::create(const QString &name) +{ + if (name == QLatin1String("QInformix")) + { + QInformixDriver *driver = new QInformixDriver(); + return driver; + } + return nullptr; +} + +#include "qsql_informix_plugin.moc" + diff --git a/Z/src/qsql_informix/qsql_informix_test.cpp b/Z/src/qsql_informix/qsql_informix_test.cpp new file mode 100755 index 000000000..03cb74d21 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_test.cpp @@ -0,0 +1,277 @@ + + + +#include +#include +#include +#include +#include +#include +#include + +#include "qsql_informix.h" +#include "qsql_informix_utils.h" + +class qsql_informix_test : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void connectDatabase(); + void createTestTable(); + void test_insert(); + void test_select(); + void test_prepare(); + void test_insert_blob(); + void test_select_blob(); + void test_transactions(); + void deleteTestTable(); + void createDB(); + void existsDB(); + void dropDB(); + +}; + +static QString informixServer() +{ + QByteArray srv = qgetenv("INFORMIXSERVER"); + if (srv.isEmpty()) + srv = "guezdbs1_tcp"; + return QString::fromLocal8Bit(srv); +} + +void qsql_informix_test::connectDatabase() +{ + QInformixDriver *drv = new QInformixDriver(); + QSqlDatabase db = QSqlDatabase::addDatabase(drv); + db.setHostName(informixServer()); + QByteArray sys_db = qgetenv("INFORMIXSYSDB"); + if (sys_db.isEmpty()) + sys_db = "int_sys_db"; + db.setDatabaseName(QString::fromLocal8Bit(sys_db)); + db.setUserName(QLatin1String("informix")); + db.setPassword(QLatin1String("informix")); + QByteArray sqlhosts = qgetenv("INFORMIXSQLHOSTS"); + QByteArray informixdir = qgetenv("INFORMIXDIR"); + qDebug() << "Conneting to" << informixServer() + << "database" << sys_db + << "with sqlhosts" << sqlhosts + << "and INFORMIXDIR" << informixdir; + bool bConnect = db.open(); + if (!bConnect) + qDebug() << "Error connecting:" << db.lastError(); + QVERIFY(bConnect); +} + +void qsql_informix_test::createTestTable() +{ + + QSqlQuery q1(QLatin1String("drop table qsql_informix_test")); + q1.exec(); + + QSqlQuery q2; + QString stmt(QLatin1String("create table qsql_informix_test (id int primary key, " + "text nchar(10), vartext varchar(10), text1 char(10), vartext1 varchar(10), blob byte, blobtext text)")); + QVERIFY(q2.exec(stmt)); +} + +void qsql_informix_test::test_insert() +{ + QSqlQuery q1; + QString stmt(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( 1, 'text1', 'vartext1', 'text1', 'vartext1' )")); + QCOMPARE(q1.size(), -1); + QVERIFY(q1.exec(stmt)); + + QSqlQuery q2; + QVERIFY(q2.prepare(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( :id, :text, :vartext, :text, :vartext )"))); + q2.bindValue(QLatin1String(":id"), 2); + q2.bindValue(QLatin1String(":text"), QLatin1String("text2")); + q2.bindValue(QLatin1String(":vartext"), QLatin1String("vartext2")); + QVERIFY(q2.exec()); + QCOMPARE(q2.numRowsAffected(), 1); + + + QVERIFY(q2.prepare(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( 3, 'text3', 'vartext3', 'text3', 'vartext3' )"))); + QVERIFY(q2.exec()); + + QSqlQuery q3(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( 4, 'text4', 'vartext4', 'text4', 'vartext4' )")); + QCOMPARE(q3.exec(), false); +} + +void qsql_informix_test::test_select() +{ + QSqlQuery q1(QLatin1String("select text from qsql_informix_test where id = 1")); + QCOMPARE(q1.size(), 1); + QVERIFY(q1.next()); + QCOMPARE(q1.value(0).toString(), QLatin1String("text1")); + + QSqlQuery q2(QLatin1String("select vartext from qsql_informix_test where id = 1")); + QVERIFY(q2.next()); + + QCOMPARE(q2.value(0).toString(), QLatin1String("vartext1")); + + QSqlQuery q3(QLatin1String("select vartext from qsql_informix_test")); + QVERIFY(q3.next()); + QCOMPARE(q3.size(), 4); + + QVERIFY(q3.prepare(QLatin1String("select vartext, text from qsql_informix_test"))); + QVERIFY(q3.exec()); + QVERIFY(q3.next()); + QCOMPARE(q3.value(0).toString(), QLatin1String("vartext1")); + QCOMPARE(q3.size(), -1); + + + QSqlQuery q4(QLatin1String("select text1 from qsql_informix_test where id = 1")); + QVERIFY(q4.next()); + QCOMPARE(q4.value(0).toString(), QLatin1String("text1")); + + + QSqlQuery q5(QLatin1String("select vartext1 from qsql_informix_test where id = 1")); + QVERIFY(q5.next()); + QCOMPARE(q5.value(0).toString(), QLatin1String("vartext1")); +} + +void qsql_informix_test::test_prepare() +{ + + +#if 0 + QSqlQuery q1; + QVERIFY(q1.prepare(QLatin1String("select * from qsql_informix_test"))); + QVERIFY(q1.exec()); + QCOMPARE(q1.size(), 3); +#endif +} + + +void qsql_informix_test::test_insert_blob() +{ + QSqlQuery q; + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blob) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 14); + q.bindValue(QLatin1String(":blob"), QByteArray(200, 'a')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 15); + q.bindValue(QLatin1String(":blob"), QByteArray(200, 'A')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 16); + q.bindValue(QLatin1String(":blob"), QByteArray(2, 'B')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("update qsql_informix_test set blobtext = :blob where id = :id"))); + q.bindValue(QLatin1String(":id"), 16); + q.bindValue(QLatin1String(":blob"), QByteArray(200, 'B')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 17); + QString str = QString::fromUtf8("öäü"); + q.bindValue(QLatin1String(":blob"), str); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 18); + str = QLatin1String("abcdefghjklimnopqrstuvwxyz"); + q.bindValue(QLatin1String(":blob"), str); + QVERIFY(q.exec()); +} + +void qsql_informix_test::test_select_blob() +{ + QSqlQuery q1(QLatin1String("select blob from qsql_informix_test where id = 14")); + QCOMPARE(q1.size(), 1); + QVERIFY(q1.next()); + QCOMPARE(q1.value(0).toByteArray(), QByteArray(200, 'a')); + + QSqlQuery q2(QLatin1String("select blobtext from qsql_informix_test where id = 15")); + QCOMPARE(q2.size(), 1); + QVERIFY(q2.next()); + QCOMPARE(q2.value(0).toByteArray(), QByteArray(200, 'A')); + + QSqlQuery q3(QLatin1String("select blobtext from qsql_informix_test where id = 16")); + QCOMPARE(q3.size(), 1); + QVERIFY(q3.next()); + QCOMPARE(q3.value(0).toByteArray(), QByteArray(200, 'B')); + + QSqlQuery q4(QLatin1String("select blobtext from qsql_informix_test where id = 17")); + QCOMPARE(q4.size(), 1); + QVERIFY(q4.next()); + QString str = QString::fromUtf8("öäü"); + QCOMPARE(q4.value(0).toString(), str); + + QSqlQuery q5(QLatin1String("select blobtext from qsql_informix_test where id = 18")); + QCOMPARE(q5.size(), 1); + QVERIFY(q5.next()); + str = QLatin1String("abcdefghjklimnopqrstuvwxyz"); + QCOMPARE(q5.value(0).toString(), str); +} + +void qsql_informix_test::test_transactions() +{ + QSqlDatabase db = QSqlDatabase::database(); + QVERIFY(db.transaction()); + QString stmt(QLatin1String("insert into qsql_informix_test (id, text, vartext) values " + "( 100, 'text1', 'vartext1' )")); + QSqlQuery q; + QVERIFY(q.exec(stmt)); + QVERIFY(db.commit()); + + QVERIFY(db.transaction()); + stmt = QLatin1String("insert into qsql_informix_test (id, text, vartext) values " + "( 101, 'text1', 'vartext1' )"); + QVERIFY(q.exec(stmt)); + QVERIFY(db.rollback()); + + stmt = QLatin1String("select * from qsql_informix_test where id = 101"); + QVERIFY(q.exec(stmt)); + QCOMPARE(q.size(), 0); +} + +void qsql_informix_test::deleteTestTable() +{ + QSqlQuery q; + QString stmt(QLatin1String("drop table qsql_informix_test")); + QVERIFY(q.exec(stmt)); +} + +void qsql_informix_test::createDB() +{ + QInformixUtils u; + + QVERIFY(u.createDatabase(informixServer(), + QLatin1String("newdatabase"), + QLatin1String("informix"), + QLatin1String("informix"), + QLatin1String("uebungsdaten_dbs"))); +} + +void qsql_informix_test::existsDB() +{ + QInformixUtils u; + QVERIFY(u.existsDbName(informixServer(), + QLatin1String("newdatabase"), + QLatin1String("informix"), + QLatin1String("informix"))); +} + +void qsql_informix_test::dropDB() +{ + QInformixUtils u; + QVERIFY(u.dropDatabase(informixServer(), + QLatin1String("newdatabase"), + QLatin1String("informix"), + QLatin1String("informix"))); +} + +QTEST_MAIN(qsql_informix_test) + +#include "qsql_informix_test.moc" diff --git a/Z/src/qsql_informix/qsql_informix_utils.cpp b/Z/src/qsql_informix/qsql_informix_utils.cpp new file mode 100755 index 000000000..433d37a83 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_utils.cpp @@ -0,0 +1,98 @@ + + + +#include "qsql_informix_utils.h" + + +#include +#include +#include +#include + +bool QInformixUtils::createDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd, const QString &dbspace) +{ + ITDBInfo info; + + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase(ITString(newDb.toUtf8().constData())); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + bool bOk = info.CreateDatabase(ITDBInfo::Log, ITString(dbspace.toUtf8().constData())); + m_errortext = QString::fromLocal8Bit(info.ErrorText()); + m_sqlstate = QString::fromLocal8Bit(info.SqlState()); + + return bOk; +} + +bool QInformixUtils::dropDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd) +{ + ITDBInfo info; + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase(ITString(newDb.toUtf8().constData())); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + bool bOk = info.DropDatabase(); + m_errortext = QString::fromLocal8Bit(info.ErrorText()); + m_sqlstate = QString::fromLocal8Bit(info.SqlState()); + + return bOk; +} + +QStringList QInformixUtils::dbListName(const QString &host, const QString &db, + const QString &user, const QString &passwd) +{ + QStringList sl; + ITDBInfo info; + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase(ITString(db.toUtf8().constData())); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + ITConnection connection; + bool bOk = connection.Open(info); + + if (!bOk) return sl; + + ITDBNameList nl; + bOk = nl.Create(); + + if (!bOk) + return sl; + + ITString dbName = nl.NextDBName(); + while (!dbName.IsNull()) + { + sl.append(QString::fromUtf8(dbName.Data())); + dbName = nl.NextDBName(); + } + + return sl; +} + +bool QInformixUtils::existsDbName(const QString &host, const QString &db, + const QString &user, const QString &passwd) +{ + ITDBInfo info; + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase("sysmaster"); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + ITConnection connection; + bool bOk = connection.Open(info); + + if (!bOk) return false; + + ITDBNameList nl; + if (!nl.Create()) + return false; + + if (nl.IsDBName(ITString(db.toUtf8().constData()))) + return true; + + return false; +} diff --git a/Z/src/qsql_informix/qsql_informix_utils.h b/Z/src/qsql_informix/qsql_informix_utils.h new file mode 100755 index 000000000..135508fc5 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_utils.h @@ -0,0 +1,41 @@ + + + +#pragma once + +#include +#include + +#ifndef Q_EXPORT_SQLDRIVER_INFORMIX +# ifdef MAKE_QSQL_INFORMIX_LIB +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_EXPORT +# else +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_IMPORT +# endif +#endif + +class Q_EXPORT_SQLDRIVER_INFORMIX QInformixUtils +{ + +public: + QInformixUtils() {} + ~QInformixUtils() {} + + bool createDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd, const QString &dbspace); + bool dropDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd); + + bool existsDbName(const QString &host, const QString &db, + const QString &user, const QString &passwd); + + QStringList dbListName(const QString &host, const QString &db, + const QString &user, const QString &passwd); + + QString errorText() const { return m_errortext; } + QString sqlState() const { return m_sqlstate; } + +private: + QString m_errortext; + QString m_sqlstate; +}; diff --git a/Z/src/tcpserver/CMakeLists.txt b/Z/src/tcpserver/CMakeLists.txt new file mode 100755 index 000000000..151a1d8b4 --- /dev/null +++ b/Z/src/tcpserver/CMakeLists.txt @@ -0,0 +1,56 @@ +# tcpserver +SET(tcp_SRCS + commandinterface.cpp + commandinterface.h + cbi_help.cpp + cbi_help.h + cbi_quit.cpp + cbi_quit.h + cbi_shutdown.cpp + cbi_shutdown.h + tcpserver.cpp + tcpserver.h + tcpserver_export.h + tcpserver_logger.h + workerbase.cpp + workerbase.h +) + +SET(tcp_HDRS +) + +NGL_ADD_LIBRARY(tcpserver AAR SV SHARED ${tcp_SRCS}) +NGL_TARGET_LINK_LIBRARIES(tcpserver + PRIVATE + Qt5::Network + ngltools + PUBLIC + Qt5::Core + NGLLogger +) +NGL_TARGET_INCLUDE_DIRECTORIES(tcpserver + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_INSTALL_TARGET(tcpserver) + +IF(BUILD_TESTING AND BUILD_SV AND NOT WIN32) + LIST(APPEND tcp_test_SRCS + cbi_pingpong.cpp + cbi_pingpong.h + cbi_recvfile.cpp + cbi_recvfile.h + cbi_sendfile.cpp + cbi_sendfile.h + tcpserver_test.cpp + ) + + ADD_EXECUTABLE(tcpserver_test ${tcp_test_SRCS}) + TARGET_LINK_LIBRARIES(tcpserver_test + Qt5::Core + Qt5::Network + tcpserver + NGLLogger + ) +ENDIF() + diff --git a/Z/src/tcpserver/cbi_help.cpp b/Z/src/tcpserver/cbi_help.cpp new file mode 100755 index 000000000..209947254 --- /dev/null +++ b/Z/src/tcpserver/cbi_help.cpp @@ -0,0 +1,29 @@ + + + +#include "cbi_help.h" +#include "workerbase.h" + +#include +#include + +CBI_Help::CBI_Help(unsigned short port) + : CommandInterface(port, "HELP") +{} + +void CBI_Help::handleCommandInternal(const QVector &) +{ + const auto commands = workerBase()->getCommands(); + QStringList list; + list.reserve(commands.size()); + for (const CommandInterface *i : commands) + list += i->help(); + + std::sort(list.begin(), list.end()); + writeData(list.join(QLatin1Char('\n'))); +} + +QString CBI_Help::help() const +{ + return QLatin1String("HELP - prints out help informations"); +} diff --git a/Z/src/tcpserver/cbi_help.h b/Z/src/tcpserver/cbi_help.h new file mode 100755 index 000000000..6e49363d2 --- /dev/null +++ b/Z/src/tcpserver/cbi_help.h @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class TCPSERVER_EXPORT CBI_Help : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Help(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_pingpong.cpp b/Z/src/tcpserver/cbi_pingpong.cpp new file mode 100755 index 000000000..da6748e38 --- /dev/null +++ b/Z/src/tcpserver/cbi_pingpong.cpp @@ -0,0 +1,23 @@ + + + +#include "cbi_pingpong.h" + +CBI_PingPong::CBI_PingPong(unsigned short port) + : CommandInterface(port, "PING") +{} + +void CBI_PingPong::handleCommandInternal(const QVector &args) +{ + writeData("PONG"); + for (const QByteArray &ba : args) + { + writeData(" "); + writeData(quote(ba.constData())); + } +} + +QString CBI_PingPong::help() const +{ + return QString::fromUtf8("PING - mirror the Input and send the data back"); +} diff --git a/Z/src/tcpserver/cbi_pingpong.h b/Z/src/tcpserver/cbi_pingpong.h new file mode 100755 index 000000000..94f94e658 --- /dev/null +++ b/Z/src/tcpserver/cbi_pingpong.h @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class CBI_PingPong : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_PingPong(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_quit.cpp b/Z/src/tcpserver/cbi_quit.cpp new file mode 100755 index 000000000..891e9598d --- /dev/null +++ b/Z/src/tcpserver/cbi_quit.cpp @@ -0,0 +1,19 @@ + + + +#include "cbi_quit.h" + +CBI_Quit::CBI_Quit(unsigned short port) + : CommandInterface(port, "QUIT") +{} + +void CBI_Quit::handleCommandInternal(const QVector &) +{ + writeOk(QLatin1String("Bye!")); + closeConnection(); +} + +QString CBI_Quit::help() const +{ + return QLatin1String("QUIT - close the current connection"); +} diff --git a/Z/src/tcpserver/cbi_quit.h b/Z/src/tcpserver/cbi_quit.h new file mode 100755 index 000000000..33b15b756 --- /dev/null +++ b/Z/src/tcpserver/cbi_quit.h @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class TCPSERVER_EXPORT CBI_Quit : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Quit(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_recvfile.cpp b/Z/src/tcpserver/cbi_recvfile.cpp new file mode 100755 index 000000000..85425edcf --- /dev/null +++ b/Z/src/tcpserver/cbi_recvfile.cpp @@ -0,0 +1,86 @@ + + + +#include "cbi_recvfile.h" +#include "workerbase.h" + +#include +#include +#include +#include + +CBI_Recvfile::CBI_Recvfile(unsigned short port) + : CommandInterface(port, "RECV_FILE") +{} + +void CBI_Recvfile::handleCommandInternal(const QVector &args) +{ + if (args.count() != 2) + { + writeError(QLatin1String("Invalid arg count: RECV_FILE ")); + return; + } + + QString fn = QString::fromUtf8(args[0]); + int size; + getValue(args[1], size); + + QFile *f = new QFile(fn); + if (!f->open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + writeError(QStringLiteral("Could not open %1 for writing").arg(fn)); + return; + } + m_wbMap.insert(workerBase(), QPair(f, size)); + workerBase()->redirectDataHandling(true, this); +} + +void CBI_Recvfile::newPlainData() +{ + WorkerBase *wb = workerBase(); + QAbstractSocket *in = socket(); + QIODevice *out = m_wbMap[ wb ].first; + if (!out) + { + in->write("ERROR\n"); + + wb->redirectDataHandling(false); + return; + } + int size = m_wbMap[ wb ].second; + + + QByteArray ba(10, 0); + do + { + qint64 bytesRead = in->read(ba.data(), ba.size() < size ? ba.size() : size); + if (bytesRead < 0) + { + in->write("ERROR\n"); + + m_wbMap.remove(wb); + wb->redirectDataHandling(false); + return; + } + size -= bytesRead; + out->write(ba.constData(), bytesRead); + } + while (size > 0 && in->bytesAvailable()); + + + if (size != 0) + { + m_wbMap[ wb ].second = size; + return; + } + out->close(); + delete out; + + m_wbMap.remove(wb); + wb->redirectDataHandling(false); +} + +QString CBI_Recvfile::help() const +{ + return QLatin1String("RECV_FILE "); +} diff --git a/Z/src/tcpserver/cbi_recvfile.h b/Z/src/tcpserver/cbi_recvfile.h new file mode 100755 index 000000000..57a7b013d --- /dev/null +++ b/Z/src/tcpserver/cbi_recvfile.h @@ -0,0 +1,23 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" +#include +#include + +class QIODevice; +class CBI_Recvfile : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Recvfile(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; + void newPlainData() override; +protected: + QMap > m_wbMap; +}; diff --git a/Z/src/tcpserver/cbi_sendfile.cpp b/Z/src/tcpserver/cbi_sendfile.cpp new file mode 100755 index 000000000..8e6d8321e --- /dev/null +++ b/Z/src/tcpserver/cbi_sendfile.cpp @@ -0,0 +1,45 @@ + + + +#include "cbi_sendfile.h" +#include "workerbase.h" + +#include +#include +#include +#include + +CBI_Sendfile::CBI_Sendfile(unsigned short port) + : CommandInterface(port, "SEND_FILE") +{} + +void CBI_Sendfile::handleCommandInternal(const QVector &args) +{ + if (args.count() != 1) + { + writeError(QLatin1String("Invalid arg count: SEND_FILE ")); + return; + } + + QString fn = QString::fromUtf8(args[0]); + QFile f(fn); + if (!f.exists()) + { + writeError(QStringLiteral("File %1 does not exist").arg(fn)); + return; + } + if (!f.open(QIODevice::ReadOnly)) + { + writeError(QStringLiteral("Could not open file %1 for reading").arg(fn)); + return; + } + writeOk(QString::number(f.size())); + writeEOL(); + setAutoWriteEOL(false); + writeData(f.readAll()); +} + +QString CBI_Sendfile::help() const +{ + return QLatin1String("SEND_FILE "); +} diff --git a/Z/src/tcpserver/cbi_sendfile.h b/Z/src/tcpserver/cbi_sendfile.h new file mode 100755 index 000000000..adece8466 --- /dev/null +++ b/Z/src/tcpserver/cbi_sendfile.h @@ -0,0 +1,17 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + +class CBI_Sendfile : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Sendfile(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_shutdown.cpp b/Z/src/tcpserver/cbi_shutdown.cpp new file mode 100755 index 000000000..e923645e8 --- /dev/null +++ b/Z/src/tcpserver/cbi_shutdown.cpp @@ -0,0 +1,25 @@ + + + +#include "cbi_shutdown.h" +#include "tcpserver.h" + +CBI_Shutdown::CBI_Shutdown(unsigned short port) + : CommandInterface(port, "SHUTDOWN") +{ + connect(this, &CBI_Shutdown::shutdownRequest, + TcpServer::instance(port), &TcpServer::shutdownRequest); +} + +void CBI_Shutdown::handleCommandInternal(const QVector &) +{ + writeOk(QLatin1String("Shutting down server - bye!")); + closeConnection(); + emit shutdownRequest(); +} + +QString CBI_Shutdown::help() const +{ + return QLatin1String("SHUTDOWN - shut down the server"); +} + diff --git a/Z/src/tcpserver/cbi_shutdown.h b/Z/src/tcpserver/cbi_shutdown.h new file mode 100755 index 000000000..ed0ed2c93 --- /dev/null +++ b/Z/src/tcpserver/cbi_shutdown.h @@ -0,0 +1,25 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class TCPSERVER_EXPORT CBI_Shutdown : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Shutdown(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; + +Q_SIGNALS: + + + void shutdownRequest(); +private: +}; diff --git a/Z/src/tcpserver/commandinterface.cpp b/Z/src/tcpserver/commandinterface.cpp new file mode 100755 index 000000000..eeedc31b1 --- /dev/null +++ b/Z/src/tcpserver/commandinterface.cpp @@ -0,0 +1,329 @@ + + + +#include "commandinterface.h" +#include "workerbase.h" +#include "tcpserver.h" +#include "tcpserver_logger.h" + +#include +#include +#include + +class CommandInterface::Private +{ +public: + explicit Private(unsigned short port_, const QByteArray &command_) + : command(command_) + , port(port_) + {} + + QByteArray m_connString; + QByteArray command; + QAbstractSocket *dev = nullptr; + WorkerBase *wb = nullptr; + int writeTimeout = 1000; + unsigned short port; + bool autoWriteEOL = true; + bool bWriteError = false; + bool closeConnection = false; + + static QByteArray defaultSuccessMessage; + static QByteArray defaultErrorMessage; +}; +QByteArray CommandInterface::Private::defaultSuccessMessage("OK"); +QByteArray CommandInterface::Private::defaultErrorMessage("ERROR"); + +CommandInterface::CommandInterface(unsigned short port, const QByteArray &command) + : d(new Private(port, command)) +{} + +CommandInterface::~CommandInterface() +{ + delete d; +} + +void CommandInterface::handleCommand(const QVector &args) +{ + Q_ASSERT(d->dev); + d->bWriteError = false; + d->closeConnection = false; + d->m_connString = WorkerBase::formatForDebug(d->dev); + handleCommandInternal(args); + if (d->autoWriteEOL) + writeEOL(); + d->dev->flush(); + if (d->closeConnection) + { + + d->dev->disconnectFromHost(); + + d->dev = nullptr; + } +} + +void CommandInterface::newPlainData() +{ + Q_ASSERT(false); + TCPSERVER_ERROR("CommandInterface::newData called which should never happen!"); +} + +void CommandInterface::writeData(const char *payload) +{ + writeData(QByteArray::fromRawData(payload, strlen(payload))); +} + +void CommandInterface::writeData(const QByteArray &payload) +{ + Q_ASSERT(d->dev); + + if (!d->dev->isOpen()) + return; + + if (!payload.size()) + return; + + TCPSERVER_DEBUG("Sending \'" << WorkerBase::formatForDebug(payload).constData() + << "\' (" << payload.size() << " Bytes) to " + << d->m_connString.constData()) + + qint64 bytesToWrite = payload.size(); + qint64 bytesWritten = 0; + do + { + bytesWritten += d->dev->write(&payload.data()[bytesWritten], bytesToWrite - bytesWritten); + if (!d->dev->waitForBytesWritten(d->writeTimeout)) + { + TCPSERVER_ERROR("waitForBytesWritten returned false for connection " + << d->m_connString.constData() + << " " + << d->dev->error() + << " " + << d->dev->errorString()) + d->bWriteError = true; + return; + } + } + while (bytesToWrite != bytesWritten); +} + +void CommandInterface::writeData(const QString &payload) +{ + writeData(payload.toUtf8()); +} + +void CommandInterface::writeData(const QList &payload) +{ + QByteArray cmd; + for (QByteArray s : payload) + { + s.replace('\"', "\\\""); + if (s.contains(' ')) + s = '"' + s + '"'; + cmd += s + ' '; + } + writeData(cmd); +} + +void CommandInterface::writeData(const QStringList &payload) +{ + QList baList; + baList.reserve(payload.size()); + for (const QString &ba : payload) + baList += ba.toUtf8(); + writeData(baList); +} + +void CommandInterface::writeOk(const QString &additionalMsg) +{ + writeData(Private::defaultSuccessMessage); + if (!additionalMsg.isEmpty()) + { + writeData(" "); + writeData(additionalMsg); + } +} + +void CommandInterface::writeError(const QString &additionalMsg) +{ + writeData(Private::defaultErrorMessage); + if (!additionalMsg.isEmpty()) + { + writeData(" "); + writeData(additionalMsg); + } +} + +void CommandInterface::writeEOL() +{ + writeData("\n"); + + Q_ASSERT(d->dev); + d->dev->flush(); +} + +QByteArray CommandInterface::quote(const QByteArray &payload) +{ + static const QByteArray escapedQuote("\""); + int idx = payload.indexOf(' '); + if (idx < 0) + return payload; + QByteArray ret = payload; + return escapedQuote + ret.replace('\"', "\\\"") + escapedQuote; +} + +QAbstractSocket *CommandInterface::socket() +{ + return d->dev; +} +void CommandInterface::setSocket(QAbstractSocket *socket) +{ + d->dev = socket; +} + +WorkerBase *CommandInterface::workerBase() +{ + return d->wb; +} + +void CommandInterface::setWorkerBase(WorkerBase *wb) +{ + d->wb = wb; +} + +QByteArray CommandInterface::command() const +{ + return d->command; +} + +void CommandInterface::setWriteTimeout(int iMS) +{ + d->writeTimeout = iMS < 0 ? 1000 : iMS; +} + +void CommandInterface::setAutoWriteEOL(bool newAutoWriteEOL) +{ + d->autoWriteEOL = newAutoWriteEOL; +} + +bool CommandInterface::autoWriteEOL() const +{ + return d->autoWriteEOL; +} + +bool CommandInterface::errorOccured() const +{ + return d->bWriteError; +} + +void CommandInterface::setDefaultSuccessMessage(const QString &msg) +{ + Private::defaultSuccessMessage = msg.isEmpty() ? "OK" : msg.toUtf8(); +} + +void CommandInterface::setDefaultErrorMessage(const QString &msg) +{ + Private::defaultErrorMessage = msg.isEmpty() ? "ERROR" : msg.toUtf8(); +} + +unsigned short CommandInterface::port() const +{ + return d->port; +} + +void CommandInterface::closeConnection() +{ + d->closeConnection = true; +} + +bool CommandInterface::socketIsOpen() const +{ + return d->dev && d->dev->isOpen(); +} + +void CommandInterface::conversionError(const QByteArray &arg, const QByteArray &type) +{ + writeError(QLatin1String("Can not convert ") + QString::fromUtf8(arg) + + QLatin1String(" to ") + QString::fromUtf8(type)); +} + +bool CommandInterface::getValue(const QByteArray &arg, bool &value) +{ + bool bOk; + int intValue; + + if (arg.startsWith("0x")) + intValue = arg.mid(2).toInt(&bOk, 16); + else + intValue = arg.toInt(&bOk); + if (!bOk) + conversionError(arg, "bool"); + value = (intValue != 0); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, long &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toLong(&bOk, 16); + else + value = arg.toLong(&bOk); + if (!bOk) + conversionError(arg, "long"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, unsigned long &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toULong(&bOk, 16); + else + value = arg.toUInt(&bOk); + if (!bOk) + conversionError(arg, "unsigned long"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, int &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toInt(&bOk, 16); + else + value = arg.toInt(&bOk); + if (!bOk) + conversionError(arg, "int"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, unsigned int &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toUInt(&bOk, 16); + else + value = arg.toUInt(&bOk); + if (!bOk) + conversionError(arg, "unsigned int"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, float &value) +{ + bool bOk; + value = arg.toFloat(&bOk); + if (!bOk) + conversionError(arg, "float"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, double &value) +{ + bool bOk; + value = arg.toDouble(&bOk); + if (!bOk) + conversionError(arg, "double"); + return bOk; +} diff --git a/Z/src/tcpserver/commandinterface.h b/Z/src/tcpserver/commandinterface.h new file mode 100755 index 000000000..fd1026608 --- /dev/null +++ b/Z/src/tcpserver/commandinterface.h @@ -0,0 +1,158 @@ + + + + +#pragma once + +#include +#include +#include + +#include "tcpserver_export.h" + +class QAbstractSocket; +class QByteArray; +class WorkerBase; + + +class TCPSERVER_EXPORT CommandInterface : public QObject +{ + Q_OBJECT +public: + + + explicit CommandInterface(unsigned short port, const QByteArray &command = QByteArray()); + + + + virtual ~CommandInterface(); + + + void handleCommand(const QVector &args); + + + virtual void newPlainData(); + + + virtual QString help() const = 0; + + + QByteArray command() const; + + + + void setAutoWriteEOL(bool newAutoWriteEOL); + + + + bool autoWriteEOL() const; + + + + bool errorOccured() const; + + + + static void setDefaultSuccessMessage(const QString &msg); + + + + static void setDefaultErrorMessage(const QString &msg); + + template + static CommandInterface *factory(unsigned short port) { return new T(port); } + + + + virtual void aboutToDestroy() {} +protected: + + + virtual void handleCommandInternal(const QVector &args) = 0; + + + void setWriteTimeout(int iMS); + + + void writeData(const QByteArray &payload); + + + void writeData(const char *payload); + + + void writeData(const QString &payload); + + + void writeData(const QStringList &payload); + + + void writeData(const QList &payload); + + + void writeOk(const QString &additionalMsg = QString()); + + + void writeError(const QString &additionalMsg = QString()); + + + void writeEOL(); + + + QByteArray quote(const QByteArray &payload); + + + QAbstractSocket *socket(); + + + void setSocket(QAbstractSocket *socket); + + + WorkerBase *workerBase(); + + + void setWorkerBase(WorkerBase *wb); + + + void conversionError(const QByteArray &arg, const QByteArray &type); + + + bool getValue(const QByteArray &arg, bool &value); + + + bool getValue(const QByteArray &arg, long &value); + + + bool getValue(const QByteArray &arg, unsigned long &value); + + + bool getValue(const QByteArray &arg, int &value); + + + bool getValue(const QByteArray &arg, unsigned int &value); + + + bool getValue(const QByteArray &arg, float &value); + + + bool getValue(const QByteArray &arg, double &value); + + + + unsigned short port() const; + + + + void closeConnection(); + + + + bool socketIsOpen() const; + +private: + friend class WorkerBase; + + class Private; + + + Private *const d; +}; diff --git a/Z/src/tcpserver/tcpserver.cpp b/Z/src/tcpserver/tcpserver.cpp new file mode 100755 index 000000000..ae075b00a --- /dev/null +++ b/Z/src/tcpserver/tcpserver.cpp @@ -0,0 +1,209 @@ + + + +#include "tcpserver.h" +#include "tcpserver_logger.h" +#include "workerbase.h" + +#include +#include +#include +#include + +#include + +NGL::INGLLogger &getTcpServerLogger() +{ + static NGL::INGLLogger *tcpserver_logger_ptr = nullptr; + if (!tcpserver_logger_ptr) + tcpserver_logger_ptr = &NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("tcpserver"); + return *tcpserver_logger_ptr; +} + +typedef QHash< unsigned short, TcpServer::CommandInterfaceList > CommandFactory; +class TcpServer::Private +{ +public: + explicit Private(unsigned short port_) + : mUserData(nullptr) + , port(port_) + , bUseThreads(false) + {} + ~Private() + { + const auto copy(workers); + for (WorkerInstance *worker : copy) + { + + QThread *workerThread = worker->thread(); + if (workerThread != qApp->thread()) + { + QTimer::singleShot(0, worker, &WorkerInstance::deleteLater); + workerThread->wait(); + } + else + delete worker; + } + workers.clear(); + } + + QVector workers; + void *mUserData; + unsigned short port; + bool bUseThreads; + + static QHash s_servers; + static CommandFactory s_cbFactory; +}; +QHash TcpServer::Private::s_servers; +CommandFactory TcpServer::Private::s_cbFactory; + +TcpServer::TcpServer(unsigned short port) + : QTcpServer() + , d(new Private(port)) +{ + TCPSERVER_TRACE2("Port: " << port); +} + +TcpServer::~TcpServer() +{ + TCPSERVER_TRACE + Private::s_servers.remove(d->port); + delete d; +} + +TcpServer *TcpServer::instance(unsigned short port) +{ + if (!Private::s_servers.contains(port)) + Private::s_servers.insert(port, new TcpServer(port)); + + return Private::s_servers[ port ]; +} + +bool TcpServer::listen(const QHostAddress &address) +{ + TCPSERVER_TRACE2("address: " << address); + return QTcpServer::listen(address, d->port); +} + +void TcpServer::setUseWorkerThreads(bool bEnable) +{ + TCPSERVER_TRACE2("bEnable: " << bEnable); + d->bUseThreads = bEnable; +} + +bool TcpServer::useWorkerThreads() const +{ + return d->bUseThreads; +} + +QVector TcpServer::workers() const +{ + return d->workers; +} + +unsigned short TcpServer::getListenPort() const +{ + return d->port; +} + +bool TcpServer::registerCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)) +{ + CommandInterfaceList &factoryList = Private::s_cbFactory[port]; + if (factoryList.contains(factory)) + { + TCPSERVER_ERROR("Factory " << (void *)factory << " already registered!") + return false; + } + factoryList.append(factory); + TCPSERVER_DEBUG("Added Factory " << (void *)factory << " for port " << port) + return true; +} + +bool TcpServer::unregisterCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)) +{ + CommandInterfaceList &factoryList = Private::s_cbFactory[port]; + if (!factoryList.contains(factory)) + { + TCPSERVER_WARN("Trying to unregister factory " << (void *)factory << " for port " << port << " which is not registered!") + return false; + } + TCPSERVER_INFO("Removed Factory " << (void *)factory << " for port " << port) + factoryList.removeAll(factory); + return true; +} + +TcpServer::CommandInterfaceList TcpServer::registeredCommands(unsigned short port) +{ + return Private::s_cbFactory[port]; +} + +void TcpServer::incomingConnection(qintptr socketDescriptor) +{ + + WorkerInstance *worker = new WorkerInstance(socketDescriptor, d->port); + connect(worker, &WorkerInstance::finished, this, &TcpServer::workerFinished); + d->workers += worker; + + if (d->bUseThreads) + { + QThread *workerThread = new QThread(this); + + connect(workerThread, &QThread::started, worker, &WorkerInstance::doWork); + connect(workerThread, &QThread::finished, worker, &WorkerInstance::quit); + worker->moveToThread(workerThread); + + workerThread->start(); + + + connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); + TCPSERVER_DEBUG("Created new WorkerThread " << worker) + } + else + { + QTimer::singleShot(0, worker, &WorkerInstance::doWork); + TCPSERVER_DEBUG("Created new WorkerInstance " << worker) + } +} + +void TcpServer::workerFinished() +{ + WorkerInstance *wi = qobject_cast(sender()); + if (wi) + { + if (!d->workers.removeAll(wi)) + TCPSERVER_WARN("Got a signal that a worker exited, but could not find it in our list!") + wi->deleteLater(); + } + else + { + TCPSERVER_WARN("Got a signal that a worker exited, but it's neither a WorkerInstance nor WorkerThread!") + } +} + +void TcpServer::shutdownRequest() +{ + emit aboutToQuit(d->port); + for (WorkerBase *worker : qAsConst(d->workers)) + { + WorkerInstance *wi = dynamic_cast(worker); + if (wi) + { + wi->quit(); + while (!wi->isFinished()) + QCoreApplication::processEvents(); + } + } + close(); + deleteLater(); +} + +void TcpServer::setUserData(void *userData) +{ + d->mUserData = userData; +} + +void *TcpServer::userData() const +{ + return d->mUserData; +} diff --git a/Z/src/tcpserver/tcpserver.h b/Z/src/tcpserver/tcpserver.h new file mode 100755 index 000000000..3b3bd1381 --- /dev/null +++ b/Z/src/tcpserver/tcpserver.h @@ -0,0 +1,96 @@ + + + + +#pragma once + +#include + +#include "tcpserver_export.h" + +class WorkerInstance; +class CommandInterface; + + + +class TCPSERVER_EXPORT TcpServer : public QTcpServer +{ + Q_OBJECT +public: + typedef QVector CommandInterfaceList; +public: + + + virtual ~TcpServer(); + + + static TcpServer *instance(unsigned short port); + + + + bool listen(const QHostAddress &address = QHostAddress::Any); + + + + void setUseWorkerThreads(bool bEnable); + + + + bool useWorkerThreads() const; + + + + QVector workers() const; + + + + unsigned short getListenPort() const; + + + + static bool registerCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)); + + + + static bool unregisterCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)); + + + + static CommandInterfaceList registeredCommands(unsigned short port); + + + + void setUserData(void *userData); + + + + void *userData() const; + +Q_SIGNALS: + + + void aboutToQuit(unsigned short port); + +public Q_SLOTS: + + + void shutdownRequest(); + + + void workerFinished(); + +protected: + void incomingConnection(qintptr socketDescriptor); + +private: + class Private; + + + Private *const d; + + explicit TcpServer(unsigned short port); + + + + bool listen(const QHostAddress &address, quint16 port); +}; diff --git a/Z/src/tcpserver/tcpserver_export.h b/Z/src/tcpserver/tcpserver_export.h new file mode 100755 index 000000000..ae0da04c9 --- /dev/null +++ b/Z/src/tcpserver/tcpserver_export.h @@ -0,0 +1,27 @@ + + +#ifndef TCPSERVER_EXPORT_H +#define TCPSERVER_EXPORT_H + +#include + +#define TCPSERVER_VERSION_MAJ 0 +#define TCPSERVER_VERSION_MIN 0 +#define TCPSERVER_VERSION_REL 3 +#define TCPSERVER_VERSION (((TCPSERVER_VERSION_MAJ) << 16) | ((TCPSERVER_VERSION_MIN) << 8) | (TCPSERVER_VERSION_REL)) + +#ifndef TCPSERVER_STATIC +# ifdef BUILD_STATIC_LIBRARIES +# define TCPSERVER_EXPORT +# else +# ifdef MAKE_TCPSERVER_LIB +# define TCPSERVER_EXPORT Q_DECL_EXPORT +# else +# define TCPSERVER_EXPORT Q_DECL_IMPORT +# endif +# endif +#else +# define TCPSERVER_EXPORT __attribute__((visibility("default"))) +#endif + +#endif diff --git a/Z/src/tcpserver/tcpserver_logger.h b/Z/src/tcpserver/tcpserver_logger.h new file mode 100755 index 000000000..492c8578d --- /dev/null +++ b/Z/src/tcpserver/tcpserver_logger.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#ifdef Q_CC_GNU +#define TCPSERVER_TRACE_FUNCTION __PRETTY_FUNCTION__ +#else +#define TCPSERVER_TRACE_FUNCTION __FUNCTION__ +#endif + +#include + +NGL::INGLLogger &getTcpServerLogger(); + +#ifdef TCPSERVER_ENABLE_TRACE +#define TCPSERVER_TRACE { TRACE_LOG(getTcpServerLogger()) << TCPSERVER_TRACE_FUNCTION; } +#define TCPSERVER_TRACE2(x) { TRACE_LOG(getTcpServerLogger()) << TCPSERVER_TRACE_FUNCTION << x; } +#else +#define TCPSERVER_TRACE +#define TCPSERVER_TRACE2(x) +#endif +#define TCPSERVER_DEBUG(y) { DEBUG_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_INFO(y) { INFO_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_WARN(y) { WARNING_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_ERROR(y) { ERROR_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_FATAL(y) { FATAL_LOG (getTcpServerLogger()) << y; } diff --git a/Z/src/tcpserver/tcpserver_test.cpp b/Z/src/tcpserver/tcpserver_test.cpp new file mode 100755 index 000000000..b3e649e65 --- /dev/null +++ b/Z/src/tcpserver/tcpserver_test.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +#include "tcpserver.h" +#include "cbi_help.h" +#include "cbi_pingpong.h" +#include "cbi_quit.h" +#include "cbi_recvfile.h" +#include "cbi_sendfile.h" +#include "cbi_shutdown.h" +#include "workerbase.h" + +int main(int argc, char **argv) +{ + NGL::NGLLoggerBootstrap::createNGLRootLogger("tcpserver_test.props", false); + + QCoreApplication app(argc, argv); + QSettings settings(QLatin1String("./settings.ini"), QSettings::IniFormat); + unsigned int port = settings.value(QLatin1String("port"), 4711).toInt(); + + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + + TcpServer *tcpServer = TcpServer::instance(port); + tcpServer->setUseWorkerThreads(true); + + if (!tcpServer->listen(QHostAddress::LocalHost)) + { + qFatal("Error listening on port %d, error: %d", port, tcpServer->serverError()); + delete tcpServer; + return 1; + } + QObject::connect(tcpServer, &TcpServer::destroyed, &app, &QCoreApplication::quit); + + int ret = app.exec(); + return ret; +} diff --git a/Z/src/tcpserver/workerbase.cpp b/Z/src/tcpserver/workerbase.cpp new file mode 100755 index 000000000..83eab0270 --- /dev/null +++ b/Z/src/tcpserver/workerbase.cpp @@ -0,0 +1,304 @@ + + + +#include "workerbase.h" + +#include "commandinterface.h" +#include "tcpserver.h" +#include "tcpserver_logger.h" + +#include +#include +#include + +#include +#include +#include + +#include + +WorkerBase::WorkerBase(qintptr sd, unsigned short port) + : m_socketDescriptor(sd) + , m_connection(nullptr) + , m_port(port) + , m_bRedirectIncomingData(false) + , m_bRedirectDataHandler(nullptr) +{} + +QAbstractSocket *WorkerBase::connection() +{ + return m_connection; +} + +const QAbstractSocket *WorkerBase::connection() const +{ + return m_connection; +} + +void WorkerBase::newDataInternal() +{ + + if (m_bRedirectIncomingData) + { + if (m_bRedirectDataHandler) + m_bRedirectDataHandler->newPlainData(); + return; + } + + if (!m_connection || !m_connection->isOpen()) + return; + + while (m_connection && m_connection->canReadLine()) + { + QByteArray ba(2048, '\0'); + bool bGotEOL = false; + int iOffset = 0; + do + { + qint64 length = m_connection->readLine(ba.data() + iOffset, ba.size()); + if (length < 0) + { + TCPSERVER_ERROR("Error reading data from " << m_connString.constData() + << qPrintable(m_connection->errorString())) + return; + } + bGotEOL = ba.contains('\n'); + if (bGotEOL) + { + + ba.resize(iOffset + length); + } + else + { + + iOffset = ba.size(); + ba.resize(ba.size() * 2); + + memset(ba.data() + iOffset, 0, ba.size() - iOffset); + } + } + while (!bGotEOL); + + + while (ba.endsWith('\r') || ba.endsWith('\n')) + { + ba.data() [ba.size() - 1] = '\0'; + ba.resize(ba.size() - 1); + } + + int idx = ba.indexOf(' '); + if (idx == -1) + idx = ba.size(); + + QByteArray command = ba.left(idx); + if (command.isEmpty()) + { + TCPSERVER_DEBUG("Got empty command from connection " << m_connString.constData()) + continue; + } + + CommandMap::ConstIterator it = m_registeredCommands.constFind(command.toLower()); + if (it == m_registeredCommands.constEnd()) + { + TCPSERVER_WARN("Got unknown command " << formatForDebug(command).constData() + << " from connection " + << m_connString.constData()) + m_connection->write("UNKNOWN COMMAND "); + m_connection->write(command); + m_connection->write("\n"); + if (!m_connection->waitForBytesWritten(1000)) + { + TCPSERVER_WARN("waitForBytesWritten returned false for connection " + << m_connString.constData() + << " " + << m_connection->error() + << " " + << m_connection->errorString()) + } + } + else + { + TCPSERVER_DEBUG("Got command " << formatForDebug(command).constData() + << " from connection " + << m_connString.constData()) + + CommandInterface *interface = *it; + const QVector args = NGL::parseFromTelnet(ba, idx + 1); + interface->handleCommand(args); + if (interface->errorOccured()) + { + TCPSERVER_ERROR("Write error occured on connection " << m_connString.constData()) + } + } + + if (m_bRedirectIncomingData && m_connection && m_connection->bytesAvailable()) + { + if (m_bRedirectDataHandler) + m_bRedirectDataHandler->newPlainData(); + return; + } + } +} + +void WorkerBase::redirectDataHandling(bool bDoRedirect, CommandInterface *newDataHandler) +{ + m_bRedirectIncomingData = bDoRedirect; + m_bRedirectDataHandler = newDataHandler; + + if (!bDoRedirect) + newDataInternal(); +} + +QByteArray WorkerBase::formatForDebug(const QByteArray &data) +{ + const int size = data.size(); + QByteArray ret; + ret.reserve(size); + for (int i = 0; i < size; ++i) + { + const unsigned char c = data[i]; + if (c < ' ' || c >= 0x7f) + ret += "\\x" + QByteArray::number(c, 16); + else + ret += c; + if (i > 31) + { + ret += "..."; + break; + } + } + return ret; +} + +WorkerBase::CommandMap WorkerBase::getCommands() const +{ + return m_registeredCommands; +} + +QByteArray WorkerBase::formatForDebug(const QAbstractSocket *dev) +{ + const QAbstractSocket *socket = qobject_cast(dev); + if (socket) + return socket->peerAddress().toString().toUtf8() + ":" + QByteArray::number(socket->peerPort()); + try + { + return typeid(*dev).name(); + } + catch (std::bad_typeid &e) + { + TCPSERVER_ERROR("TcpSocket null? - " << e.what()) + } + return ""; +} + +int WorkerBase::initCommands(unsigned short port) +{ + const TcpServer::CommandInterfaceList cbList = TcpServer::registeredCommands(port); + TcpServer::CommandInterfaceList::ConstIterator it = cbList.begin(); + TcpServer::CommandInterfaceList::ConstIterator end = cbList.end(); + for (; it != end; ++it) + { + CommandInterface *(*factory)(unsigned short) = *it; + CommandInterface *cbi = factory(port); + cbi->setWorkerBase(this); + cbi->setSocket(m_connection); + m_registeredCommands.insert(cbi->command().toLower(), cbi); + } + return m_registeredCommands.count(); +} + +void WorkerBase::cleanupCommands() +{ + CommandMap::ConstIterator it = m_registeredCommands.constBegin(); + CommandMap::ConstIterator end = m_registeredCommands.constEnd(); + for (; it != end; ++it) + { + if (*it) + { + (*it)->aboutToDestroy(); + (*it)->deleteLater(); + } + } + m_registeredCommands.clear(); +} + + + +WorkerInstance::WorkerInstance(qintptr sd, unsigned short port, QObject *parent) + : QObject(parent) + , WorkerBase(sd, port) + , m_bFinished(false) +{} + +WorkerInstance::~WorkerInstance() +{ + if (m_connection && m_connection->state() != QAbstractSocket::UnconnectedState) + { + m_connection->disconnectFromHost(); + if (m_connection) + m_connection->waitForDisconnected(); + } + cleanupCommands(); + + delete m_connection; + m_connection = nullptr; +} + +void WorkerInstance::doWork() +{ + m_connection = new QTcpSocket(this); + initCommands(m_port); + if (!m_connection->setSocketDescriptor(m_socketDescriptor)) + { + m_connString = formatForDebug(m_connection); + TCPSERVER_ERROR("Connection to " << m_connString.constData() + << " failed - Aborting (" + << m_connection->error() << ")") + return; + } + m_connString = formatForDebug(m_connection); + TCPSERVER_DEBUG("New incoming connection from " + << m_connString.constData() + << " to " << m_connection->localAddress().toString().toUtf8().constData() + << ":" << m_connection->localPort()); + connect(m_connection.data(), &QTcpSocket::readyRead, this, &WorkerInstance::newData); + connect(m_connection.data(), &QTcpSocket::disconnected, this, &WorkerInstance::connectionDisconnected); +} + +void WorkerInstance::newData() +{ + WorkerBase::newDataInternal(); +} + +void WorkerInstance::connectionDisconnected() +{ + TCPSERVER_DEBUG(m_connString.constData() << " closed - exiting instance " << this); + if (m_connection) + m_connection->deleteLater(); + m_connection = nullptr; + m_bFinished = true; + + QThread *workerThread = QThread::currentThread(); + if (workerThread != qApp->thread()) + { + workerThread->disconnect(this); + workerThread->quit(); + } + emit finished(); +} + +bool WorkerInstance::isRunning() const +{ + return m_connection && m_connection->isOpen(); +} + +bool WorkerInstance::isFinished() const +{ + return m_bFinished; +} + +void WorkerInstance::quit() +{ + if (m_connection) + m_connection->close(); +} diff --git a/Z/src/tcpserver/workerbase.h b/Z/src/tcpserver/workerbase.h new file mode 100755 index 000000000..f42806f2c --- /dev/null +++ b/Z/src/tcpserver/workerbase.h @@ -0,0 +1,127 @@ + + + +#pragma once + +#include +#include +#include + +#include "tcpserver_export.h" + +class QAbstractSocket; +class CommandInterface; + + + +class TCPSERVER_EXPORT WorkerBase +{ +public: + typedef QMap< QByteArray, CommandInterface *> CommandMap; +public: + + + WorkerBase(qintptr sd, unsigned short port); + + + virtual ~WorkerBase() = default; + + + QAbstractSocket *connection(); + + + + const QAbstractSocket *connection() const; + + + + void redirectDataHandling(bool bDoRedirect, CommandInterface *newDataHandler = nullptr); + + + + static QByteArray formatForDebug(const QByteArray &data); + + + + static QByteArray formatForDebug(const QAbstractSocket *dev); + + + + CommandMap getCommands() const; + +protected: + + + void newDataInternal(); + + + int initCommands(unsigned short port); + + + + void cleanupCommands(); + + + + qintptr m_socketDescriptor; + + + QPointer m_connection; + + + unsigned short m_port; + + + QByteArray m_connString; + + + bool m_bRedirectIncomingData; + + + CommandInterface *m_bRedirectDataHandler; + + + + CommandMap m_registeredCommands; +}; + + + +class WorkerInstance final : public QObject, public WorkerBase +{ + Q_OBJECT +public: + WorkerInstance(qintptr sd, unsigned short port, QObject *parent = nullptr); + virtual ~WorkerInstance(); + + + + bool isRunning() const; + + + bool isFinished() const; + +public Q_SLOTS: + + + void quit(); + + + + void doWork(); + +protected Q_SLOTS: + + + void newData(); + + + void connectionDisconnected(); + +Q_SIGNALS: + void finished(); + +private: + bool m_bFinished; +}; + diff --git a/cmake/DoxygenMacros.cmake b/cmake/DoxygenMacros.cmake new file mode 100755 index 000000000..6fdf455c8 --- /dev/null +++ b/cmake/DoxygenMacros.cmake @@ -0,0 +1,22 @@ + + + + + + + + + + +FIND_PROGRAM(DOXYGEN_EXECUTABLE doxygen) + +MACRO(ADD_DOXYGEN_TARGET target input output infile outdir) + IF(DOXYGEN_EXECUTABLE-NOTFOUND) + MESSAGE(STATUS "Doxygen executable not found - can't create doxygen documentation") + ELSE(DOXYGEN_EXECUTABLE-NOTFOUND) + CONFIGURE_FILE(${input} ${output}) + ADD_CUSTOM_TARGET(doxygen_${target} doxygen ${output} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${infile} ${outdir} + ) + ENDIF(DOXYGEN_EXECUTABLE-NOTFOUND) +ENDMACRO(ADD_DOXYGEN_TARGET target) diff --git a/cmake/FindArcGIS.cmake b/cmake/FindArcGIS.cmake new file mode 100755 index 000000000..5f04b4605 --- /dev/null +++ b/cmake/FindArcGIS.cmake @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + +IF(ARCGIS_INCLUDE_DIR AND ARCGIS_LIBRARY) + SET(ARCGIS_FOUND TRUE) +ELSE() + + INCLUDE(FindLibraryWithDebug) + INCLUDE(FindPackageHandleStandardArgs) + + SET(QT_MIN_VERSION 5.4.0) + FIND_PACKAGE(Qt5 COMPONENTS Core Gui Location Network Sensors REQUIRED) + + SET(_arcgis_include_hint "/usr/include") + SET(_arcgis_library_hint "/usr/lib64") + + SET(_arcgis_lib_dir $ENV{ARCGIS_LIB_DIR}) + SET(_arcgis_inc_dir $ENV{ARCGIS_INC_DIR}) + IF (NOT ${_arcgis_lib_dir} STREQUAL "") + SET(_arcgis_library_hint "${_arcgis_lib_dir}") + ENDIF() + IF (NOT ${_arcgis_inc_dir} STREQUAL "") + SET(_arcgis_include_hint "${_arcgis_inc_dir}") + ENDIF() + IF(WIN32) + GET_FILENAME_COMPONENT(_arcgis_root_path "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\ESRI\\ArcGISRuntimeQt100.0.0;InstallDir]" ABSOLUTE) + IF(_arcgis_root_path) + SET(_arcgis_include_hint "${_arcgis_root_path}/sdk/windows/include/") + SET(_arcgis_library_hint "${_arcgis_root_path}/sdk/windows/x86/lib/") + ELSE() + SET(_root "$ENV{KDEROOT}") + FILE(TO_CMAKE_PATH "${_root}" _root) + IF(NOT EXISTS "${_root}" OR NOT IS_DIRECTORY "${_root}") + SET(_root $ENV{WORKSPACE}) + FILE(TO_CMAKE_PATH "${_root}" _root) + ENDIF() + IF(NOT EXISTS "${_root}" OR NOT IS_DIRECTORY "${_root}") + SET(_root ${EXTERNAL_LIBRARY_DIR}) + FILE(TO_CMAKE_PATH "${_root}" _root) + ENDIF() + SET(_arcgis_include_hint "${_root}/include/") + SET(_arcgis_library_hint "${_root}/lib/") + ENDIF() + ENDIF() + + FIND_PATH(ARCGIS_INCLUDE_DIR arcgis/ArcGISQt_global.h HINTS ${_arcgis_include_hint}) + FIND_LIBRARY_WITH_DEBUG(ARCGIS_LIBRARY WIN32_DEBUG_POSTFIX d NAMES EsriRuntimeQt HINTS ${_arcgis_library_hint}) + + FIND_LIBRARY_WITH_DEBUG(ARCGIS_COMMON_LIBRARY WIN32_DEBUG_POSTFIX d NAMES EsriCommonQt HINTS ${_arcgis_library_hint}) + IF (UNIX) + + FIND_LIBRARY_WITH_DEBUG(ARCGIS_CPP_LIBRARY WIN32_DEBUG_POSTFIX d NAMES runtimecore HINTS ${_arcgis_library_hint}) + ENDIF() + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(ArcGIS DEFAULT_MSG ARCGIS_LIBRARY ARCGIS_INCLUDE_DIR) + + MARK_AS_ADVANCED(ARCGIS_INCLUDE_DIR ARCGIS_LIBRARY) +ENDIF() + +IF(NOT TARGET ArcGIS::ArcGIS) + ADD_LIBRARY(ArcGIS::ArcGIS UNKNOWN IMPORTED) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${ARCGIS_INCLUDE_DIR}") + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${ARCGIS_INCLUDE_DIR}") + + IF(ARCGIS_LIBRARY_RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY IMPORTED_LOCATION_RELEASE "${ARCGIS_LIBRARY_RELEASE}") + ENDIF() + IF(ARCGIS_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY IMPORTED_LOCATION_DEBUG "${ARCGIS_LIBRARY_DEBUG}") + ENDIF() + IF(NOT ARCGIS_LIBRARY_RELEASE AND NOT ARCGIS_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY IMPORTED_LOCATION "${ARCGIS_LIBRARY}") + ENDIF() + + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $ + $ + $ + $ + ) + + IF (UNIX) + IF(ARCGIS_COMMON_LIBRARY_RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_COMMON_LIBRARY_RELEASE}">) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_CPP_LIBRARY_RELEASE}">) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_COMMON_LIBRARY_DEBUG}">) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_CPP_LIBRARY_DEBUG}">) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY AND NOT ARCGIS_COMMON_LIBRARY_RELEASE AND NOT ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${ARCGIS_COMMON_LIBRARY}" "${ARCGIS_CPP_LIBRARY}") + ENDIF() + ELSE() + IF(ARCGIS_COMMON_LIBRARY_RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:${ARCGIS_COMMON_LIBRARY_RELEASE}>) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:${ARCGIS_COMMON_LIBRARY_RELEASE}>) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:${ARCGIS_COMMON_LIBRARY_DEBUG}>) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY AND NOT ARCGIS_COMMON_LIBRARY_RELEASE AND NOT ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${ARCGIS_COMMON_LIBRARY}") + ENDIF() + ENDIF() +ENDIF() diff --git a/cmake/FindBgViewer.cmake b/cmake/FindBgViewer.cmake new file mode 100755 index 000000000..624930cd9 --- /dev/null +++ b/cmake/FindBgViewer.cmake @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + +INCLUDE(FindPackageHandleStandardArgs) +INCLUDE(FindLibraryWithDebug) + +FIND_LIBRARY_WITH_DEBUG(BGVIEWER_DTENTITY_LIBRARY WIN32_DEBUG_POSTFIX d dtEntity) +FIND_LIBRARY_WITH_DEBUG(BGVIEWER_DTENTITYOSG_LIBRARY WIN32_DEBUG_POSTFIX d dtEntityOSG) +FIND_PATH(BGVIEWER_INCLUDE_DIR dtEntity/export.h) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(BgViewer DEFAULT_MSG + BGVIEWER_DTENTITY_LIBRARY + BGVIEWER_DTENTITYOSG_LIBRARY + BGVIEWER_INCLUDE_DIR) +SET(BGVIEWER_LIBRARIES ${BGVIEWER_DTENTITYOSG_LIBRARY} + ${BGVIEWER_DTENTITY_LIBRARY}) diff --git a/cmake/FindBotan2.cmake b/cmake/FindBotan2.cmake new file mode 100755 index 000000000..684546bd0 --- /dev/null +++ b/cmake/FindBotan2.cmake @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + +include(FindPkgConfig) + +if(NOT BOTAN_FOUND) + pkg_check_modules(Botan botan-2) +endif() + +if(NOT BOTAN_FOUND) + find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h + PATH_SUFFIXES botan-2 + DOC "The botan include directory") + + find_library(BOTAN_LIBRARIES NAMES botan botan-2 + DOC "The botan library") + + + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Botan REQUIRED_VARS BOTAN_LIBRARIES BOTAN_INCLUDE_DIRS) + + if(BOTAN_FOUND) + set(BOTAN_LIBRARY ${BOTAN_LIBRARIES} CACHE INTERNAL "") + set(BOTAN_INCLUDE_DIR ${BOTAN_INCLUDE_DIRS} CACHE INTERNAL "") + set(BOTAN_FOUND ${BOTAN_FOUND} CACHE INTERNAL "") + endif() +endif() + +mark_as_advanced(BOTAN_INCLUDE_DIRS BOTAN_LIBRARIES) diff --git a/cmake/FindKDChart.cmake b/cmake/FindKDChart.cmake new file mode 100755 index 000000000..f4a434bb3 --- /dev/null +++ b/cmake/FindKDChart.cmake @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + +IF(KDCHART_INCLUDE_DIRS AND KDCHART_LIBRARY) + SET(KDCHART_FOUND TRUE) +ELSE() + + FIND_PATH(KDCHART_INCLUDE_DIRS KDChart/kdchart_export.h) + FIND_LIBRARY(KDCHART_LIBRARY NAMES kdchart) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(KDChart DEFAULT_MSG KDCHART_LIBRARY KDCHART_INCLUDE_DIRS) + + MARK_AS_ADVANCED(KDCHART_INCLUDE_DIRS KDCHART_LIBRARY) +ENDIF() + +IF(NOT TARGET KDChart::KDChart) + ADD_LIBRARY(KDChart::KDChart UNKNOWN IMPORTED) + SET_PROPERTY(TARGET KDChart::KDChart PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${KDCHART_INCLUDE_DIRS}") + SET_PROPERTY(TARGET KDChart::KDChart PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${KDCHART_INCLUDE_DIRS}") + SET_PROPERTY(TARGET KDChart::KDChart PROPERTY IMPORTED_LOCATION "${KDCHART_LIBRARY}") +ENDIF() diff --git a/cmake/FindKDReports.cmake b/cmake/FindKDReports.cmake new file mode 100755 index 000000000..42c58a9f3 --- /dev/null +++ b/cmake/FindKDReports.cmake @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + +FIND_PACKAGE(Qt5 COMPONENTS Core Gui PrintSupport Sql Svg Widgets Xml REQUIRED) +IF(KDREPORTS_INCLUDE_DIR AND KDREPORTS_KDREPORTS_INCLUDE_DIR AND KDREPORTS_LIBRARY) + SET(KDREPORTS_FOUND TRUE) +ELSE() + + FIND_PATH(KDREPORTS_INCLUDE_DIR KDReports/KDReports.h) + FIND_PATH(KDREPORTS_KDREPORTS_INCLUDE_DIR KDReports.h PATH_SUFFIXES KDReports) + FIND_LIBRARY(KDREPORTS_LIBRARY NAMES kdreports) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(KDReports DEFAULT_MSG + KDREPORTS_LIBRARY + KDREPORTS_INCLUDE_DIR + KDREPORTS_KDREPORTS_INCLUDE_DIR + ) + + MARK_AS_ADVANCED(KDREPORTS_INCLUDE_DIR KDREPORTS_LIBRARY) + MARK_AS_ADVANCED(KDREPORTS_KDREPORTS_INCLUDE_DIR KDREPORTS_LIBRARY) +ENDIF() + +IF(NOT TARGET KDReports::KDReports) + ADD_LIBRARY(KDReports::KDReports UNKNOWN IMPORTED) + SET_PROPERTY(TARGET KDReports::KDReports PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${KDREPORTS_INCLUDE_DIR}" "${KDREPORTS_KDREPORTS_INCLUDE_DIR}") + SET_PROPERTY(TARGET KDReports::KDReports PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${KDREPORTS_INCLUDE_DIR}" "${KDREPORTS_KDREPORTS_INCLUDE_DIR}") + SET_PROPERTY(TARGET KDReports::KDReports PROPERTY IMPORTED_LOCATION "${KDREPORTS_LIBRARY}") + SET_PROPERTY(TARGET KDReports::KDReports APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qt5::Core Qt5::Gui Qt5::PrintSupport Qt5::Widgets) +ENDIF() diff --git a/cmake/FindLibraryWithDebug.cmake b/cmake/FindLibraryWithDebug.cmake new file mode 100755 index 000000000..90101b0a2 --- /dev/null +++ b/cmake/FindLibraryWithDebug.cmake @@ -0,0 +1,113 @@ + + + + + + + + + + + +MACRO(FIND_LIBRARY_WITH_DEBUG var_name win32_dbg_postfix_name dgb_postfix libname) + + IF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") + + + FIND_LIBRARY(${var_name} + ${win32_dbg_postfix_name} + ${dgb_postfix} + ${libname} + ${ARGN} + ) + + ELSE() + + IF(NOT WIN32) + + + FIND_LIBRARY(${var_name} ${libname} ${ARGN}) + + ELSE() + + + SET(args ${ARGN}) + SET(newargs "") + SET(libnames_release "") + SET(libnames_debug "") + + IF("${libname}" STREQUAL "NAMES") + SET(append_rest 0) + LIST(LENGTH args listCount) + LIST(APPEND args " ") + + FOREACH(i RANGE ${listCount}) + LIST(GET args ${i} val) + + IF(append_rest) + LIST(APPEND newargs ${val}) + ELSE() + IF(${val} STREQUAL "PATHS" OR ${val} STREQUAL "HINTS") + LIST(APPEND newargs ${val}) + SET(append_rest 1) + ELSE() + LIST(APPEND libnames_release "${val}") + LIST(APPEND libnames_debug "${val}${dgb_postfix}") + ENDIF() + ENDIF() + + ENDFOREACH() + + ELSE() + + + LIST(APPEND libnames_release "${libname}") + LIST(APPEND libnames_debug "${libname}${dgb_postfix}") + + SET(newargs ${args}) + + ENDIF() + + + FIND_LIBRARY(${var_name}_RELEASE + NAMES ${libnames_release} + ${newargs} + ) + + + FIND_LIBRARY(${var_name}_DEBUG + NAMES ${libnames_debug} + ${newargs} + ) + + IF(${var_name}_RELEASE AND ${var_name}_DEBUG) + + + SET(${var_name} optimized ${${var_name}_RELEASE} + debug ${${var_name}_DEBUG}) + + ELSE() + + IF(${var_name}_RELEASE) + + + SET(${var_name} ${${var_name}_RELEASE}) + + ELSE() + + + SET(${var_name} ${${var_name}_DEBUG}) + + ENDIF() + + ENDIF() + + MARK_AS_ADVANCED(${var_name}_RELEASE) + MARK_AS_ADVANCED(${var_name}_DEBUG) + + ENDIF() + + ENDIF() + +ENDMACRO() + diff --git a/cmake/FindNGS.cmake b/cmake/FindNGS.cmake new file mode 100755 index 000000000..4838a511e --- /dev/null +++ b/cmake/FindNGS.cmake @@ -0,0 +1,134 @@ + + + + +IF(NGS_INCLUDE_DIRS AND NGS_LIBRARIES) + SET(NGS_FOUND TRUE) +ELSE() + + SET(FOM_NAME "RPRFOM20d17E") + IF("$ENV{NGS_ROOT}" STREQUAL "") + SET(NGS_ROOT "/opt/NGS/NGSPublic") + MESSAGE(STATUS "NGS_ROOT env var not set - using ${NGS_ROOT}") + ELSE() + SET(NGS_ROOT "$ENV{NGS_ROOT}") + ENDIF() + + FIND_PROGRAM(NGS_FOMBUILD fombuild + PATHS ${NGS_ROOT}/exe + ) + FIND_PATH(NGS_INCLUDE_DIR NGSUtils/SimTime.h + PATHS ${NGS_ROOT}/include + ) + FIND_PATH(NGS_SM_INCLUDE_DIR ISystem.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES SimulationManager + ) + FIND_PATH(NGS_FC_INCLUDE_DIR IRTIAmbassador.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES RTIFacadeAPI + ) + FIND_PATH(NGS_GE_INCLUDE_DIR SimulatedWorldAPI.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES SWGeneral + ) + FIND_PATH(NGS_UT_INCLUDE_DIR NGSConfig.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES NGSUtils + ) + FIND_PATH(NGS_PF_INCLUDE_DIR configureBool.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES NGSPlatformConfigure + ) + + FIND_PATH(NGS_FOM_INCLUDE_DIR WorldLocationStruct.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES sw${FOM_NAME}/rpr + PATH_SUFFIXES sw${FOM_NAME}/rpr2 + ) + + FIND_LIBRARY(NGS_LIBRARY NGS + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(NGS_LIBRARY_SWGENERAL SWGENERAL + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(NGS_LIBRARY_UTILS NGSUtils + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(FOM_LIBRARY SW${FOM_NAME} + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(NGS_LIBRARY_CORBA CorbaNotify + PATHS ${NGS_ROOT}/lib/CorbaNotifyCdr + ) + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(NGS DEFAULT_MSG NGS_LIBRARY + NGS_LIBRARY_SWGENERAL + NGS_LIBRARY_UTILS + NGS_LIBRARY_CORBA + FOM_LIBRARY + NGS_SM_INCLUDE_DIR + NGS_FC_INCLUDE_DIR + NGS_GE_INCLUDE_DIR + NGS_UT_INCLUDE_DIR + ) + SET(NGS_INCLUDE_DIRS + ${NGS_INCLUDE_DIR} + ${NGS_SM_INCLUDE_DIR} + ${NGS_FC_INCLUDE_DIR} + ${NGS_GE_INCLUDE_DIR} + ${NGS_UT_INCLUDE_DIR} + ${NGS_PF_INCLUDE_DIR} + ${NGS_FOM_INCLUDE_DIR} + CACHE STRING "All ngs include dirs" FORCE + ) + SET(NGS_LIBRARIES + ${NGS_LIBRARY} + ${NGS_LIBRARY_SWGENERAL} + ${NGS_LIBRARY_UTILS} + ${NGS_LIBRARY_CORBA} + ${FOM_LIBRARY} + CACHE STRING "All ngs libraries" FORCE + ) + MARK_AS_ADVANCED(NGS_INCLUDE_DIR NGS_LIBRARY FOM_LIBRARY) +ENDIF() + +SET(NGS_IS_GUEZ OFF) +SET(NGS_IS_AHTC OFF) +IF (NGS_FOUND) + FIND_PATH(NGS_GUEZ_INCLUDE_DIR TacticalStatusStruct.h + PATHS ${NGS_FOM_INCLUDE_DIR}) + FIND_PATH(NGS_AHTC_INCLUDE_DIR LongBowApacheObjClass.h + PATHS ${NGS_FOM_INCLUDE_DIR}) + IF (NGS_GUEZ_INCLUDE_DIR AND EXISTS "${NGS_GUEZ_INCLUDE_DIR}/TacticalStatusStruct.h") + SET(NGS_IS_GUEZ ON) + MESSAGE(STATUS "NGS - GUEZ version (${NGS_GUEZ_INCLUDE_DIR})") + ELSE() + SET(NGS_IS_GUEZ OFF) + ENDIF() + IF (NGS_AHTC_INCLUDE_DIR AND EXISTS "${NGS_AHTC_INCLUDE_DIR}/LongBowApacheObjClass.h") + SET(NGS_IS_AHTC ON) + MESSAGE(STATUS "NGS - AHTC version (${NGS_AHTC_INCLUDE_DIR})") + ELSE() + SET(NGS_IS_AHTC OFF) + ENDIF() +ENDIF() + +IF(NOT TARGET NGS::NGS) + ADD_LIBRARY(NGS::NGS UNKNOWN IMPORTED) + SET_PROPERTY(TARGET NGS::NGS PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${NGS_INCLUDE_DIRS}) + SET_PROPERTY(TARGET NGS::NGS PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES ${NGS_INCLUDE_DIRS}) + SET_PROPERTY(TARGET NGS::NGS PROPERTY IMPORTED_LOCATION "${NGS_LIBRARY}") + + SET_PROPERTY(TARGET NGS::NGS APPEND PROPERTY INTERFACE_LINK_LIBRARIES + "${NGS_LIBRARY_SWGENERAL}" + "${NGS_LIBRARY_UTILS}" + "${NGS_LIBRARY_CORBA}" + "${FOM_LIBRARY}" + ) +ENDIF() diff --git a/cmake/FindPopplerQt5.cmake b/cmake/FindPopplerQt5.cmake new file mode 100755 index 000000000..bec65c4df --- /dev/null +++ b/cmake/FindPopplerQt5.cmake @@ -0,0 +1,61 @@ + + + + + + + + + + + + + +if(POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_LIBRARY) + + + set(POPPLER_QT5_FOUND TRUE) + +else(POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_LIBRARY) + +set(_poppler_version_bad FALSE) + +if(NOT WIN32) + + + include(FindPkgConfig) + pkg_check_modules(_pc_poppler poppler-qt5) + if(_pc_poppler_FOUND) + if(NOT "${_pc_poppler_VERSION}" VERSION_GREATER 0.24.0) + set(_poppler_version_bad TRUE) + endif(NOT "${_pc_poppler_VERSION}" VERSION_GREATER 0.24.0) + endif(_pc_poppler_FOUND) +endif(NOT WIN32) + +if(NOT _poppler_version_bad) + set(POPPLER_QT5_FOUND FALSE) + + find_library(POPPLER_QT5_LIBRARY poppler-qt5 + HINTS ${_pc_poppler_LIBRARY_DIRS} + ) + + find_path(POPPLER_QT5_INCLUDE_DIR poppler-qt5.h + HINTS ${_pc_poppler_INCLUDE_DIRS} + PATH_SUFFIXES poppler/qt5 + ) + find_path(POPPLER_QT5_INCLUDE_DIR_core qt5/poppler-qt5.h + HINTS ${_pc_poppler_INCLUDE_DIRS} + PATH_SUFFIXES poppler + ) + + if(POPPLER_QT5_LIBRARY AND POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_INCLUDE_DIR_core) + list(APPEND POPPLER_QT5_INCLUDE_DIR "${POPPLER_QT5_INCLUDE_DIR_core}") + set(POPPLER_QT5_FOUND TRUE) + endif(POPPLER_QT5_LIBRARY AND POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_INCLUDE_DIR_core) +endif(NOT _poppler_version_bad) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PopplerQt5 DEFAULT_MSG + POPPLER_QT5_LIBRARY + POPPLER_QT5_INCLUDE_DIR) +endif(POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_LIBRARY) diff --git a/cmake/FindRTI.cmake b/cmake/FindRTI.cmake new file mode 100755 index 000000000..3aaf5e82d --- /dev/null +++ b/cmake/FindRTI.cmake @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +SET(_rti_gcc_arch "") +IF(NOT RTI_DIR) + SET(_arch "unknown") + IF(WIN32) + SET(_RTI_DIR $ENV{DDS_PATH}) + IF(NOT _RTI_DIR) + GET_FILENAME_COMPONENT(_rti_root_path "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Real-Time Innovations\\RTI Connext DDS Pro 5.2.3;Location]" ABSOLUTE) + SET(_RTI_DIR "${_rti_root_path}") + ENDIF() + IF(MSVC_VERSION EQUAL 1900) + SET(_rti_msvc_ver "VS2015") + ELSEIF(MSVC_VERSION GREATER_EQUAL 1910) + SET(_rti_msvc_ver "VS2017") + ENDIF() + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(_rti_msvc_ver "x64Win64${_rti_msvc_ver}") + ELSE() + SET(_rti_msvc_ver "i86Win32${_rti_msvc_ver}") + ENDIF() + IF(NOT ${_rti_root_path}) + SET(_RTI_DIR $ENV{KDEROOT}) + FILE(TO_CMAKE_PATH "${_RTI_DIR}" _RTI_DIR) + IF(NOT EXISTS "${_RTI_DIR}" OR NOT IS_DIRECTORY "${_RTI_DIR}") + SET(_RTI_DIR $ENV{WORKSPACE}) + FILE(TO_CMAKE_PATH "${_RTI_DIR}" _RTI_DIR) + ENDIF() + IF(NOT EXISTS "${_RTI_DIR}" OR NOT IS_DIRECTORY "${_RTI_DIR}") + SET(_RTI_DIR ${EXTERNAL_LIBRARY_DIR}) + FILE(TO_CMAKE_PATH "${_RTI_DIR}" _RTI_DIR) + ENDIF() + ENDIF() + SET(_arch "${_rti_msvc_ver}") + ELSE(WIN32) + SET(_RTI_DIR $ENV{DDS_PATH}) + IF(NOT _RTI_DIR) + SET(_RTI_DIR "/opt/RTI") + ENDIF() + IF(NOT EXISTS "${_RTI_DIR}" OR NOT IS_DIRECTORY "${_RTI_DIR}") + MESSAGE(FATAL_ERROR "Umgebungsvariable DDS_PATH nicht gesetzt!") + ENDIF() + SET(_rti_gcc_arch "x64Linux3gcc4.8.2") + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0.0) + SET(_rti_gcc_arch "x64Linux3gcc5.4.0") + SET(_tmp "${_RTI_DIR}/lib/${_rti_gcc_arch}") + IF (NOT EXISTS ${_tmp}) + SET(_rti_gcc_arch "x64Linux4gcc7.3.0") + ENDIF() + ENDIF() + ENDIF() + SET(_arch "${_rti_gcc_arch}") + ENDIF() + SET(RTI_DIR "${_RTI_DIR}" CACHE STRING "RTI base path" FORCE) + MESSAGE(STATUS "Trying to use RTI from ${RTI_DIR} with arch ${_arch}") +ENDIF() +IF(WIN32) + SET(_rti_include_hint "${RTI_DIR}/include/") + SET(_rti_library_hint "${RTI_DIR}/lib/${_rti_msvc_ver}/") +ELSE() + SET(_rti_include_hint "${RTI_DIR}/include/") + SET(_rti_library_hint "${RTI_DIR}/lib/") +ENDIF() + + +IF(NOT RTI_INCLUDE_DIR) + FIND_PATH(RTI_INCLUDE_DIR ndds/ndds_cpp.h HINTS ${_rti_include_hint}) + IF(RTI_INCLUDE_DIR) + SET(RTI_INCLUDE_DIRS "${RTI_INCLUDE_DIR}" "${RTI_INCLUDE_DIR}/ndds" "${RTI_INCLUDE_DIR}/ndds/hpp" CACHE STRING "RTI include directories" FORCE) + MARK_AS_ADVANCED(RTI_INCLUDE_DIRS) + ELSE() + MESSAGE(FATAL "Could not find RTI include directory at ${_rti_include_hint}") + ENDIF() +ENDIF() + + +IF(NOT RTI_DDSGEN_EXECUTABLE) + FIND_PROGRAM(RTI_DDSGEN_EXECUTABLE NAMES rtiddsgen rtiddsgen.bat HINTS ${RTI_DIR}/scripts ${RTI_DIR}/bin) +ENDIF() +IF(NOT RTI_VERSION_MAJOR) + EXEC_PROGRAM(${RTI_DDSGEN_EXECUTABLE} ARGS -version OUTPUT_VARIABLE _dds_version_output) + STRING(REGEX REPLACE ".* ([0-9]\\.[0-9]\\.[0-9]).*" "\\1" _dds_version_output ${_dds_version_output}) + SET(_rti_version_major 5) + IF(_dds_version_output VERSION_GREATER 2.9.9) + SET(_rti_version_major 6) + ENDIF() + SET(RTI_VERSION_MAJOR ${_rti_version_major} CACHE STRING "RTI version" FORCE) +ENDIF() + +INCLUDE(FindLibraryWithDebug) +INCLUDE(FindPackageHandleStandardArgs) + + +SET(_RTI_LIBS nddscore nddsc nddscpp2 rtiroutingservice) +SET(_libs "") +SET(_lib_vars "") + +FOREACH(_lib ${_RTI_LIBS}) + SET(_libname "RTI_${_lib}_LIBRARY") + IF (NOT ${_libname}) + FIND_LIBRARY_WITH_DEBUG("${_libname}" + WIN32_DEBUG_POSTFIX d + NAMES ${_lib} + HINTS ${_rti_library_hint} ${RTI_DIR}/lib ${RTI_DIR}/lib/${_rti_gcc_arch}) + ENDIF() + SET(_tgt_name RTI::${_lib}) + + IF(NOT TARGET ${_tgt_name}) + ADD_LIBRARY(${_tgt_name} UNKNOWN IMPORTED) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${RTI_INCLUDE_DIRS}") + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${RTI_INCLUDE_DIRS}") + + IF(UNIX) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "RTI_UNIX;RTI_LINUX;RTI_64BIT" ) + ENDIF() + IF(WIN32) + IF("${_lib}" STREQUAL "rtiroutingservice") + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "RTI_WIN32;RTI_routingservice_DLL_VARIABLE" ) + ELSE() + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "RTI_WIN32;NDDS_DLL_VARIABLE" ) + ENDIF() + ENDIF() + + IF(${_libname}_RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_RELEASE "${${_libname}_RELEASE}") + ENDIF() + IF(${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_DEBUG "${${_libname}_DEBUG}") + ENDIF() + IF(NOT ${_libname}_RELEASE AND NOT ${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION "${${_libname}}") + ENDIF() + ENDIF() + + LIST(APPEND _libs "${${_libname}}") + LIST(APPEND _lib_vars "${_libname}") +ENDFOREACH() + +IF(TARGET RTI::nddscore AND UNIX) + SET_PROPERTY(TARGET RTI::nddscore PROPERTY INTERFACE_LINK_LIBRARIES "dl" ) +ENDIF() + +SET(RTI_LIBRARIES ${_libs} CACHE STRING "All rti libraries" FORCE) +MARK_AS_ADVANCED(RTI_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(RTI DEFAULT_MSG RTI_DIR RTI_INCLUDE_DIR RTI_DDSGEN_EXECUTABLE ${_lib_vars}) + diff --git a/cmake/FindSchusstafel.cmake b/cmake/FindSchusstafel.cmake new file mode 100755 index 000000000..87a44356e --- /dev/null +++ b/cmake/FindSchusstafel.cmake @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(SCHUSSTAFEL_INCLUDE_DIR AND SCHUSSTAFEL_LIBRARY) + SET(SCHUSSTAFEL_FOUND TRUE) +ELSE(SCHUSSTAFEL_INCLUDE_DIR AND SCHUSSTAFEL_LIBRARY) + + FIND_PATH(SCHUSSTAFEL_INCLUDE_DIR Schusstafel.h) + FIND_LIBRARY_WITH_DEBUG(SCHUSSTAFEL_LIBRARY WIN32_DEBUG_POSTFIX d NAMES Schusstafel libSchusstafel) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Schusstafel DEFAULT_MSG SCHUSSTAFEL_LIBRARY SCHUSSTAFEL_INCLUDE_DIR) + + MARK_AS_ADVANCED(SCHUSSTAFEL_INCLUDE_DIR SCHUSSTAFEL_LIBRARY) +ENDIF(SCHUSSTAFEL_INCLUDE_DIR AND SCHUSSTAFEL_LIBRARY) diff --git a/cmake/FindTMSIF.cmake b/cmake/FindTMSIF.cmake new file mode 100755 index 000000000..66985c563 --- /dev/null +++ b/cmake/FindTMSIF.cmake @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(NOT TMSIF_DIR) + SET(_arch "unknown") + SET(_TMSIF_DIR $ENV{TMSIF_PATH}) + IF(NOT _TMSIF_DIR) + SET(_TMSIF_DIR "/opt/tmsif") + ENDIF() + IF(NOT EXISTS "${_TMSIF_DIR}" OR NOT IS_DIRECTORY "${_TMSIF_DIR}") + MESSAGE(FATAL_ERROR "Umgebungsvariable TMSIF_PATH nicht gesetzt!") + ENDIF() + SET(TMSIF_DIR "${_TMSIF_DIR}" CACHE STRING "TMSIF base path" FORCE) + MESSAGE(STATUS "Trying to use TMSIF_DIR from ${TMSIF_DIR}") +ENDIF() +SET(_tmsif_include_hint "${TMSIF_DIR}/include/") +SET(_tmsif_library_hint "${TMSIF_DIR}/lib/") + + +IF(NOT TMSIF_INCLUDE_DIR) + FIND_PATH(TMSIF_INCLUDE_DIR Common.h HINTS ${_tmsif_include_hint}) + IF(TMSIF_INCLUDE_DIR) + SET(TMSIF_INCLUDE_DIRS "${TMSIF_INCLUDE_DIR}" "${TMSIF_INCLUDE_DIR}/ddscxx" CACHE STRING "TMSIF include directories" FORCE) + MARK_AS_ADVANCED(TMSIF_INCLUDE_DIRS) + ELSE() + MESSAGE(FATAL "Could not find TMSIF include directory at ${_tmsif_include_hint}") + ENDIF() +ENDIF() + + + +SET(_TMSIF_LIBS tmsif-cyclone ddscxx ddkit-cyclone ) +SET(_libs "") +SET(_lib_vars "") + +FOREACH(_lib ${_TMSIF_LIBS}) + SET(_libname "TMSIF_${_lib}_LIBRARY") + IF (NOT ${_libname}) + FIND_LIBRARY_WITH_DEBUG("${_libname}" + WIN32_DEBUG_POSTFIX d + NAMES ${_lib} + HINTS ${_tmsif_library_hint} ${TMSIF_DIR}/lib ) + ENDIF() + SET(_tgt_name TMSIF::${_lib}) + + IF(NOT TARGET ${_tgt_name}) + ADD_LIBRARY(${_tgt_name} UNKNOWN IMPORTED) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${TMSIF_INCLUDE_DIRS}") + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${TMSIF_INCLUDE_DIRS}") + + IF(UNIX) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "TMSIF_UNIX;TMSIF_LINUX;TMSIF_64BIT" ) + ENDIF() + IF(${_libname}_RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_RELEASE "${${_libname}_RELEASE}") + ENDIF() + IF(${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_DEBUG "${${_libname}_DEBUG}") + ENDIF() + IF(NOT ${_libname}_RELEASE AND NOT ${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION "${${_libname}}") + ENDIF() + ENDIF() + + LIST(APPEND _libs "${${_libname}}") + LIST(APPEND _lib_vars "${_libname}") +ENDFOREACH() + + +SET(TMSIF_LIBRARIES ${_libs} CACHE STRING "All TMSIF libraries" FORCE) +MARK_AS_ADVANCED(TMSIF_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TMSIF DEFAULT_MSG TMSIF_DIR TMSIF_INCLUDE_DIR ${_lib_vars}) + diff --git a/cmake/FindVLC.cmake b/cmake/FindVLC.cmake new file mode 100755 index 000000000..d6ab65cd4 --- /dev/null +++ b/cmake/FindVLC.cmake @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +IF(VLC_INCLUDE_DIR AND VLC_LIBRARIES) + + + SET(VLC_FOUND TRUE) + +ELSE() + + INCLUDE(FindPackageHandleStandardArgs) + INCLUDE(FindLibraryWithDebug) + + FIND_LIBRARY_WITH_DEBUG(VLC_LIBRARIES WIN32_DEBUG_POSTFIX d NAMES vlc libvlc) + FIND_PATH(VLC_INCLUDE_DIR vlc/vlc.h) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(VLC DEFAULT_MSG VLC_LIBRARIES VLC_INCLUDE_DIR) + + FIND_PATH(VLC_IS_2_0_ABOVE vlc/libvlc_version.h + PATHS ${VLC_INCLUDE_DIR} + NO_DEFAULT_PATH) + + IF(NOT VLC_IS_2_0_ABOVE) + MESSAGE(FATAL_ERROR "Need at least VLC 2.x") + ENDIF() + MARK_AS_ADVANCED(VLC_DEFINES) + +ENDIF() diff --git a/cmake/FindXSD.cmake b/cmake/FindXSD.cmake new file mode 100755 index 000000000..ccf432e07 --- /dev/null +++ b/cmake/FindXSD.cmake @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(XSD_INCLUDE_DIR AND XSD_COMPILER) + SET(XSD_FOUND TRUE) +ELSE(XSD_INCLUDE_DIR AND XSD_COMPILER) + + FIND_PROGRAM(XSD_COMPILER NAMES xsdcxx xsd) + FIND_PATH(XSD_INCLUDE_DIR xsd/cxx/config.hxx) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XSD DEFAULT_MSG + XSD_COMPILER + XSD_INCLUDE_DIR + ) + + MARK_AS_ADVANCED(XSD_COMPILER + XSD_INCLUDE_DIR) +ENDIF(XSD_INCLUDE_DIR AND XSD_COMPILER) + +MACRO(XSD_GENERATE_TREE srcList infile) + GET_FILENAME_COMPONENT(output ${infile} NAME) + GET_FILENAME_COMPONENT(input ${infile} ABSOLUTE) + GET_FILENAME_COMPONENT(dir ${infile} DIRECTORY) + + EXEC_PROGRAM(${XSD_COMPILER} ARGS version OUTPUT_VARIABLE _xsd_version_output) + STRING(REGEX REPLACE ".* ([0-9]\\.[0-9]\\.[0-9]).*" "\\1" _xsd_version_output ${_xsd_version_output}) + + SET(_xsd_in ${input}) + SET(_cpp_out ${dir}/${output}.cxx) + SET(_hpp_out ${dir}/${output}.hxx) + + STRING(REPLACE ".xsd" "" _cpp_out "${_cpp_out}") + STRING(REPLACE ".xsd" "" _hpp_out "${_hpp_out}") + SET(additional_xsd_args "") + IF(_xsd_version_output VERSION_GREATER 3.9.0) + IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.7.0) + SET(additional_xsd_args --std c++11) + ELSE() + IF(WIN32 OR NOT CMAKE_COMPILER_IS_GNUCC) + SET(additional_xsd_args --std c++11) + ENDIF(WIN32 OR NOT CMAKE_COMPILER_IS_GNUCC) + ENDIF() + ENDIF() + + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${dir} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${dir} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + ADD_CUSTOM_COMMAND(OUTPUT ${_cpp_out} ${_hpp_out} + COMMAND ${XSD_COMPILER} + ARGS cxx-tree ${additional_xsd_args} --generate-serialization ${_xsd_in} + DEPENDS ${_xsd_in} ${CMAKE_CURRENT_BINARY_DIR}/${dir} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir} + ) + LIST(APPEND ${srcList} ${_cpp_out} ${_hpp_out} ${infile}) +ENDMACRO(XSD_GENERATE_TREE srcList infile) diff --git a/cmake/MacroCodeGenIdl.cmake b/cmake/MacroCodeGenIdl.cmake new file mode 100755 index 000000000..ba39f7d39 --- /dev/null +++ b/cmake/MacroCodeGenIdl.cmake @@ -0,0 +1,511 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +INCLUDE(CMakeParseArguments) + +MACRO(_ADD_SERVICE_RESTART_FLAG svcName) + + STRING(TOUPPER ${svcName} _svcNameUpper) + STRING(TOLOWER ${svcName} _svcNameLower) + SET(_optionName DONTRESTARTSVC_${_svcNameUpper}) + OPTION(${_optionName} "Do not automatically restart Service ${_svcNameUpper} (build dir only)" OFF) + SET(_fn "${CMAKE_BINARY_DIR}/share/Lts/xml/${_svcNameLower}.dontRestart") + IF (${_optionName}) + FILE(WRITE ${_fn} "blub") + ELSE() + FILE(REMOVE ${_fn}) + ENDIF() + +ENDMACRO() + + +MACRO(_GET_SERVICENAME xmlFile_in svcNameOut) + GET_FILENAME_COMPONENT(xmlFile ${xmlFile_in} NAME_WE) + SET(_idx -1) + STRING(FIND "${xmlFile}" "_" _idx) + STRING(SUBSTRING "${xmlFile}" 0 ${_idx} ${svcNameOut}) +ENDMACRO() + +MACRO(_CODEGEN_ACTION action srcList xmlIn in_files out_files) + LIST(APPEND dependFiles ${ARGN} ${xmlIn} ${${in_files}}) + + + + + SET(_cg codegen) + ADD_CUSTOM_COMMAND(OUTPUT ${${out_files}} + COMMAND ${_cg} + ARGS -s ${xmlIn} + -a ${action} + -o ${CMAKE_CURRENT_BINARY_DIR} + -i ${CMAKE_BINARY_DIR}/service_idl_files.txt + ${${in_files}} + DEPENDS ${_cg} ${dependFiles} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + LIST(APPEND ${srcList} ${${out_files}}) + GET_FILENAME_COMPONENT(_xml "${CMAKE_CURRENT_SOURCE_DIR}/${xmlIn}" ABSOLUTE) + SET_PROPERTY(GLOBAL APPEND PROPERTY CODEGEN_IDL_FILES "${_xml}") +ENDMACRO() + +MACRO(CODEGEN_DATABASE_STRUCTS srcList_h xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.h" + ) + _CODEGEN_ACTION("DATABASE" ${srcList_h} ${xmlFile_in} in_files out_files ${ARGN}) +ENDMACRO() + +MACRO(CODEGEN_DATABASE_SQL srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h" + ) + _CODEGEN_ACTION("DATABASE" ${srcList} ${xmlFile_in} in_files out_files ${ARGN}) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h") + ENDIF() +ENDMACRO() + +MACRO(CODEGEN_DAO srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dao.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dao.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.h" + ) + _CODEGEN_ACTION("dao" ${srcList} ${xmlFile_in} in_files out_files ${ARGN}) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.h") + ENDIF() +ENDMACRO() + +MACRO(CODEGEN_DATABASE srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + ) + _CODEGEN_ACTION("DATABASE_SERVER" ${srcList} ${xmlFile_in} in_files out_files ${ARGN}) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h") + ENDIF() +ENDMACRO() + + +MACRO(INSTALL_SHARED_FILES srcList) + SET(options) + SET(oneValueArgs DESTINATION) + SET(multiValueArgs FILES) + CMAKE_PARSE_ARGUMENTS(_ISF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + SET(build_out_dir ${CMAKE_BINARY_DIR}/share/Lts/${_ISF_DESTINATION}) + SET(inst_out_dir share/Lts/${_ISF_DESTINATION}) + + FOREACH(filename ${_ISF_FILES}) + GET_FILENAME_COMPONENT(fn ${filename} NAME) + SET(build_out_file ${build_out_dir}/${fn}) + SET(in_file ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) + ADD_CUSTOM_COMMAND(OUTPUT ${build_out_file} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${build_out_dir} + COMMAND ${CMAKE_COMMAND} + ARGS -E copy_if_different ${in_file} ${build_out_file} + DEPENDS ${in_file} + ) + LIST(APPEND ${srcList} ${in_file} ${build_out_file}) + ENDFOREACH() + NGL_INSTALL(${_ISF_UNPARSED_ARGUMENTS} FILES ${_ISF_FILES} DESTINATION ${inst_out_dir}) +ENDMACRO() + +MACRO(CODEGEN_SQL srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(out_dir_sql "${CMAKE_BINARY_DIR}/share/Lts/sql/") + SET(out_file_sql "${out_dir_sql}/${svcNameOut}.sql") + SET(action "SQL") + ADD_CUSTOM_COMMAND(OUTPUT ${out_file_sql} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${out_dir_sql} + COMMAND codegen + ARGS -s ${xmlFile_in} + -a ${action} + -o ${out_dir_sql} + -i ${CMAKE_BINARY_DIR}/service_idl_files.txt + DEPENDS ${_cg} ${xmlFile_in} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + LIST(APPEND ${srcList} ${out_file_sql}) + + + NGL_INSTALL(SV AAR FILES ${out_file_sql} DESTINATION share/Lts/sql) +ENDMACRO() + +MACRO(CODEGEN_HANDLE_SVC_XML srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + + SET(out_dir_xml "${CMAKE_BINARY_DIR}/share/Lts/xml/") + SET(out_file_xml "${out_dir_xml}/${svcNameOut}.xml") + ADD_CUSTOM_COMMAND(OUTPUT ${out_file_xml} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${out_dir_xml} + COMMAND ${CMAKE_COMMAND} + ARGS -E copy_if_different ${xmlFile_in} ${out_file_xml} + DEPENDS ${xmlFile_in} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + LIST(APPEND ${srcList} ${xmlFile_in} ${out_file_xml}) + + _ADD_SERVICE_RESTART_FLAG(${svcNameOut}) + + + NGL_INSTALL(SV AAR FILES ${out_file_xml} DESTINATION share/Lts/xml) +ENDMACRO() + +MACRO(CODEGEN_IDL_SVC srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc.idl.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_enums.idl.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_json.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_json.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_translation.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_translation.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}.idl" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_enums.idl") + SET_PROPERTY(GLOBAL APPEND PROPERTY CODEGEN_IDL_FILES "${out_files}") + SET_SOURCE_FILES_PROPERTIES(${out_files} PROPERTIES HEADER_FILE_ONLY TRUE) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_json.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_json.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_translation.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_translation.h") + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files ${ARGN}) + + CODEGEN_HANDLE_SVC_XML(${srcList} ${xmlFile_in}) +ENDMACRO() + +FIND_PACKAGE(PythonInterp 2.7 REQUIRED) +MACRO(CODEGEN_TOPIC_TYPEDEFS srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(inFile ${xmlFile_in}) + IF(NOT IS_ABSOLUTE ${inFile}) + SET(inFile ${CMAKE_CURRENT_SOURCE_DIR}/${inFile}) + IF(NOT EXISTS ${inFile}) + SET(inFile ${CMAKE_CURRENT_BINARY_DIR}/${inFile}) + ENDIF() + ENDIF() + SET(prog ${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/codegen_simple.py) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_operator_rights.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_operator_rights.cpp" + "${CMAKE_BINARY_DIR}/share/Lts/sql/${svcNameOut}_operator_rights.sql" + ) + + ADD_CUSTOM_COMMAND( OUTPUT ${out_files} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${CMAKE_BINARY_DIR}/share/Lts/sql/ + COMMAND ${PYTHON_EXECUTABLE} + ARGS ${prog} ALL + ${inFile} + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${PYTHON_EXECUTABLE} + ARGS ${prog} SQL + ${inFile} + ${CMAKE_BINARY_DIR}/share/Lts/sql + DEPENDS ${inFile} + ${prog} + ) + LIST(APPEND ${srcList} ${out_files}) + SET_PROPERTY(GLOBAL APPEND PROPERTY CODEGEN_XML_FILES "${inFile}") +ENDMACRO() + +MACRO(CODEGEN_CLIENT_TOPICS_IFC srcList xmlFile_in) + SET(options) + SET(oneValueArgs) + SET(multiValueArgs PARTS) + CMAKE_PARSE_ARGUMENTS(_CST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + IF(NOT _CST_PARTS) + SET(_CST_PARTS "DTC" "FTC") + ENDIF() + SET(in_files "") + SET(out_files "") + FOREACH(part ${_CST_PARTS}) + IF(part STREQUAL "DTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dtc.h.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc.h" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc.h") + ENDIF() + ELSEIF(part STREQUAL "FTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_ftc.h.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc.h" + ) + ELSE() + MESSAGE(FATAL_ERROR "Unkown part argument for CODEGEN_SERVER_TOPICS (${part})") + ENDIF() + ENDFOREACH() + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) +ENDMACRO() + +MACRO(CODEGEN_CLIENT_TOPICS_IMPL srcList xmlFile_in) + SET(options) + SET(oneValueArgs) + SET(multiValueArgs PARTS) + CMAKE_PARSE_ARGUMENTS(_CST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + IF(NOT _CST_PARTS) + SET(_CST_PARTS "DTC" "FTC") + ENDIF() + SET(in_files "") + SET(out_files "") + FOREACH(part ${_CST_PARTS}) + IF(part STREQUAL "DTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dtc_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dtc_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_impl.cpp" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_impl.h") + ENDIF() + ELSEIF(part STREQUAL "FTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_ftc_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_ftc_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_impl.cpp" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_impl.h") + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "Unkown part argument for CODEGEN_SERVER_TOPICS (${part})") + ENDIF() + ENDFOREACH() + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) +ENDMACRO() + +MACRO(CODEGEN_SERVER_TOPICS srcList xmlFile_in) + SET(options) + SET(oneValueArgs) + SET(multiValueArgs PARTS) + CMAKE_PARSE_ARGUMENTS(_CST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + IF(NOT _CST_PARTS) + SET(_CST_PARTS "DTS" "FTS") + ENDIF() + SET(in_files "") + SET(out_files "") + FOREACH(part ${_CST_PARTS}) + IF(part STREQUAL "DTS") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dts.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dts_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dts_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts_impl.cpp" + ) + ELSEIF(part STREQUAL "FTS") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_fts.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_fts_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_fts_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_impl.cpp" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} ${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_impl.h) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "Unkown part argument for CODEGEN_SERVER_TOPICS (${part})") + ENDIF() + ENDFOREACH() + + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) +ENDMACRO() + + + + +MACRO(CODEGEN_TOPIC_TYPE_PLUGIN srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_topic_type_plugin.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_topic_type_plugin.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_topic_type_plugin.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_topic_type_plugin.h" + ) + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} ${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_topic_type_plugin.h) + ENDIF() +ENDMACRO() + +MACRO(CREATE_TOPIC_TYPE_PLUGIN xmlFile_in) + SET(_my_srcs "") + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + CODEGEN_TOPIC_TYPE_PLUGIN(_my_srcs ${xml_FILE}) + + STRING(SUBSTRING ${svcNameOut} 0 1 _ss1) + STRING(SUBSTRING ${svcNameOut} 1 -1 _ss2) + STRING(TOUPPER ${_ss1} _ss1) + SET(_commonLib "svc${_ss1}${_ss2}Common") + + IF(svcNameOut STREQUAL "core") + SET(_commonLib ddscore) + ENDIF() + + NGL_ADD_LIBRARY(WS AAR SV NO_TRANSLATION ${svcNameOut}TopicTypePlugin MODULE + ${_my_srcs} + ) + NGL_TARGET_LINK_LIBRARIES(${svcNameOut}TopicTypePlugin + topic_type_plugin + routing_plugin + ddscore + ${_commonLib} + ) + NGL_INSTALL_TARGET(${svcNameOut}TopicTypePlugin) +ENDMACRO() + + + + +MACRO(CODEGEN_RECORD_REPLAY_PLUGIN srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_record_replay_plugin.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_record_replay_plugin.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_record_replay_plugin.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_record_replay_plugin.h" + ) + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} ${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_record_replay_plugin.h) + ENDIF() +ENDMACRO() + +MACRO(CREATE_RECORD_REPLAY_PLUGIN_INTERN xmlFile_in svcSourceList libtype) + SET(_my_srcs "") + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + CODEGEN_RECORD_REPLAY_PLUGIN(_my_srcs ${xml_FILE}) + + STRING(SUBSTRING ${svcNameOut} 0 1 _ss1) + STRING(SUBSTRING ${svcNameOut} 1 -1 _ss2) + STRING(TOUPPER ${_ss1} _ss1) + SET(_commonLib "svc${_ss1}${_ss2}Common") + + IF(svcNameOut STREQUAL "core") + SET(_commonLib ddscore) + ENDIF() + + LIST(APPEND ${svcSourceList} ${_my_srcs}) + + NGL_ADD_LIBRARY(SV AAR WS ${svcNameOut}RecordReplayPlugin ${libtype} + ${_my_srcs} + ) + NGL_TARGET_LINK_LIBRARIES(${svcNameOut}RecordReplayPlugin + RecordReplayPlugin + ddscore + ddsconnector + ddsdtc + ngldb + LtsUtilsCore + ${_commonLib} + ) + NGL_INSTALL_TARGET(${svcNameOut}RecordReplayPlugin) + NGL_TARGET_INCLUDE_DIRECTORIES(${svcNameOut}RecordReplayPlugin + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_BINARY_DIR}/../ + ) +ENDMACRO() + +MACRO(CREATE_RECORD_REPLAY_PLUGIN xmlFile_in svcSourceList) + CREATE_RECORD_REPLAY_PLUGIN_INTERN(${xmlFile_in} ${svcSourceList} MODULE) +ENDMACRO() + +MACRO(CREATE_RECORD_REPLAY_PLUGIN_SHARED xmlFile_in) + CREATE_RECORD_REPLAY_PLUGIN_INTERN(${xmlFile_in} _unused SHARED) +ENDMACRO() + +MACRO(CODEGEN_WRITE_SERVICEFILE_INFO) + GET_PROPERTY(idl_files GLOBAL PROPERTY CODEGEN_IDL_FILES) + LIST(REMOVE_DUPLICATES idl_files) + FILE(WRITE ${CMAKE_BINARY_DIR}/service_idl_files.txt "-- all available service idl files\n") + FOREACH(idl_file ${idl_files}) + FILE(APPEND ${CMAKE_BINARY_DIR}/service_idl_files.txt "${idl_file}\n") + ENDFOREACH() +ENDMACRO() diff --git a/cmake/MacroEnsureOutOfSourceBuild.cmake b/cmake/MacroEnsureOutOfSourceBuild.cmake new file mode 100755 index 000000000..3b3655519 --- /dev/null +++ b/cmake/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,21 @@ + + + + + + + + + + + + +MACRO (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage) + + STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" insource) + IF(insource) + MESSAGE(FATAL_ERROR "${_errorMessage}") + ENDIF(insource) + +ENDMACRO (MACRO_ENSURE_OUT_OF_SOURCE_BUILD) + diff --git a/cmake/MacroRTIDDSGen.cmake b/cmake/MacroRTIDDSGen.cmake new file mode 100755 index 000000000..b8daeb8b1 --- /dev/null +++ b/cmake/MacroRTIDDSGen.cmake @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + +MACRO(RTIDDSGEN srcList infile) + FIND_PACKAGE(RTI REQUIRED) + + SET(input ${infile}) + IF(NOT IS_ABSOLUTE ${input}) + SET(input "${CMAKE_CURRENT_BINARY_DIR}/${input}") + ENDIF() + GET_FILENAME_COMPONENT(output ${infile} NAME_WE) + GET_FILENAME_COMPONENT(input ${input} ABSOLUTE) + + + + + SET(_ddsgen_args "") + SET(output_cxx + ${CMAKE_CURRENT_BINARY_DIR}/${output}.cxx + ${CMAKE_CURRENT_BINARY_DIR}/${output}Plugin.cxx + ) + + SET(output_hpp + ${CMAKE_CURRENT_BINARY_DIR}/${output}.hpp + ${CMAKE_CURRENT_BINARY_DIR}/${output}Plugin.hpp + ) + + + + + ADD_CUSTOM_COMMAND(OUTPUT ${output_cxx} ${output_hpp} + COMMAND ${CMAKE_COMMAND} + ARGS -E remove ${output_cxx} + COMMAND ${RTI_DDSGEN_EXECUTABLE} + ARGS -language "C++11" + ARGS -unboundedSupport + ARGS -verbosity 2 + ARGS -update typefiles + ARGS -stl + ARGS -d ${CMAKE_CURRENT_BINARY_DIR} + ARGS -inputIdl ${input} + ARGS -I ${CMAKE_CURRENT_BINARY_DIR} + ARGS -I ${CMAKE_CURRENT_BINARY_DIR}/../ + ARGS -I ${CMAKE_CURRENT_BINARY_DIR}/../../ + ARGS -I ${CMAKE_CURRENT_SOURCE_DIR} + ARGS -I ${CMAKE_CURRENT_SOURCE_DIR}/../ + ARGS -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${input} ${ARGN} + ) + + IF(WIN32) + SET_SOURCE_FILES_PROPERTIES(${output_cxx} PROPERTIES COMPILE_FLAGS "-DNDDS_USER_DLL_EXPORT") + ELSE() + SET_SOURCE_FILES_PROPERTIES(${output_cxx} PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) + ENDIF() + LIST(APPEND ${srcList} ${output_cxx} ${output_hpp}) + + +ENDMACRO() diff --git a/cmake/NGLMacros.cmake b/cmake/NGLMacros.cmake new file mode 100755 index 000000000..cf06076ac --- /dev/null +++ b/cmake/NGLMacros.cmake @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +INCLUDE(GenerateExportHeader) +SET(_default_build OFF) +IF(BUILD_ALL) + SET(_default_build ON) +ENDIF() + +OPTION(BUILD_SV "Build and install Server software parts" ${_default_build}) +OPTION(BUILD_AAR "Build and install AAR software parts" ${_default_build}) +OPTION(BUILD_LTSCC "Build and install LTS CC Conf" OFF) +OPTION(BUILD_HLA "Build and install HLA Server software parts" OFF) +OPTION(BUILD_WS "Build and install Workstation software parts" ${_default_build}) +OPTION(BUILD_TOOLSWS "Build and install TOOLS for WS" OFF) +OPTION(BUILD_TOOLSSV "Build and install TOOLS for SV" OFF) + +OPTION(BUILD_DEP_TEST_EXECUTABLES "Build executables for created libs to check library dependencies" OFF) +OPTION(BUILD_TS_FILES "Regenerate ts-files for translations" OFF) +OPTION(BUILD_STATIC_LIBRARIES "Build all libraries as static libraries" OFF) + +IF(BUILD_STATIC_LIBRARIES) + ADD_DEFINITIONS(-DBUILD_STATIC_LIBRARIES) +ENDIF() + + +SET(AAR_INSTALL_PATH "AAR") +SET(SV_INSTALL_PATH "SV") +SET(HLA_INSTALL_PATH "SV") +SET(DDS_INSTALL_PATH "SV") +SET(WS_INSTALL_PATH "WS") +SET(TOOLSWS_INSTALL_PATH "WS") +SET(TOOLSSV_INSTALL_PATH "SV") +IF(WIN32) + SET(INSTALL_DEFAULT_ARGS RUNTIME DESTINATION bin + LIBRARY DESTINATION bin + ARCHIVE DESTINATION lib COMPONENT Devel) +ELSE() + SET(INSTALL_DEFAULT_ARGS RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib COMPONENT Devel) +ENDIF() +SET(INSTALL_DEFAULT_ARGS_DEVEL RUNTIME DESTINATION bin COMPONENT Devel + LIBRARY DESTINATION lib COMPONENT Devel + ARCHIVE DESTINATION lib COMPONENT Devel) +SET(_components SV WS AAR TOOLSWS TOOLSSV HLA) + + + + +MACRO (NGL_GET_BUILDPARTS _args _buildopts) + + SET(${_buildopts} "") + SET(_at_least_one_keyword_found OFF) + + LIST(FIND ${_args} "ALL" _all) + IF (_all GREATER -1) + LIST(REMOVE_AT ${_args} ${_all}) + SET(_at_least_one_keyword_found ON) + FOREACH(_component ${_components}) + IF(BUILD_${_component}) + LIST(APPEND ${_buildopts} ${_component}) + ENDIF() + ENDFOREACH() + ELSE() + FOREACH(_component ${_components}) + LIST(FIND ${_args} "${_component}" _idx) + IF(_idx GREATER -1) + LIST(REMOVE_AT ${_args} ${_idx}) + SET(_at_least_one_keyword_found ON) + IF(BUILD_${_component}) + LIST(APPEND ${_buildopts} ${_component}) + ENDIF() + ENDIF() + ENDFOREACH() + ENDIF() + + IF(NOT _at_least_one_keyword_found) + MESSAGE(FATAL_ERROR "No software component keyword (ALL/SV/WS) given!") + ENDIF() +ENDMACRO() + +MACRO (NGL_PARSE_BUILDCOMPONENT_INTERNAL _args _properties _build_target) + + NGL_GET_BUILDPARTS(${_args} _buildopts) + SET(${_build_target} OFF) + + FOREACH(_component ${_components}) + LIST(FIND _buildopts ${_component} _idx) + IF(_idx GREATER -1) + LIST(APPEND ${_properties} NGL_INSTALL_${_component} ON) + SET(${_build_target} ON) + ENDIF() + ENDFOREACH() + LIST(FIND ${_args} "NO_TRANSLATION" _no_i18n) + IF (_no_i18n GREATER -1) + LIST(REMOVE_AT ${_args} ${_no_i18n}) + LIST(APPEND ${_properties} NO_TRANSLATION ON) + ENDIF () + +ENDMACRO() + +MACRO(NGL_ADD_TRANSLATION output_location _qm_file_name _ts_file _qm_files) + GET_FILENAME_COMPONENT(_abs_FILE ${_ts_file} ABSOLUTE) + FILE(MAKE_DIRECTORY "${output_location}") + SET(qm "${output_location}/${_qm_file_name}.qm") + + ADD_CUSTOM_COMMAND(OUTPUT ${qm} + COMMAND Qt5::lrelease + ARGS ${_abs_FILE} -qm ${qm} + DEPENDS ${_abs_FILE} + ) + SET(${_qm_files} ${${_qm_files}} ${qm}) +ENDMACRO() + + + + +MACRO (NGL_ADD_LIBRARY) + + SET(_args ${ARGN}) + + + IF(BUILD_STATIC_LIBRARIES) + LIST(FIND _args "SHARED" _is_shared) + IF(_is_shared GREATER -1) + LIST(REMOVE_AT _args ${_is_shared}) + ENDIF() + ENDIF() + + SET(_properties "") + SET(_build_target OFF) + NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target) + LIST(GET _args 0 _target_NAME) + + IF(_build_target) + + ADD_LIBRARY(${_args}) + SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties}) + + IF(NOT MSVC AND NOT USE_ASAN AND NOT USE_UBSAN) + + SET_PROPERTY(TARGET ${_target_NAME} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--no-undefined") + ENDIF() + + + STRING(TOUPPER ${_target_NAME} _symbol) + STRING(REGEX REPLACE "[^_A-Za-z0-9]" "_" _symbol ${_symbol}) + IF(BUILD_STATIC_LIBRARIES) + SET(_symbol "${_symbol}_EXPORT=") + TARGET_COMPILE_DEFINITIONS(${_target_NAME} PUBLIC ${_symbol}) + ELSE() + GET_TARGET_PROPERTY(target_type ${_target_NAME} TYPE) + IF(target_type STREQUAL "SHARED_LIBRARY" OR + target_type STREQUAL "MODULE_LIBRARY") + SET(_symbol "MAKE_${_symbol}_LIB") + TARGET_COMPILE_DEFINITIONS(${_target_NAME} PRIVATE ${_symbol}) + ENDIF() + ENDIF() + + IF(BUILD_DEP_TEST_EXECUTABLES) + LIST(FIND _args "SHARED" _is_shared) + IF(_is_shared GREATER -1) + LIST(REMOVE_AT _args ${_is_shared}) + LIST(REMOVE_ITEM _args "${_target_NAME}") + ADD_EXECUTABLE(${_target_NAME}_dep_test ${NGL_MODULE_DIR}/ngl_dep_test_main.cpp ${_args}) + ENDIF() + ENDIF() + SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME}) + ENDIF() + + + +ENDMACRO() + +MACRO (NGL_ADD_LIBRARY2) + + SET(_args ${ARGN}) + + + IF(BUILD_STATIC_LIBRARIES) + LIST(FIND _args "SHARED" _is_shared) + IF(_is_shared GREATER -1) + LIST(REMOVE_AT _args ${_is_shared}) + ENDIF() + ENDIF() + + SET(_properties "") + SET(_build_target OFF) + NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target) + LIST(GET _args 0 _target_NAME) + + IF(_build_target) + + ADD_LIBRARY(${_args}) + SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties}) + + IF(NOT MSVC AND NOT USE_ASAN AND NOT USE_UBSAN) + + SET_PROPERTY(TARGET ${_target_NAME} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--no-undefined") + ENDIF() + TARGET_INCLUDE_DIRECTORIES(${_target_NAME} + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/../ + ) + GET_PROPERTY(type TARGET ${_target_NAME} PROPERTY TYPE) + IF(NOT ${type} STREQUAL "STATIC_LIBRARY") + NGL_INSTALL_TARGET(${_target_NAME}) + ENDIF() + IF(${type} STREQUAL "SHARED_LIBRARY" OR ${type} STREQUAL "MODULE_LIBRARY") + GENERATE_EXPORT_HEADER(${_target_NAME}) + ENDIF() + IF(BUILD_DEP_TEST_EXECUTABLES) + IF(${type} STREQUAL "SHARED_LIBRARY") + LIST(REMOVE_ITEM _args "SHARED") + LIST(REMOVE_ITEM _args "${_target_NAME}") + ADD_EXECUTABLE(${_target_NAME}_dep_test ${NGL_MODULE_DIR}/ngl_dep_test_main.cpp ${_args}) + ENDIF() + ENDIF() + + SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME}) + ENDIF() + + + +ENDMACRO() + + + + +MACRO (NGL_ADD_EXECUTABLE) + + SET(_args ${ARGN}) + SET(_properties "") + SET(_build_target OFF) + NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target) + LIST(GET _args 0 _target_NAME) + + IF(_build_target) + ADD_EXECUTABLE(${_args}) + SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties}) + SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME}) + ENDIF() + + + +ENDMACRO() + + + + +MACRO(NGL_TARGET_INCLUDE_DIRECTORIES _target_NAME) + + IF(TARGET ${_target_NAME}) + TARGET_INCLUDE_DIRECTORIES(${_target_NAME} ${ARGN}) + ENDIF() + +ENDMACRO() + + + + +MACRO(NGL_TARGET_LINK_LIBRARIES _target_NAME) + + IF(TARGET ${_target_NAME}) + TARGET_LINK_LIBRARIES(${_target_NAME} ${ARGN}) + IF(BUILD_DEP_TEST_EXECUTABLES) + GET_TARGET_PROPERTY(_type ${_target_NAME} TYPE) + IF("${_type}" STREQUAL "SHARED_LIBRARY") + TARGET_LINK_LIBRARIES(${_target_NAME}_dep_test ${ARGN} ${_target_NAME}) + ENDIF() + ENDIF() + ENDIF() + +ENDMACRO() +MACRO(NGL_ADD_INSTALL_PREFIX_INTERNAL _args prefix) + LIST(LENGTH ${_args} len) + + SET(_ret_args "") + SET(_replace_next OFF) + FOREACH( _arg ${${_args}}) + IF(${_arg} STREQUAL "DESTINATION") + SET(_replace_next ON) + LIST(APPEND _ret_args ${_arg}) + ELSE() + IF(_replace_next) + LIST(APPEND _ret_args "${prefix}/${_arg}") + SET(_replace_next OFF) + ELSE() + LIST(APPEND _ret_args ${_arg}) + ENDIF() + ENDIF() + ENDFOREACH() + + SET(${_args} ${_ret_args}) +ENDMACRO() + + + + + +MACRO(_NGL_INSTALL_TARGET_internal _target_NAME) + + SET(_args ${ARGN}) + IF(TARGET ${_target_NAME}) + FOREACH(_component ${_components}) + GET_TARGET_PROPERTY(_install_component ${_target_NAME} NGL_INSTALL_${_component}) + IF(_install_component) + SET(_my_args ${_args}) + NGL_ADD_INSTALL_PREFIX_INTERNAL(_my_args ${${_component}_INSTALL_PATH}) + INSTALL(TARGETS ${_target_NAME} ${_my_args}) + ENDIF() + ENDFOREACH() + ENDIF() +ENDMACRO() + +MACRO(NGL_INSTALL_TARGET _target_NAME) + SET(_args ${ARGN}) + LIST(LENGTH _args len) + IF(${len} EQUAL 0) + SET(_args ${INSTALL_DEFAULT_ARGS}) + ENDIF() + _NGL_INSTALL_TARGET_internal(${_target_NAME} ${_args}) +ENDMACRO() + +MACRO(NGL_INSTALL_TARGET_DEVEL _target_NAME) + IF (NOT BUILD_RPM) + SET(_args ${ARGN}) + LIST(LENGTH _args len) + IF(${len} EQUAL 0) + SET(_args ${INSTALL_DEFAULT_ARGS_DEVEL}) + ENDIF() + _NGL_INSTALL_TARGET_internal(${_target_NAME} ${_args}) + ENDIF() +ENDMACRO() + +MACRO(NGL_INSTALL) + SET(_args ${ARGN}) + + NGL_GET_BUILDPARTS(_args _buildopts) + + FOREACH(_component ${_components}) + LIST(FIND _buildopts ${_component} _idx) + IF(_idx GREATER -1) + SET(_my_args ${_args}) + NGL_ADD_INSTALL_PREFIX_INTERNAL(_my_args ${${_component}_INSTALL_PATH}) + INSTALL(${_my_args}) + ENDIF() + ENDFOREACH() + +ENDMACRO() + +MACRO(NGL_SET_TARGET_PROPERTIES _target_NAME) + IF(TARGET ${_target_NAME}) + SET_TARGET_PROPERTIES(${_target_NAME} ${ARGN}) + ENDIF() +ENDMACRO() + +MACRO(NGL_TARGET_COMPILE_DEFINITIONS _target_NAME) + IF(TARGET ${_target_NAME}) + TARGET_COMPILE_DEFINITIONS(${_target_NAME} ${ARGN}) + ENDIF() +ENDMACRO() + +MACRO(NGL_ADD_COMPILE_FLAGS _target_NAME _property_value) + IF(TARGET ${_target_NAME}) + + SET_PROPERTY(TARGET ${_target_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_property_value}") + ENDIF() +ENDMACRO() + +MACRO(NGL_ADD_TEST) + IF(TARGET ${_target_NAME}) + ADD_TEST(${_target_NAME} ${ARGN}) + ENDIF() +ENDMACRO() + +MACRO(NGL_CREATE_ASSISTANT_HELP type target_name language) + + SET(_QHP_FILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${language}.qhp") + SET(_QHP_FILE_BLD "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qhp") + SET(_QCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qch") + SET(_QHCP_FILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${language}.qhcp") + SET(_QHCP_FILE_BLD "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qhcp") + SET(_QHC_FILE "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qhc") + + SET(_file_list ${ARGN}) + + SET(_command_qhg qhelpgenerator-qt5) + SET(_command_qcg qcollectiongenerator-qt5) + + ADD_CUSTOM_COMMAND(DEPENDS ${_file_list} ${_QHP_FILE_SRC} ${_QHCP_FILE_SRC} + COMMAND ${NGL_MODULE_DIR}/make_qt_help.py + ARGS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${language} ${language} ${_file_list} + COMMAND ${_command_qhg} + ARGS ${_QHP_FILE_BLD} -o ${_QCH_FILE} + COMMAND ${_command_qcg} + ARGS "${_QHCP_FILE_BLD}" -o "${_QHC_FILE}" + COMMAND ${CMAKE_COMMAND} + ARGS -E touch ${CMAKE_CURRENT_BINARY_DIR}/${language}_qch_dummy.c + OUTPUT "${_QHC_FILE}" + "${_QHCP_FILE_BLD}" + "${_QHP_FILE_BLD}" + "${_QCH_FILE}" + "${CMAKE_CURRENT_BINARY_DIR}/${language}_qch_dummy.c" + WORKING_DIRECTORY ${CMAKE_CURRENT_BUILD_DIR} + COMMENT "Generating Qt assistant help for language ${language}" + ) + + NGL_ADD_LIBRARY(${type} "${type}_${target_name}_${language}_qch_dummy" "${language}_qch_dummy") + NGL_INSTALL(${type} FILES "${_QCH_FILE}" "${_QHC_FILE}" DESTINATION help/${target_name}/) + +ENDMACRO() + +MACRO(NGL_ADD_TARGET_LINK targetName targetAbbr) + +IF(TARGET ${targetName}) + IF(NOT WIN32) + SET(cmake_operation create_symlink) + IF(WIN32) + SET(cmake_operation copy) + ENDIF(WIN32) + ADD_CUSTOM_COMMAND(TARGET ${targetName} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove -f ${targetAbbr} + COMMAND ${CMAKE_COMMAND} -E ${cmake_operation} ${targetName} ${targetAbbr} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin + ) + ENDIF() +ENDIF() +ENDMACRO() + + +MACRO(ADD_INTERFACE_LIBRARY name_ header_ inc_path_) + SET(link_libs_ ${ARGN}) + ADD_LIBRARY(${name_} INTERFACE) + TARGET_INCLUDE_DIRECTORIES(${name_} + INTERFACE + ${inc_path_} + ) + FOREACH(link_lib_ ${link_libs_}) + TARGET_LINK_LIBRARIES(${name_} + INTERFACE + ${link_lib_} + ) + ENDFOREACH() + TARGET_SOURCES(${name_} INTERFACE ${header_}) +ENDMACRO() + + +macro(NGL_COMPILE_RESOURCES output_qrc_objects) + + + get_property(ipo_active VARIABLE PROPERTY CMAKE_INTERPROCEDURAL_OPTIMIZATION) + if(CMAKE_VERSION VERSION_GREATER 3.8.99 AND Qt5Core_VERSION VERSION_GREATER 5.12.99 AND NOT WIN32 AND NOT ipo_active) + set(_QT5_INTERNAL_SCOPE ON) + + set(options) + set(oneValueArgs) + set(multiValueArgs OPTIONS) + cmake_parse_arguments(_NGL_COMPILE_RESOURCES "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(qrc_files ${_NGL_COMPILE_RESOURCES_UNPARSED_ARGUMENTS}) + set(rcc_options ${_NGL_COMPILE_RESOURCES_OPTIONS}) + + foreach(qrc_file ${qrc_files}) + get_filename_component(qrc_object_file ${qrc_file} NAME_WE) + get_filename_component(qrc_filename ${qrc_file} ABSOLUTE) + set(qrc_header_file ${CMAKE_CURRENT_BINARY_DIR}/qrc_${qrc_object_file}_header.cpp) + set(qrc_object ${CMAKE_CURRENT_BINARY_DIR}/qrc_${qrc_object_file}.o) + + _qt5_parse_qrc_file(${qrc_filename} _out_depends _rc_depends) + set_source_files_properties(${qrc_filename} PROPERTIES SKIP_AUTORCC ON) + add_custom_command(OUTPUT ${qrc_header_file} + COMMAND echo ">>> 1: Regenerating ${qrc_header_file}" + COMMAND ${Qt5Core_RCC_EXECUTABLE} ${rcc_options} --name ${qrc_object_file} --pass 1 --output ${qrc_header_file} ${qrc_filename} + DEPENDS ${qrc_filename} ${_rc_depends} "${_out_depends}" + VERBATIM) + + add_custom_target(resources_${qrc_object_file} ALL DEPENDS ${qrc_header_file}) + add_library(qrc_object_${qrc_object_file} OBJECT ${qrc_header_file}) + add_dependencies(qrc_object_${qrc_object_file} resources_${qrc_object_file}) + + set_target_properties(qrc_object_${qrc_object_file} PROPERTIES AUTOMOC OFF) + set_target_properties(qrc_object_${qrc_object_file} PROPERTIES AUTOUIC OFF) + + add_custom_command(OUTPUT ${qrc_object} + COMMAND echo ">>> 2: Regenerating ${qrc_object} with $" + COMMAND ${Qt5Core_RCC_EXECUTABLE} + ARGS ${rcc_options} --name ${qrc_object_file} --pass 2 --temp $ --output ${qrc_object} ${qrc_filename} + DEPENDS qrc_object_${qrc_object_file} ${qrc_filename} ${qrc_header_file} + VERBATIM) + + list(APPEND ${output_qrc_objects} ${qrc_object}) + endforeach() + else() + + QT5_ADD_RESOURCES(${output_qrc_objects} ${ARGN}) + endif() +endmacro() + + +MACRO(NGL_ADD_BIG_RESOURCES) + + + GET_PROPERTY(ipo_active VARIABLE PROPERTY CMAKE_INTERPROCEDURAL_OPTIMIZATION) + IF(CMAKE_VERSION VERSION_GREATER 3.8.99 AND Qt5Core_VERSION VERSION_GREATER 5.12.99 AND NOT WIN32 AND NOT ipo_active) + QT5_ADD_BIG_RESOURCES(${ARGN}) + ELSE() + QT5_ADD_RESOURCES(${ARGN}) + ENDIF() +ENDMACRO() + + + + +MACRO(NGL_WRAP_UI) + QT5_WRAP_UI(${ARGN}) +ENDMACRO() + +MACRO(NGL_ADD_APP_ICON_INTERNAL _srcs icon) + IF(WIN32) + SET(_rc_file ${CMAKE_CURRENT_BINARY_DIR}/${target}_icon.rc) + FILE(WRITE ${_rc_file} "IDI_ICON1 ICON DISCARDABLE \"${icon}\"\n") + LIST(APPEND ${target} ${_rc_file}) + SET_SOURCE_FILES_PROPERTIES(${_rc_file} PROPERTIES OBJECT_DEPENDS ${icon}) + LIST(APPEND ${_srcs} ${_rc_file}) + ENDIF() +ENDMACRO() + +MACRO(NGL_ADD_APP_ICON target) + NGL_ADD_APP_ICON_INTERNAL(${target} "${CMAKE_SOURCE_DIR}/Lts/Common/LtsWidgets/resources/rde_icon_256.ico") +ENDMACRO() + +MACRO(NGL_ADD_SVC_ICON target) + NGL_ADD_APP_ICON_INTERNAL(${target} "${CMAKE_SOURCE_DIR}/Lts/Common/LtsWidgets/resources/rde_icon_256.ico") +ENDMACRO() + +MACRO(NGL_ADD_TOOL_ICON target) + SET(_args ${ARGN}) + LIST(LENGTH _args len) + SET(_ico "rde_logo.ico") + IF (len EQUAL 1) + LIST(GET _args 0 _tool) + SET(_ico "rde_internal_${_tool}_logo_256x256.ico") + ENDIF() + NGL_ADD_APP_ICON_INTERNAL(${target} "${CMAKE_SOURCE_DIR}/Lts/Common/LtsWidgets/resources/${_ico}") +ENDMACRO() + + +macro(NGL_TEST_APPS_JSON target) + if(NOT BUILD_RPM AND TARGET ${target}) + add_custom_command( + TARGET ${target} + PRE_BUILD + COMMAND $ + ARGS ${CMAKE_CURRENT_SOURCE_DIR} resources/apps.json + VERBATIM) + + if(jsonschema) + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND jsonschema + ARGS -i ${CMAKE_CURRENT_SOURCE_DIR}/resources/apps.json ${CMAKE_CURRENT_SOURCE_DIR}/../apps.schema.json + VERBATIM) + endif() + endif() +endmacro() diff --git a/cmake/make_qt_help.py b/cmake/make_qt_help.py new file mode 100755 index 000000000..4c93fb9fc --- /dev/null +++ b/cmake/make_qt_help.py @@ -0,0 +1,186 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + + + + +import os +import shutil +import sys +import sgmllib + + + +class MyParser(sgmllib.SGMLParser): + "A simple parser class." + + def __init__(self, verbose=0): + "Initialise an object, passing 'verbose' to the superclass." + + sgmllib.SGMLParser.__init__(self, verbose) + self.hyperlinks = [] + self.descriptions = [] + self.depths = [] + self.inside_a_element = 0 + self.inside_li_element = 0 + self.current_description = "" + self.current_hyperlink = "" + self.current_ul_depth = 0 + self.current_li_data = "" + + def parse(self, string): + "Parse the given string 'string'." + self.feed(string) + self.close() + + def start_a(self, attributes): + "Process a hyperlink and its 'attributes'." + + self.current_hyperlink = "" + self.current_description = "" + self.inside_a_element = 1 + for name, value in attributes: + if name == "href": + self.current_hyperlink = value + + def end_a(self): + "Record the end of a hyperlink" + + self.inside_a_element = 0 + + def start_ul(self, attributes): + "
    " + self.current_ul_depth += 1 + + def end_ul(self): + "
" + self.current_ul_depth -= 1 + + def start_li(self, attributes): + "
  • " + self.inside_li_element = 1 + self.current_description = "" + self.current_hyperlink = "" + + def end_li(self): + "
  • " + self.inside_li_element = 0 + if len(self.current_description) == 0: + self.descriptions.append(self.current_li_data) + self.hyperlinks.append(self.current_hyperlink) + self.depths.append(self.current_ul_depth) + + def handle_data(self, data): + "Handle the textual 'data'" + + if self.inside_a_element: + self.descriptions.append(data) + self.hyperlinks.append(self.current_hyperlink) + self.depths.append(self.current_ul_depth) + + self.current_description = data + + if self.inside_li_element: + self.current_li_data = data + + def get_xml(self, spacecount, prefix): + "return the structure as xml" + ret = "" + basespaces = ' ' * spacecount + for i, val in enumerate( self.descriptions ): + depth = self.depths[i] + + nextdepth = self.depths[0] + if i != len(self.descriptions) - 1: + nextdepth = self.depths[i+1] + end = '/>' + if depth < nextdepth: + end = '>' + ref = "" + if len(self.hyperlinks[i]) > 0: + ref += ' ref="%s/%s"' % ( prefix, self.hyperlinks[i] ) + spaces = basespaces + ' ' * depth + ret += '%s
    nextdepth: + spaces = basespaces + ' ' * (depth - 1) + ret += '%s
    \n' % spaces + depth -= 1 + return ret + +def removeDir(dirname): + "remove dir 'dirname' and all it's subdirectories" + for name in os.listdir(dirname): + filename = os.path.join(dirname, name) + if not os.path.islink(filename) and os.path.isdir(filename): + removeDir(filename) + else: + os.remove(filename) + os.rmdir(dirname) + return + +def main(): + if len(sys.argv) < 4: + print >> sys.stderr, "To few arguments: %s []" % sys.argv[0] + sys.exit(1) + srcdir = sys.argv[1] + blddir = sys.argv[2] + lang = sys.argv[3] + files = sys.argv[4:] + files.sort() + + if os.path.exists( blddir ): + removeDir( blddir ) + os.makedirs( blddir ) + + menu_toc = '' + files_string = '' + for filename in files: + files_string += '%s\n' % filename + if filename.endswith( 'menu.html' ): + try: + f = open( os.path.join( srcdir, filename ), 'r' ) + except IOError: + continue + parser = MyParser() + parser.parse( f.read() ) + menu_toc = parser.get_xml(13, lang) + + + qhp_file_src = os.path.join( srcdir, lang + '.qhp' ) + qhp_file_bld = os.path.join( blddir, lang + '.qhp' ) + infile = open( qhp_file_src, "r" ) + outfile = open( qhp_file_bld, "w" ) + for line in infile: + line = line.replace( "@FILES@", files_string ).replace( "@MENU_TOC@", menu_toc ) + outfile.write(line) + infile.close() + outfile.close() + + + qhcp_file_src = os.path.join( srcdir, lang + '.qhcp' ) + qhcp_file_bld = os.path.join( blddir, lang + '.qhcp' ) + shutil.copy( qhcp_file_src, qhcp_file_bld ) + + + for filename in files: + src = os.path.join( srcdir, filename ) + dst = os.path.join( blddir, filename ) + if not os.path.exists( src ): + print >> sys.stderr, "Source file %s does not exist - skipping" % src + continue + + if ( os.path.exists( dst ) and os.path.isfile( dst ) ) and\ + ( os.path.getsize( src ) == os.path.getsize( dst ) ) and\ + ( os.stat( src ).st_mtime <= os.stat( dst ).st_mtime ): + continue + + dstdir = os.path.dirname( dst ) + if not os.path.isdir( dstdir ): + + if os.path.exists( dstdir ): + os.remove( dstdir ) + os.makedirs( dstdir ) + shutil.copy( src, dst ) + +if __name__ == "__main__": + main() diff --git a/cmake/ngl_dep_test_main.cpp b/cmake/ngl_dep_test_main.cpp new file mode 100755 index 000000000..474486e44 --- /dev/null +++ b/cmake/ngl_dep_test_main.cpp @@ -0,0 +1,5 @@ +int main(int, char**) +{ + return 0; +} +