Qt6 migration: build fixes for Groups 10/11 + missing plugin modules
Continue the Qt5->Qt6 migration so the LTS Projects (Group 10) and LTS
Application (Group 11) compile, link, and ctest runs.
Qt5->Qt6 API migration (resolves removed/deprecated Qt6 APIs) across Lts
Tools and Apps, e.g. QAction->QActionGroup, QAbstractSocket::errorOccurred,
Qt::SkipEmptyParts, QRandomGenerator, QInputDevice::DeviceType,
QRegularExpression, QLatin1Literal->QStringLiteral, and the SampleModel
m_description->description rename.
CMake build fixes:
- CMakeLists.txt: add Lts/Common to CMAKE_AUTOMOC_INCLUDE_DIRECTORIES so moc
resolves Q_INTERFACES(ProjectPlugin::Plugin) for the migrated Projects.
- cmake/NGLMacros.cmake: NGL_COMPILE_RESOURCES - replace return() (which aborts
the calling CMakeLists.txt) with an if/else/endif.
- OpApp/THP: guard the ArcGISQt5Hack link with $<IF:$<TARGET_EXISTS:...>> (the
target is absent when the SituationMap viewer is stubbed); matches
CentralEffectSimulation.
- LtsSession: prefer the in-tree svcCoreClient target over a FIND_LIBRARY in
/usr/local/lib.
- CnrProxyTester/DotMatrixDisplay: set AUTOUIC_SEARCH_PATHS for the ui/ subdir.
- TopicDiscover: link NGLLogger.
Export-header visibility stubs (expand the empty *_EXPORT macro to
__attribute__((visibility("default"))); the build sets -fvisibility=hidden and
these stubs shadow the CMake-generated header):
- include/LtsProjectionWorkstation/ltsprojectionworkstation_export.h (fixes
undefined reference to LtsProjectionWorkstation::getInstance /
setProjectionOperatorPreset)
- include/LtsSession/ltssession_export.h, include/LtsUtilsGuiDds/ltsutilsguidds_export.h (same pattern)
New plugin modules (copied from legacy) so LtsAppDescriptorChecker finds the
gui:3 IIDs referenced by the Projects' apps.json:
- TakeHomePackageManager/OldTHP gui:3:tpm.man, gui:3:tpm.usb
- PresentationManagement/.../ScriptEditor gui:3:pre.script.edit
- Timeline/Gui/EventTimelineClassic gui:3:tln.view
new_docker_build.sh: correct group targets to the actual CMake target names,
guard LtsReportDisplay on BUILD_CODIFICATION, and skip modules unavailable in
the prebuilt image (AsmWorkstationCertifier/botan2, TrajectoryWidget,
VideoImport, thp_viewer/VLC).
This commit is contained in:
1 parent
040bdd558f
commit
3f7beb3c7e
154 files changed
+24958
-167
No files matched your search
@@ -676,6 +676,16 @@ IF(BUILD_RTI)
|
||||
# the AutogenInfo MOC_INCLUDES.
|
||||
SET(CMAKE_AUTOMOC_INCLUDE_DIRECTORIES ${CMAKE_AUTOMOC_INCLUDE_DIRECTORIES} ${CMAKE_SOURCE_DIR}/include/Viewer/SituationMap/ElevationMap)
|
||||
|
||||
# The migrated Projects declare Q_INTERFACES(ProjectPlugin::Plugin) and include
|
||||
# <PluginInterfaces/project_plugin_interface.h>. That include dir
|
||||
# (Lts/Common/PluginInterfaces/..) is only a target-level PUBLIC include of
|
||||
# ProjectPluginInterface and is NOT part of the global include_directories that
|
||||
# reach the AutogenInfo MOC_INCLUDES, so moc fails with "Undefined interface".
|
||||
# Add the Lts/Common root explicitly (mirrors the Lts append above) so moc can
|
||||
# resolve the interface. Must be set at root scope - subdir appends do not
|
||||
# reach the AutogenInfo MOC_INCLUDES.
|
||||
SET(CMAKE_AUTOMOC_INCLUDE_DIRECTORIES ${CMAKE_AUTOMOC_INCLUDE_DIRECTORIES} ${CMAKE_SOURCE_DIR}/Lts/Common)
|
||||
|
||||
# IMPORTED Targets für RTI Libraries erstellen
|
||||
# Debug und Release Varianten korrekt konfigurieren
|
||||
FOREACH(lib nddsc nddscore nddscpp nddscpp2 nddsctesthelpers)
|
||||
|
||||
@@ -56,13 +56,13 @@ bool DatabasesModel::initModel(const QSqlDatabase &db)
|
||||
}
|
||||
|
||||
Exercise exercise;
|
||||
exercise.m_id = q.value(0).toInt();
|
||||
exercise.id = q.value(0).toInt();
|
||||
exercise.name = q.value(1).toString();
|
||||
exercise.startTime = q.value(2).toLongLong();
|
||||
exercise.endTime = q.value(3).toLongLong();
|
||||
exercise.dbName = QStringLiteral("lts_db_") + QString::number(exercise.m_id);
|
||||
exercise.dbName = QStringLiteral("lts_db_") + QString::number(exercise.id);
|
||||
exercise.stateId = q.value(4).toInt();
|
||||
TRACE_LOG(m_logger) << "Found exercise with id=" << exercise.m_id << ", name=" << exercise.name << ", startTime="
|
||||
TRACE_LOG(m_logger) << "Found exercise with id=" << exercise.id << ", name=" << exercise.name << ", startTime="
|
||||
<< exercise.startTime << ", endTime=" << exercise.endTime << ", dbName=" << exercise.dbName
|
||||
<< ", stateId=" << exercise.stateId;
|
||||
if (exercise.stateId != 6)
|
||||
@@ -86,7 +86,7 @@ QVariant DatabasesModel::data(const QModelIndex &index, int role) const
|
||||
switch (index.column())
|
||||
{
|
||||
case Id:
|
||||
return e.m_id;
|
||||
return e.id;
|
||||
case Name:
|
||||
return QString(e.name);
|
||||
case StartTime:
|
||||
@@ -176,7 +176,7 @@ void DatabasesModel::onDataChanged(const Exercise &data, DataModification modTyp
|
||||
row = m_vecData.indexOf(data);
|
||||
if (row != -1)
|
||||
if (removeRow(row))
|
||||
emit dataChanged(index(std::min(row, m_vecData.size()-1), Columns::Id), index(m_vecData.size()-1, Columns::EndTime));
|
||||
emit dataChanged(index(std::min<qsizetype>(row, m_vecData.size() - 1), Columns::Id), index(m_vecData.size()-1, Columns::EndTime));
|
||||
return;
|
||||
} // switch
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ struct Exercise
|
||||
qint64 endTime = 0;
|
||||
qint32 stateId = 0;
|
||||
|
||||
bool operator == (const Exercise &other) { return id == other.m_id; }
|
||||
bool operator != (const Exercise &other) { return id != other.m_id; }
|
||||
bool operator == (const Exercise &other) const { return id == other.id; }
|
||||
bool operator != (const Exercise &other) const { return id != other.id; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ ENDIF()
|
||||
|
||||
if(QT6_GUI_AVAILABLE)
|
||||
NGL_TARGET_LINK_LIBRARIES(OperatorApplication
|
||||
ArcGISQt5Hack # make sure it's loaded *before* libEsriCommonQt.so
|
||||
$<IF:$<TARGET_EXISTS:ArcGISQt5Hack>,ArcGISQt5Hack,> # make sure it's loaded *before* libEsriCommonQt.so (guard: only linked when the SituationMap viewer is built, matching CentralEffectSimulation)
|
||||
${Qt6_Widgets}
|
||||
Qt6::Network
|
||||
nglapplication
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#include <QInputDialog>
|
||||
#include <QNetworkProxy>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QRandomGenerator>
|
||||
#include <QInputDevice>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
@@ -157,7 +160,7 @@ public:
|
||||
bool isForcedTabletMode() const { return isSet(QStringLiteral("x")); }
|
||||
bool isForcedWSMode() const { return isSet(QStringLiteral("w")); }
|
||||
QString langIsoCode() const { return value(QStringLiteral("l")); }
|
||||
QStringList ignoredPlugins() const { return value(QStringLiteral("ignore-plugins")).split(QLatin1Char(','), QString::SkipEmptyParts); }
|
||||
QStringList ignoredPlugins() const { return value(QStringLiteral("ignore-plugins")).split(QLatin1Char(','), Qt::SkipEmptyParts); }
|
||||
bool checkRequirements() const { return isSet(QStringLiteral("check-requirements")); }
|
||||
QString skipScreen() const { return value(QStringLiteral("k")); }
|
||||
QString qosFile() const { return value(QStringLiteral("q")).size() > 0 ? value(QStringLiteral("q")) : QString(); }
|
||||
@@ -172,7 +175,7 @@ public:
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv) // TODO: json strings to lower
|
||||
{
|
||||
qsrand(time(nullptr));
|
||||
QRandomGenerator::global()->seed(time(nullptr));
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||
|
||||
@@ -380,7 +383,7 @@ int main(int argc, char **argv) // TODO: json strings to lower
|
||||
|
||||
if (!skipScreen.isEmpty())
|
||||
{
|
||||
QStringList skipScreenList(skipScreen.split(QLatin1Char('.'), QString::SkipEmptyParts));
|
||||
QStringList skipScreenList(skipScreen.split(QLatin1Char('.'), Qt::SkipEmptyParts));
|
||||
|
||||
int skipScreenListCount = skipScreenList.count();
|
||||
|
||||
@@ -431,7 +434,8 @@ int main(int argc, char **argv) // TODO: json strings to lower
|
||||
sessionData->setAsTablet();
|
||||
else if (options.isForcedWSMode())
|
||||
sessionData->setAsTablet(false);
|
||||
else if (!QTouchDevice::devices().isEmpty())
|
||||
else if (std::any_of(QInputDevice::devices().cbegin(), QInputDevice::devices().cend(),
|
||||
[](const QInputDevice *dev) { return dev && dev->type() == QInputDevice::DeviceType::TouchScreen; }))
|
||||
sessionData->setAsTablet();
|
||||
LtsWidgets::LtsComboBox::setUseSelectionDialog(sessionData->isTablet());
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ NGL_TARGET_COMPILE_DEFINITIONS(thp_viewer
|
||||
${VLC_DEFINES}
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(thp_viewer
|
||||
ArcGISQt5Hack # make sure it's loaded *before* libEsriCommonQt.so
|
||||
$<IF:$<TARGET_EXISTS:ArcGISQt5Hack>,ArcGISQt5Hack,> # make sure it's loaded *before* libEsriCommonQt.so (guard: only linked when the SituationMap viewer is built, matching CentralEffectSimulation)
|
||||
|
||||
${VLC_LIBRARIES}
|
||||
Qt6::Core
|
||||
|
||||
@@ -258,8 +258,9 @@ void ThpViewer::onLinkClicked(const QUrl &url)
|
||||
const QString path = url.path();
|
||||
const QString lpath = path.toLower();
|
||||
|
||||
const QStringRef ext = lpath.splitRef(QLatin1Char('.')).last();
|
||||
const QStringRef ext2Chars = ext.left(2);
|
||||
// Qt6: QStringRef/QString::splitRef were removed; QStringView::split provides zero-copy access
|
||||
const QStringView ext = QStringView{lpath}.split(QLatin1Char('.')).last();
|
||||
const QStringView ext2Chars = ext.left(2);
|
||||
|
||||
ui->audioWidget->stop();
|
||||
ui->videoWidget->stop();
|
||||
@@ -370,7 +371,7 @@ void ThpViewer::onLinkClicked(const QUrl &url)
|
||||
ui->backButton->setEnabled(true);
|
||||
}
|
||||
else if (ext == QLatin1String("html") &&
|
||||
lpath.midRef(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
|
||||
QStringView{lpath}.mid(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
|
||||
{
|
||||
// Kombiniert
|
||||
QHash<QString, QUrl> urls = getCombinedPlaybackDetails(url);
|
||||
|
||||
@@ -32,10 +32,11 @@ public:
|
||||
bool needsToBeOpenedExternally(const QUrl &url)
|
||||
{
|
||||
const QString lpath = url.toString();
|
||||
const QStringRef ext = lpath.splitRef(QLatin1Char('.')).last();
|
||||
const QStringRef ext2Chars = ext.left(2);
|
||||
// Qt6: QStringRef/QString::splitRef and QString::midRef were removed; use QStringView
|
||||
const QStringView ext = QStringView{lpath}.split(QLatin1Char('.')).last();
|
||||
const QStringView ext2Chars = ext.left(2);
|
||||
if (ext == QLatin1String("html") &&
|
||||
lpath.midRef(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
|
||||
QStringView{lpath}.mid(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
|
||||
return true;
|
||||
// PDF
|
||||
if (ext == QLatin1String("pdf"))
|
||||
|
||||
@@ -140,7 +140,7 @@ void LtsAppManager::slotStartDebugServer()
|
||||
QString commandStr(
|
||||
QString::fromUtf8(client->readLine(100)).remove(QStringLiteral("\r")).remove(QStringLiteral("\n")));
|
||||
|
||||
QStringList argList = commandStr.split(QLatin1Char(' '), QString::SplitBehavior::SkipEmptyParts);
|
||||
QStringList argList = commandStr.split(QLatin1Char(' '), Qt::SkipEmptyParts);
|
||||
|
||||
if (argList.count() < 1)
|
||||
return;
|
||||
|
||||
@@ -16,7 +16,7 @@ LogoutInformationDialog::LogoutInformationDialog(int timeOut, AssetManagement::S
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
QString actionText;
|
||||
switch (shutdownAction.underlying())
|
||||
switch (shutdownAction)
|
||||
{
|
||||
case AssetManagement::ShutdownAction::NoAction:
|
||||
case AssetManagement::ShutdownAction::Logout:
|
||||
|
||||
@@ -154,13 +154,13 @@ void LtsLogin::slotLogoutShutdown(const AssetManagement::WorkstationLogout& data
|
||||
|
||||
if (!m_asmDtc->isAssetEnabled())
|
||||
m_asmDtc->enableAsset();
|
||||
for (int id : data.ids())
|
||||
for (int id : data.ids)
|
||||
{
|
||||
if (QString::fromStdString(m_asmDtc->asset(id).name())
|
||||
if (QString::fromStdString(m_asmDtc->asset(id).name)
|
||||
.compare(LtsSession::LtsSession::workstationName(), Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
m_isInLogoutDialog = true;
|
||||
showLogoutInformationDialog(data.shutdownAction());
|
||||
showLogoutInformationDialog(data.shutdownAction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,7 @@ void LtsLogin::logoff()
|
||||
m_loginApp = nullptr;
|
||||
|
||||
QString cmd;
|
||||
switch (m_shutdownAction.underlying())
|
||||
switch (m_shutdownAction)
|
||||
{
|
||||
case AssetManagement::ShutdownAction::Shutdown:
|
||||
#ifdef LTS_DEBUG
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace LtsPluginManager
|
||||
|
||||
LtsPluginManager::LtsPluginManager()
|
||||
: m_sessionManager(new LtsSession::LtsSessionManager)
|
||||
.getNGLLogger("LtsPluginManager"))
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("LtsPluginManager"))
|
||||
, m_markedForDeletion(false)
|
||||
{
|
||||
connect(m_sessionManager, &LtsSession::LtsSessionManager::signalQuit, this, &LtsPluginManager::signalQuit);
|
||||
|
||||
@@ -79,7 +79,14 @@ NGL_TARGET_INCLUDE_DIRECTORIES(LtsSession
|
||||
)
|
||||
|
||||
# Optional external dependencies
|
||||
FIND_LIBRARY(SVCCORECLIENT_LIBRARY NAMES svcCoreClient PATHS /usr/local/lib /usr/lib NO_DEFAULT_PATH)
|
||||
# Prefer the in-tree target: a fresh build tree does not have svcCoreClient
|
||||
# installed in /usr/local/lib, and the Core::Interface::Ftc::create symbols
|
||||
# referenced at link time live in libsvcCoreClient.so
|
||||
IF(TARGET svcCoreClient)
|
||||
SET(SVCCORECLIENT_LIBRARY svcCoreClient)
|
||||
ELSE()
|
||||
FIND_LIBRARY(SVCCORECLIENT_LIBRARY NAMES svcCoreClient PATHS /usr/local/lib /usr/lib NO_DEFAULT_PATH)
|
||||
ENDIF()
|
||||
FIND_LIBRARY(OHPONLINEHELP_LIBRARY NAMES OhpOnlineHelpViewerGuiPluginInterface PATHS /usr/local/lib /usr/lib NO_DEFAULT_PATH)
|
||||
|
||||
SET(LtsSession_PRIVATE_LIBS
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLSE, 2016-03-17
|
||||
#
|
||||
|
||||
SET(pre_script_gui_SRCS
|
||||
pre_script_gui_plugin.cpp
|
||||
pre_script_gui_plugin.h
|
||||
pre_script_dialog.h
|
||||
pre_script_dialog.cpp
|
||||
pre_storyboard.cpp
|
||||
pre_storyboard.h
|
||||
pre_journal_types.h
|
||||
pre_journal_types.cpp
|
||||
pre_journal_dialog.h
|
||||
pre_journal_dialog.cpp
|
||||
pre_screen.h
|
||||
pre_screen.cpp
|
||||
filter_topic.h
|
||||
filter_topic.cpp
|
||||
)
|
||||
|
||||
QT5_WRAP_UI(pre_script_gui_SRCS
|
||||
pre_storyboard.ui
|
||||
pre_script_dialog.ui
|
||||
pre_journal_dialog.ui
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(WS PreScriptGuiPlugin MODULE ${pre_script_gui_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(PreScriptGuiPlugin
|
||||
NGLLogger
|
||||
LtsSession
|
||||
PreDataPluginInterface
|
||||
PrePresentationGuiPluginInterface
|
||||
PreGuiCommon
|
||||
PreGuiScriptCommon
|
||||
svcPreCommon
|
||||
Qt5::Widgets
|
||||
LtsWidgets
|
||||
LtsDataView
|
||||
LtsUtilsGuiDds
|
||||
LtsSessionData
|
||||
ProjectConfig
|
||||
LtsScriptTimeline
|
||||
LtsMultiMonitor
|
||||
|
||||
LtsAppManager # start replay app
|
||||
LtsSessionData # set partition preset for replay app
|
||||
TopicEditorInterface
|
||||
TopicEditorBase
|
||||
LtsPluginManager # manipulate apps
|
||||
|
||||
# for Topics
|
||||
EvlGuiPluginInterface
|
||||
|
||||
|
||||
SrmDataPluginInterface # start playback
|
||||
LtsPrinting
|
||||
SituationMapGuiPluginInterface
|
||||
|
||||
# Script Player Controls:
|
||||
SrpGuiPluginInterface
|
||||
|
||||
# file topic
|
||||
FlmExplorerGuiPluginInterface
|
||||
# building topic
|
||||
BdvViewerGuiPluginInterface
|
||||
# report topic
|
||||
RepGuiPluginInterface
|
||||
LtsReportDisplay
|
||||
MrkCommon # for ApplyFilter @ SitmapFilter
|
||||
LtsUtilsSettings
|
||||
ngltools # DTG
|
||||
situationMap # set time string on map
|
||||
ExportBdvTopicSetting
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(PreScriptGuiPlugin)
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#include "filter_topic.h"
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
FilterTopic::~FilterTopic()
|
||||
{
|
||||
//delete filterTopic;
|
||||
}
|
||||
|
||||
|
||||
FilterTopic::FilterTopic(const FilterTopic &other)
|
||||
{
|
||||
mainTopicId = other.mainTopicId;
|
||||
filterTopic = other.filterTopic;//new LtsScriptTimeline::TrackEntry(other.filterTopic);
|
||||
}
|
||||
} // namespace PresentationManagement
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
class FilterTopic
|
||||
{
|
||||
public:
|
||||
FilterTopic()
|
||||
: mainTopicId(-1)
|
||||
, filterTopic(nullptr)
|
||||
{}
|
||||
|
||||
FilterTopic(int _mainTopicId, LtsScriptTimeline::TrackEntry *_filterTopic)
|
||||
: mainTopicId(_mainTopicId)
|
||||
, filterTopic(_filterTopic)
|
||||
{}
|
||||
|
||||
FilterTopic(const FilterTopic &other);
|
||||
|
||||
~FilterTopic();
|
||||
|
||||
int mainTopicId;
|
||||
LtsScriptTimeline::TrackEntry *filterTopic;
|
||||
};
|
||||
} // namespace PresentationManagement
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#include "pre_journal_dialog.h"
|
||||
#include "ui_pre_journal_dialog.h"
|
||||
|
||||
#include <LtsPrinting/printing.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
JournalDialog::JournalDialog(LtsSession::LtsSession *session, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent)
|
||||
, m_ui(new Ui::JournalDialog)
|
||||
, m_journal(nullptr)
|
||||
, m_session(session)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &JournalDialog::slotPrint);
|
||||
}
|
||||
|
||||
|
||||
JournalDialog::~JournalDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void JournalDialog::slotPrint()
|
||||
{
|
||||
LtsPrinting::printView(m_session, this, m_ui->listWidget);
|
||||
}
|
||||
|
||||
|
||||
bool JournalDialog::init(MainJournal *journal)
|
||||
{
|
||||
m_journal = journal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void JournalDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Script Journal"));
|
||||
fillJournal();
|
||||
}
|
||||
|
||||
|
||||
void JournalDialog::fillJournal()
|
||||
{
|
||||
m_ui->listWidget->clear();
|
||||
|
||||
if (!m_journal)
|
||||
return;
|
||||
|
||||
m_ui->listWidget->addItem(m_journal->getText());
|
||||
for (const Journal *j : qAsConst(m_journal->journalList))
|
||||
m_ui->listWidget->addItem(j->getText());
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "pre_journal_types.h"
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class JournalDialog;
|
||||
}
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class JournalDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit JournalDialog(LtsSession::LtsSession *session, QWidget *parent);
|
||||
~JournalDialog();
|
||||
bool init(MainJournal *journal);
|
||||
void retranslate() override final;
|
||||
|
||||
private slots:
|
||||
void slotPrint();
|
||||
|
||||
private:
|
||||
void fillJournal();
|
||||
|
||||
Ui::JournalDialog *m_ui;
|
||||
MainJournal *m_journal;
|
||||
LtsSession::LtsSession *m_session;
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>JournalDialog</class>
|
||||
<widget class="QWidget" name="JournalDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>707</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#include "pre_journal_types.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
QString ttt(qint64 msecsSinceEpoch)
|
||||
{
|
||||
return DTG::toStringMSec(msecsSinceEpoch);
|
||||
}
|
||||
|
||||
|
||||
QString pttt(int presentationTime)
|
||||
{
|
||||
return QTime::fromMSecsSinceStartOfDay(presentationTime * 1000).toString();
|
||||
}
|
||||
|
||||
|
||||
Journal::Journal()
|
||||
: m_started(QDateTime::currentMSecsSinceEpoch())
|
||||
{}
|
||||
|
||||
|
||||
QString Journal::started() const
|
||||
{
|
||||
return ttt(m_started);
|
||||
}
|
||||
|
||||
|
||||
MainJournal::~MainJournal()
|
||||
{
|
||||
qDeleteAll(journalList);
|
||||
}
|
||||
|
||||
|
||||
QString MainJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script Player started on %1").arg(ttt(started));
|
||||
}
|
||||
|
||||
|
||||
NextTopicJournal::NextTopicJournal(int presentationTime, bool isFilter, const QString &topicTypeName, int length)
|
||||
: Journal()
|
||||
, m_isFilter(isFilter)
|
||||
, m_topicTypeName(topicTypeName)
|
||||
, m_length(length)
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
|
||||
QString NextTopicJournal::getText() const
|
||||
{
|
||||
return Journal::tr("%1 '%2' started at %3 for %4 seconds on %5").arg(m_isFilter ? tr("FilterTopic") : tr("Topic"),
|
||||
m_topicTypeName, pttt(m_presentationTime)).arg(m_length).arg(started());
|
||||
}
|
||||
|
||||
|
||||
QString PlayJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Started / resumed script at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString PauseJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Paused script at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString EndedJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script ended at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString StopJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script stopped at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString SetTimeJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Position time set to %1 on %2").arg(pttt(m_toPresentationTime), started());
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class Journal
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Journal)
|
||||
|
||||
public:
|
||||
Journal();
|
||||
virtual ~Journal() = default;
|
||||
QString started() const;
|
||||
virtual QString getText() const = 0;
|
||||
qint64 m_started;
|
||||
};
|
||||
|
||||
|
||||
class MainJournal
|
||||
{
|
||||
public:
|
||||
~MainJournal();
|
||||
QString getText() const;
|
||||
|
||||
qint64 started = 0;
|
||||
QVector<Journal *> journalList;
|
||||
};
|
||||
|
||||
|
||||
class NextTopicJournal : public Journal
|
||||
{
|
||||
public:
|
||||
NextTopicJournal(int presentationTime, bool isFilter, /*int topicId, */const QString &topicTypeName, int length);
|
||||
QString getText() const override final;
|
||||
|
||||
bool m_isFilter;
|
||||
//int m_topicId;
|
||||
QString m_topicTypeName;
|
||||
int m_length;
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class PlayJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit PlayJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class PauseJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit PauseJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class EndedJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit EndedJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class StopJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit StopJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class SetTimeJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit SetTimeJournal(int toPresentationTime)
|
||||
: Journal()
|
||||
, m_toPresentationTime(toPresentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_toPresentationTime;
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
#include "pre_screen.h"
|
||||
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
|
||||
|
||||
Screen::Screen()
|
||||
: QWidget()
|
||||
{
|
||||
setBgColor(QColor("black"));
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
Screen::~Screen()
|
||||
{
|
||||
const auto p1Widgets = findChildren<QWidget *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
for (QWidget *w : p1Widgets)
|
||||
w->setParent(nullptr);
|
||||
}
|
||||
|
||||
|
||||
void Screen::setBgColor(const QColor &color)
|
||||
{
|
||||
setStyleSheet(QStringLiteral("Screen { background: %1; background-color: %1; }").arg(color.name()));
|
||||
}
|
||||
|
||||
|
||||
void Screen::paintEvent(QPaintEvent *) // needed to apply the style sheet...........
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
class Screen : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Screen();
|
||||
virtual ~Screen();
|
||||
|
||||
void setBgColor(const QColor &color);
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
};
|
||||
+3377
File diff suppressed because it is too large.
Load diff
+402
@@ -0,0 +1,402 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManagement - Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pre_screen.h"
|
||||
#include "pre_journal_types.h"
|
||||
#include "pre_storyboard.h" // QPointer
|
||||
#include "filter_topic.h"
|
||||
|
||||
#include <DDS/Core/core_dtc.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <LtsPluginManager/lts_plugin_manager.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <LtsScriptTimeline/track_entry_painters.h> // TET
|
||||
#include <LtsScriptTimeline/temporary_pointer_vector.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
#include <Services/PresentationManagement/pre_dtc.h>
|
||||
#include <Services/PresentationManagement/pre_ftc.h>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
#include <Services/SituationReplayManagement/srm_ftc.h>
|
||||
#include <Services/OperatorManagement/opm_dtc.h>
|
||||
|
||||
|
||||
// foreign gui plugins for the topic playback
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class ExportProcess;
|
||||
}
|
||||
namespace Ui
|
||||
{
|
||||
class ScriptDialog;
|
||||
}
|
||||
namespace LtsScriptTimeline
|
||||
{
|
||||
class TrackEntry;
|
||||
}
|
||||
namespace SituationReplayManagement
|
||||
{
|
||||
class ForeignDataInterface;
|
||||
}
|
||||
namespace LtsPluginManager
|
||||
{
|
||||
class LtsPluginManager;
|
||||
}
|
||||
namespace Ui
|
||||
{
|
||||
class ScriptPlayerDialog;
|
||||
}
|
||||
namespace LtsScriptTimeline
|
||||
{
|
||||
class TrackEntry;
|
||||
}
|
||||
namespace LtsUtils
|
||||
{
|
||||
class Promise;
|
||||
}
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
class TopicDesigner;
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Ftc;
|
||||
}
|
||||
|
||||
|
||||
class ScriptDialog : public LtsWidgets::LtsDialog
|
||||
, protected PresentationManagement::Interface::Ftc::PresentationModifyReplyHandler
|
||||
, protected PresentationManagement::Interface::Ftc::GetPresentationContentReplyHandler
|
||||
, protected SituationReplayManagement::Interface::Ftc::ReplayPartitionCreateReplyHandler
|
||||
, protected SituationReplayManagement::Interface::Ftc::ReplayPartitionRemoveReplyHandler
|
||||
{
|
||||
public:
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScriptDialog(const QString &menuGroup, QWidget *parent = nullptr);
|
||||
~ScriptDialog();
|
||||
|
||||
LtsSession::LtsSession *eVSession() { return m_essentialsViewSession; }
|
||||
|
||||
bool init(LtsSession::LtsSession *session,
|
||||
const int scriptId,
|
||||
const std::shared_ptr<Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<SituationReplayManagement::ForeignDataInterface> &srmForeign,
|
||||
const std::shared_ptr<Core::Interface::Dtc> &coreDtc,
|
||||
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc);
|
||||
|
||||
void loadScript();
|
||||
TopicEditorBase::TopicEditor *createTopic(const TopicAssignment &ta);
|
||||
TopicEditorBase::TopicEditor *createTopic(const LtsScriptTimeline::TrackEntry &data);
|
||||
void createTopicFromTrackEntry(LtsScriptTimeline::TrackEntry *data);
|
||||
|
||||
bool topicStringToType(const QString &typeName, LtsScriptTimeline::TrackEntryType &tet) const;
|
||||
int getCurrentScriptEndTime() const;
|
||||
bool isEssentialsViewOpened() const;
|
||||
|
||||
static LtsScriptTimeline::TrackEntry *trackEntryFromContent(const PresentationManagement::PresentationContent &content,
|
||||
int topicId,
|
||||
LtsScriptTimeline::TrackEntryType trackType);
|
||||
|
||||
bool importTrackEntries(const QVector<LtsScriptTimeline::TrackEntry *> &tes);
|
||||
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> getReplayGuiIfc() const
|
||||
{
|
||||
return m_essentialsViewsSrpGuiIfc;
|
||||
}
|
||||
|
||||
private:
|
||||
enum class ProjectionWidget
|
||||
{
|
||||
Unknown = 0,
|
||||
Screen1,
|
||||
Screen2,
|
||||
};
|
||||
|
||||
|
||||
enum class SpecialTopicType
|
||||
{
|
||||
NonSpecial = 0,
|
||||
ReplayTopic,
|
||||
FilterTopic,
|
||||
};
|
||||
|
||||
|
||||
class PlayingTopic
|
||||
{
|
||||
public:
|
||||
PlayingTopic() = default;
|
||||
|
||||
~PlayingTopic()
|
||||
{
|
||||
if (topicReplayIfc != nullptr)
|
||||
{
|
||||
topicReplayIfc->playbackStop();
|
||||
delete topicReplayIfc;
|
||||
}
|
||||
// if (replayWidget) HACK: FIXME: trading memory for security BUT dont delete if it's the situation map app's base layout !
|
||||
// delete replayWidget;
|
||||
}
|
||||
|
||||
QString topicTypeName;
|
||||
LtsScriptTimeline::TrackEntry *topic = nullptr;
|
||||
TopicReplay::Interface *topicReplayIfc = nullptr; // 1 instance per 1 currently playing topic
|
||||
QWidget *replayWidget = nullptr;
|
||||
LtsScriptTimeline::TrackEntryType trackEntryType = LtsScriptTimeline::TrackEntryType::INVALID;
|
||||
bool isFilter = false;
|
||||
};
|
||||
|
||||
|
||||
void onPresentationModifyReply(const Core::FunctionReplyObject &replyObject) override { if (m_requestHelper != nullptr) m_requestHelper->requestReply(replyObject); }
|
||||
void onGetPresentationContentReply(const GetPresentationContentReply &reply) override { if (m_requestHelper != nullptr) m_requestHelper->requestReply(reply); }
|
||||
void onReplayPartitionCreateReply(const Core::FunctionReplyObject &reply) override { if (m_requestHelper != nullptr) m_requestHelper->requestReply(reply); }
|
||||
void onReplayPartitionRemoveReply(const Core::FunctionReplyObject &) override { /* ignore */ }
|
||||
|
||||
void retranslate() override;
|
||||
bool apply() override;
|
||||
void aboutToClose() override;
|
||||
void getPresentationContent(); // tryAddTopics has to be called first to populate m_trackEntryAssignments
|
||||
TopicEditorBase::TopicEditor *createTopicEditor(LtsScriptTimeline::TrackEntry *te);
|
||||
bool topicTypeOnEssentialsView(LtsScriptTimeline::TrackEntryType tet) const;
|
||||
void startEssentialsViewStage2(const Core::ReplayPartition &replay);
|
||||
bool tryAddTopics(QStringList &resultList);
|
||||
void fillTopicVector();
|
||||
void createSitMapApp();
|
||||
void startReplaySession();
|
||||
void exportPresentationContent(const Core::FunctionReply &baseReply);
|
||||
void disableSessionDialog(LtsSession::LtsSession *pSession, bool disable);
|
||||
void deletePlayingTopic(PlayingTopic *playingTopic); // WARNING: use a mutable iterator while iterating over m_currentlyPlayingTopics and remove the entry before calling this method!
|
||||
static QString toReadableTime(qint64 seconds);
|
||||
ProjectionWidget identifyProjectionWidget(LtsScriptTimeline::TrackEntry *topic) const;
|
||||
bool usesAvsWindow(LtsScriptTimeline::TrackEntryType trackEntryType) const;
|
||||
void playTopic(LtsScriptTimeline::TrackEntry *topic);
|
||||
bool enableFireEventFlash(bool enable);
|
||||
void pausePlayingTopics();
|
||||
static bool isFilter(LtsScriptTimeline::TrackEntryType tet);
|
||||
void initProjectionWidget(Screen **pointerToWidgetPointer);
|
||||
void deleteProjectionWidget(Screen **pointerToWidgetPointer);
|
||||
bool _tryAddTopic(LtsScriptTimeline::TrackEntryType trackEntryType,
|
||||
const std::shared_ptr<TopicEditorBase::Interface> &topicEditorIfc,
|
||||
const std::shared_ptr<TopicReplay::Factory> &topicReplayFactory,
|
||||
const std::shared_ptr<TopicReplay::Factory> &topicExportFactory,
|
||||
QStringList &resultList,
|
||||
const SpecialTopicType &specialTopicType = SpecialTopicType::NonSpecial);
|
||||
void initFailed(int reason);
|
||||
void setFreestanding(bool freestanding, const ProjectionWidget &pw);
|
||||
void setReplayWidgetFreestanding(PlayingTopic *playingTopic, bool freestanding);
|
||||
void printCurrentlyPlayingTopics();
|
||||
void addReplayWidget(PlayingTopic *playingTopic, QWidget *replayWidget);
|
||||
Screen *getProjectionWidget(const ScriptDialog::ProjectionWidget &projectionWidget);
|
||||
bool isScreenFreestanding(const ProjectionWidget &pw) const;
|
||||
void previewSecond(int time, int ignoreTopicForReplay = -1);
|
||||
void setReplayWidgetPosition(PlayingTopic *playingTopic);
|
||||
void avsFreestandingHack(bool freestanding, QWidget *projectionWidget, QWidget **parentForScreen);
|
||||
void avsVisibilityHack(QWidget *parentForScreen, bool visible);
|
||||
void stop(bool ended = false, bool ignoreFireEventFlashing = false);
|
||||
void changelogCheck();
|
||||
int previousTopicTime() const;
|
||||
bool hasPreviousTopic() const { return previousTopicTime() > -1; }
|
||||
int nextTopicTime() const;
|
||||
bool hasNextTopic() const { return nextTopicTime() > -1; }
|
||||
void setPositionTime(int positionTime, bool setByUser = false);
|
||||
void setPositionTimeActive(int positionTime, bool setByUser = false); // setPositionTime, but, if playing, also ticks and resets timeout
|
||||
|
||||
|
||||
template <typename TopicEditorInterface>
|
||||
std::shared_ptr<TopicEditorBase::Interface> getTopicEditorIfc(LtsScriptTimeline::TrackEntryType trackEntryType)
|
||||
{
|
||||
std::shared_ptr<TopicEditorBase::Interface> topicEditorIfc;
|
||||
|
||||
if (!m_exerciseSession->interfaceFromGui<TopicEditorInterface>(topicEditorIfc))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getTopicEditorIfc failed: Cannot add topic type "
|
||||
<< LtsScriptTimeline::trackEntryTypeName(trackEntryType)
|
||||
<< " because topic editor ifc is missing.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return topicEditorIfc;
|
||||
}
|
||||
|
||||
|
||||
template <typename TopicReplayInterface>
|
||||
std::shared_ptr<TopicReplay::Factory> getTopicReplayFactory(LtsScriptTimeline::TrackEntryType trackEntryType)
|
||||
{
|
||||
std::shared_ptr<TopicReplay::Factory> topicReplayFactory;
|
||||
|
||||
if (!m_replaySession->interfaceFromGui<TopicReplayInterface>(topicReplayFactory))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getTopicIfcFactory failed: Cannot add topic type "
|
||||
<< LtsScriptTimeline::trackEntryTypeName(trackEntryType)
|
||||
<< " because topic ifc factory is missing.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return topicReplayFactory;
|
||||
}
|
||||
|
||||
|
||||
template <typename TopicEditorGuiInterface,
|
||||
typename TopicReplayFactory = TopicReplay::Factory,
|
||||
typename TopicExportFactory = TopicReplayFactory>
|
||||
bool tryAddTopic(LtsScriptTimeline::TrackEntryType trackEntryType,
|
||||
QStringList &resultList,
|
||||
const SpecialTopicType &specialTopicType = SpecialTopicType::NonSpecial)
|
||||
{
|
||||
std::shared_ptr<TopicEditorBase::Interface> topicEditorIfc;
|
||||
std::shared_ptr<TopicReplay::Factory> topicReplayFactory;
|
||||
std::shared_ptr<TopicReplay::Factory> topicExportFactory;
|
||||
|
||||
if (!std::is_same<TopicEditorBase::Interface, TopicEditorGuiInterface>::value)
|
||||
{
|
||||
topicEditorIfc = getTopicEditorIfc<TopicEditorGuiInterface>(trackEntryType);
|
||||
|
||||
if (topicEditorIfc == nullptr)
|
||||
{
|
||||
resultList.append(LtsScriptTimeline::trackEntryTypeName(trackEntryType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::is_same<TopicReplay::Factory, TopicReplayFactory>::value)
|
||||
{
|
||||
topicReplayFactory = getTopicReplayFactory<TopicReplayFactory>(trackEntryType);
|
||||
|
||||
if (topicReplayFactory == nullptr)
|
||||
{
|
||||
resultList.append(LtsScriptTimeline::trackEntryTypeName(trackEntryType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::is_same<TopicReplay::Factory, TopicExportFactory>::value)
|
||||
{
|
||||
topicExportFactory = getTopicReplayFactory<TopicExportFactory>(trackEntryType);
|
||||
|
||||
if (topicExportFactory == nullptr)
|
||||
{
|
||||
resultList.append(LtsScriptTimeline::trackEntryTypeName(trackEntryType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
topicExportFactory = topicReplayFactory;
|
||||
|
||||
return _tryAddTopic(trackEntryType, topicEditorIfc, topicReplayFactory, topicExportFactory, resultList, specialTopicType);
|
||||
}
|
||||
|
||||
|
||||
Ui::ScriptDialog *m_ui;
|
||||
LtsSession::LtsSession *m_essentialsViewSession;
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> m_essentialsViewsSrpGuiIfc;
|
||||
std::shared_ptr<PresentationManagement::Interface::Dtc> m_dtc;
|
||||
std::shared_ptr<PresentationManagement::Interface::Ftc> m_ftc;
|
||||
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_srmForeign;
|
||||
std::shared_ptr<Core::Interface::Dtc> m_coreDtc;
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
|
||||
QString m_menuGroup;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
int m_selectedTeId;
|
||||
TopicEditorBase::TopicEditor *m_currentTopicEditor;
|
||||
int m_scriptId;
|
||||
QMap<QString, TopicAssignment> m_trackEntryAssignments;
|
||||
QMap<LtsScriptTimeline::TrackEntryType, TopicAssignment> m_trackEntryToTopicAssignment;
|
||||
LtsPluginManager::LtsPluginManager *m_essentialsViewApp;
|
||||
QString m_scriptName;
|
||||
QString m_scriptOwner;
|
||||
qint64 m_lastModified = 0;
|
||||
QVector<LtsScriptTimeline::TrackEntry *> m_topicVector;
|
||||
QMultiMap<int, LtsScriptTimeline::TrackEntry *> m_topicMap; // <seconds, trackEntry>
|
||||
QVector<FilterTopic> m_filterTopicVector;
|
||||
TakeHomePackageGenerator::ExportProcess *m_exportProcess;
|
||||
LtsSession::LtsSession *m_exerciseSession; // aka. script editor app
|
||||
LtsSession::LtsSession *m_replaySession;
|
||||
QTimer *m_presentationTimer;
|
||||
int m_lowestTime;
|
||||
int m_highestTime;
|
||||
int m_positionTime;
|
||||
int m_duration;
|
||||
int m_nextPauseTime;
|
||||
QVector<PlayingTopic *> m_currentlyPlayingTopics; // also indicates that the script is either playing or in paused state if NOT empty
|
||||
Screen *m_projectionWidget1;
|
||||
Screen *m_projectionWidget2;
|
||||
MainJournal m_journal;
|
||||
int m_scriptsExerciseId;
|
||||
QString m_exerciseName;
|
||||
LtsPluginManager::LtsPluginManager *m_sitMapApp;
|
||||
LtsSession::LtsSession *m_sitMapSession;
|
||||
bool m_currentlyFreestandingTopicsScreen1;
|
||||
bool m_currentlyFreestandingTopicsScreen2;
|
||||
TopicReplay::Interface *m_sitMapTopicIfc;
|
||||
bool m_firstPlayAfterStop;
|
||||
bool m_enableApply;
|
||||
bool m_stopAfterPlayingFilterTopic;
|
||||
QWidget *m_previousParentForScreen1;
|
||||
QWidget *m_previousParentForScreen2;
|
||||
int m_ignoreTopicForReplay;
|
||||
QPointer<TopicDesigner> m_currentTopicDesigner;
|
||||
bool m_avsVisibilityHackActive;
|
||||
QPointer<StoryboardDialog> m_storyboardDialog;
|
||||
bool m_ignoreChanges;
|
||||
bool m_scriptRunning;
|
||||
bool m_bTimerTickRecursionGuard;
|
||||
bool m_isPlayTopicMethodStillRunning;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
private slots:
|
||||
void slotEditEntry(const int topicId);
|
||||
void slotTrackEntrySelectionChanged(LtsScriptTimeline::TrackEntry *);
|
||||
void slotChangesWereMade();
|
||||
void slotTrackEntryModified();
|
||||
void slotNull(QObject *obj);
|
||||
void slotDiscard();
|
||||
void slotStartEssentialsView();
|
||||
void slotLoadScript();
|
||||
void slotExportScript();
|
||||
void slotExportSuccessful(const QString &path, const QString &failedTopics);
|
||||
void slotBurnDvD(const QString &strExportPath);
|
||||
void slotBurningFinished(bool success);
|
||||
void slotPlay();
|
||||
void slotPause();
|
||||
void slotStop();
|
||||
void slotTimerTick();
|
||||
void slotShowStoryboard();
|
||||
void slotShowJournal();
|
||||
void slotToNextTopic();
|
||||
void slotToPreviousTopic();
|
||||
void slotPlayUntilNextTopic();
|
||||
void slotSetTopicPosition(QWidget *previewWidget, int ignoreTopicForReplay);
|
||||
void slotTrackEntryDeleted(const int topicId);
|
||||
void slotEditSelectedEntry();
|
||||
void slotCheckNewTopicLength(int newLength, LtsUtils::Promise *promise);
|
||||
void slotAddFakeLegacyPlanTopic();
|
||||
|
||||
void slotChangesMade();
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScriptDialog</class>
|
||||
<widget class="QWidget" name="ScriptDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1010</width>
|
||||
<height>587</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="999,0">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="LtsScriptTimeline::ScriptTimeline" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="replayControls">
|
||||
<property name="title">
|
||||
<string>Replay Controls</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QWidget" name="replayControlsWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,999">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="replayControlsLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="replayControlsMainLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="replayControlsScreensLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbInitScr1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Screen 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbInitScr2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Screen 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPause">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPlay">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="replayControlsJumpLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbUntilNextTopic">
|
||||
<property name="text">
|
||||
<string>Play Until Next Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPreviousTopic">
|
||||
<property name="text">
|
||||
<string>Previous Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbNextTopic">
|
||||
<property name="text">
|
||||
<string>Next Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="replayInfoLayout">
|
||||
<property name="horizontalSpacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="durationLabel">
|
||||
<property name="text">
|
||||
<string>Presentation duration:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblDuration">
|
||||
<property name="text">
|
||||
<string notr="true"> - </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="posLabel">
|
||||
<property name="text">
|
||||
<string>Pos:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSlider" name="posSlider">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="currentPosLabel">
|
||||
<property name="text">
|
||||
<string>Current position:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="currentositionLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPos">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="slashLabel">
|
||||
<property name="text">
|
||||
<string>/</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblMax">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="statusLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lwStatus">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Free</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsScriptTimeline::ScriptTimeline</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">LtsScriptTimeline/script_timeline.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#include "pre_script_gui_plugin.h"
|
||||
#include "pre_script_dialog.h"
|
||||
|
||||
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/ScriptChooser/script_chooser.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/pre_edit_dialog.h>
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsWidgets/lts_background_widget.h>
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsScriptTimeline/temporary_pointer_vector.h>
|
||||
#include <Common/TopicEditorBase/topic_editor_base.h>
|
||||
|
||||
// Control- & Widget-Ifcs:
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
#include <Plugins/BuildingViewer/bdv_viewer_gui_plugin_interface.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_menu_edit_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_script_filter_gui_plugin_interface.h>
|
||||
#include <Plugins/MarkerManagement/mrk_gui_plugin_interface.h>
|
||||
#include <Plugins/Evaluations/evl_gui_plugin_interface.h>
|
||||
#include <Plugins/ReportManagement/rep_gui_plugin_interface.h>
|
||||
#include <Plugins/PlanOverlays/plan_overlays_plugin_interface.h>
|
||||
#include <Services/PresentationManagement/pre_operator_rights.h>
|
||||
#include <Services/PresentationManagement/pre_dtc.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QJsonParseError>
|
||||
#include <QJsonDocument>
|
||||
#include <QProgressDialog>
|
||||
#include <QTimer>
|
||||
#include <QFileDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <stdlib.h> // for abort
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
|
||||
{
|
||||
return std::make_shared<InterfaceImpl>(session);
|
||||
}
|
||||
|
||||
|
||||
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
|
||||
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Pre.Script"))
|
||||
, m_dtc(nullptr)
|
||||
, m_opmDtc(nullptr)
|
||||
, m_ftc(nullptr)
|
||||
, m_repForeign(nullptr)
|
||||
, m_scriptDialog(nullptr)
|
||||
, m_scriptId(0) // invalid
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
{
|
||||
connect(this, &InterfaceImpl::signalSuccess, m_session, &LtsSession::LtsSession::slotExecuteNextPayload, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
|
||||
{
|
||||
QVector<LtsWidgets::PluginData> ret;
|
||||
{
|
||||
LtsWidgets::PluginData data;
|
||||
data.menuGroup = menuGroup();
|
||||
data.identifier = QStringLiteral("PresentationManagement.ScriptDialog");
|
||||
data.menuText = tr("Show Script Editor");
|
||||
|
||||
if (getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN))
|
||||
{
|
||||
data.layoutArea = LtsWidgets::LayoutArea::eMainTab;
|
||||
data.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction;
|
||||
data.closable = false;
|
||||
}
|
||||
else // (as dialog) = rather unlikely..
|
||||
{
|
||||
data.layoutArea = LtsWidgets::LayoutArea::eDialogTab;
|
||||
}
|
||||
data.operatorRight = OperatorRights::ScriptEditorShow;
|
||||
data.createWidgetFunc = [this](QWidget *parent)
|
||||
{
|
||||
return onShowScriptDialog(parent);
|
||||
};
|
||||
|
||||
ret.append(data);
|
||||
}
|
||||
|
||||
{
|
||||
LtsWidgets::PluginData data;
|
||||
data.menuGroup = menuGroup();
|
||||
data.identifier = QLatin1String("PresentationManagement.ScriptDialog.ImportScript");
|
||||
data.menuIcon = QIcon(QLatin1String("icon:import_documents.svg"));
|
||||
data.menuText = tr("Insert Script");
|
||||
data.operatorRight = OperatorRights::ScriptEditorEdit;
|
||||
data.directFunc = [this](const LtsWidgets::PluginData &)
|
||||
{
|
||||
return onImportScript();
|
||||
};
|
||||
data.createWidgetFunc = nullptr;
|
||||
|
||||
ret.append(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::fetchInterfaces()
|
||||
{
|
||||
if (!m_session->getDtc<PresentationManagement::DataInterface>(m_dtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for PresentationManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getFtc<PresentationManagement::DataInterface>(m_ftc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getFtc for PresentationManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getDtc<OperatorManagement::DataInterface>(m_opmDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for OperatorManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getDtc<SituationReplayManagement::DataInterface>(m_coreDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for SituationReplayManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getForeignDataInterface<SituationReplayManagement::DataInterface>(m_repForeign))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "getForeignDataInterface for SituationReplayManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::clearInterfaces()
|
||||
{
|
||||
m_repForeign = nullptr;
|
||||
m_coreDtc = nullptr;
|
||||
m_opmDtc = nullptr;
|
||||
m_ftc = nullptr;
|
||||
m_dtc = nullptr;
|
||||
}
|
||||
|
||||
|
||||
QString InterfaceImpl::menuGroup() const
|
||||
{
|
||||
return tr("Presentation");
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowScriptDialog(QWidget *parent)
|
||||
{
|
||||
m_scriptDialog = new ScriptDialog(menuGroup(), parent);
|
||||
|
||||
if (!m_scriptDialog->init(m_session, m_scriptId, m_dtc, m_ftc, m_repForeign, m_coreDtc, m_opmDtc))
|
||||
{
|
||||
m_scriptDialog->deleteLater();
|
||||
m_scriptDialog = nullptr;
|
||||
|
||||
// dialog is app's main dialog, close app if dialog cannot initialize
|
||||
emit m_session->signalClose();
|
||||
}
|
||||
|
||||
return m_scriptDialog.data();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::onImportScript()
|
||||
{
|
||||
ScriptChooser *scriptChooser = new ScriptChooser(m_dtc, m_opmDtc, false, true);
|
||||
scriptChooser->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalSelectScript,
|
||||
this, &InterfaceImpl::slotImportScript, Qt::QueuedConnection);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalQuit,
|
||||
m_session, &LtsSession::LtsSession::signalQuit);
|
||||
|
||||
if (!LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
scriptChooser->setModal(true);
|
||||
scriptChooser->show();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotNewScript()
|
||||
{
|
||||
// prepare request
|
||||
PresentationModifyRequest req;
|
||||
req.name(tr("New Script").toStdString());
|
||||
req.description(tr("No description available.").toStdString());
|
||||
req.operatorId(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
|
||||
req.lastModified(QDateTime::currentMSecsSinceEpoch());
|
||||
req.fileStatus(FileStatus::Valid);
|
||||
|
||||
if (m_requestHelper->startSingleRequest([this, req]()
|
||||
{
|
||||
return m_ftc->presentationModifyRequest(req, this);
|
||||
}))
|
||||
{
|
||||
//slotSelectScript(m_requestHelper->getRepliedId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotAddScript()
|
||||
{
|
||||
PresentationEditDialog *dialog = new PresentationEditDialog(nullptr);
|
||||
if (!dialog->init(-1 /* new presentation */, m_dtc, m_ftc, m_opmDtc))
|
||||
{
|
||||
delete dialog;
|
||||
return;
|
||||
}
|
||||
|
||||
QObject::connect(dialog, &PresentationEditDialog::rejected, dialog, &PresentationEditDialog::deleteLater);
|
||||
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::executePayload(LtsWidgets::LtsBackgroundWidget *mainBackground)
|
||||
{
|
||||
Q_UNUSED(mainBackground);
|
||||
|
||||
if (m_session->partitionType() != IDL::PartitionType::Exercise) // only on valid exercise
|
||||
{
|
||||
emit signalSuccess();
|
||||
return;
|
||||
}
|
||||
|
||||
int scriptId = m_session->getSavegame()[QStringLiteral("ScriptId")].toInt();
|
||||
if (scriptId > 0)
|
||||
{
|
||||
slotSelectScript(scriptId);
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptChooser *scriptChooser = new ScriptChooser(m_dtc, m_opmDtc, false, false, mainBackground);
|
||||
scriptChooser->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalSelectScript,
|
||||
this, &InterfaceImpl::slotSelectScript, Qt::QueuedConnection);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalQuit,
|
||||
m_session, &LtsSession::LtsSession::signalQuit);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalNewScript,
|
||||
this, &InterfaceImpl::slotAddScript);
|
||||
|
||||
if (!LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
scriptChooser->setModal(true);
|
||||
|
||||
scriptChooser->show();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotSelectScript(int scriptId)
|
||||
{
|
||||
m_scriptId = scriptId;
|
||||
|
||||
// std::shared_ptr<ForeignGuiInterface> preGuiIfc;
|
||||
|
||||
// if (!m_session->getForeignGuiInterface<ForeignGuiInterface>(preGuiIfc))
|
||||
// {
|
||||
// // TODO: MSG !!1
|
||||
// return;
|
||||
// }
|
||||
|
||||
// preGuiIfc->setScriptId(scriptId);
|
||||
|
||||
emit signalSuccess();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotImportScript(int scriptId)
|
||||
{
|
||||
if (m_scriptId == scriptId)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Not possible to import same script!";
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("Not possible to import same script!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!importScript(scriptId))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to import script Id " << scriptId;
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("Failed to import Script Id %1").arg(scriptId));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Succesfully imported script Id " << scriptId ;
|
||||
|
||||
//LtsWidgets::LtsMessageDialog::showMessage(nullptr, tr("Successfully imported Script Id %1").arg(scriptId));
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::importScript(int idSource)
|
||||
{
|
||||
if (!m_scriptDialog)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no script dialog open for import script";
|
||||
return false;
|
||||
}
|
||||
|
||||
PresentationManagement::Presentation preSource = m_dtc->presentation(idSource);
|
||||
|
||||
if (preSource.id() < 1)
|
||||
return false;
|
||||
|
||||
// import topics
|
||||
std::function<void(const Core::FunctionReply &baseReply)> importPresentationContent = [&](const Core::FunctionReply &baseReply)
|
||||
{
|
||||
const GetPresentationContentReply &reply = static_cast<const GetPresentationContentReply &>(baseReply);
|
||||
const auto &contentList = reply.content();
|
||||
|
||||
if (contentList.size() < 1)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No Presentation Content for Script Id " << reply.id();
|
||||
return;
|
||||
}
|
||||
|
||||
LtsScriptTimeline::TemporaryPointerVector<LtsScriptTimeline::TrackEntry *> importedTes;
|
||||
|
||||
for (const PresentationManagement::PresentationContent &content : contentList)
|
||||
{
|
||||
LtsScriptTimeline::TrackEntryType tet = LtsScriptTimeline::TrackEntryType::INVALID;
|
||||
|
||||
if (!m_scriptDialog->topicStringToType(QString::fromStdString(content.presentationTopicType()), tet))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Topic ignored - invalid topic type for presentation's content id " << content.id();
|
||||
continue;
|
||||
}
|
||||
|
||||
importedTes.append(ScriptDialog::trackEntryFromContent(content, 0, tet));
|
||||
}
|
||||
|
||||
if (m_scriptDialog->importTrackEntries(importedTes))
|
||||
importedTes.setDiscardable(false); // don't delete tes if they could be imported and finally be managed by the script timeline
|
||||
};
|
||||
|
||||
|
||||
GetPresentationContentRequest req(idSource);
|
||||
req.presentationId(idSource);
|
||||
|
||||
if (!m_requestHelper->startSingleRequest([req, this]()
|
||||
{
|
||||
return m_ftc->getPresentationContentRequest(req, this);
|
||||
}, importPresentationContent))
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("There is no content to import for this script."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/pre_data_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/pre_script_gui_plugin_interface.h>
|
||||
#include <Services/PresentationManagement/pre_ftc.h> // reply handler
|
||||
#include <Services/OperatorManagement/opm_dtc.h>
|
||||
#include <Plugins/SituationReplayManagement/srm_data_plugin_interface.h>
|
||||
#include <Common/ProjectConfig/project_defines.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
|
||||
// test:
|
||||
#include <LtsScriptTimeline/track_entry_painters.h>
|
||||
#include "pre_script_dialog.h"
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "gui:3:pre.script.edit")
|
||||
Q_INTERFACES(GuiPluginBase::Plugin)
|
||||
|
||||
public:
|
||||
explicit GuiPlugin() = default;
|
||||
~GuiPlugin() = default;
|
||||
|
||||
QString pluginName() override { return ForeignScriptDialogGuiInterface::pluginName(); }
|
||||
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override
|
||||
{ return (partition == IDL::PartitionType::Exercise); }
|
||||
};
|
||||
|
||||
|
||||
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
|
||||
, protected PresentationManagement::Interface::Ftc::PresentationModifyReplyHandler
|
||||
, protected PresentationManagement::Interface::Ftc::GetPresentationContentReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InterfaceImpl(LtsSession::LtsSession *session);
|
||||
|
||||
QVector<LtsWidgets::PluginData> getActions() override;
|
||||
QString menuGroup() const override;
|
||||
bool fetchInterfaces() override;
|
||||
void clearInterfaces() override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override
|
||||
{ return partition == IDL::PartitionType::Exercise; }
|
||||
|
||||
// be able to show script chooser
|
||||
int executionPriority() const override { return 9999; }
|
||||
void executePayload(LtsWidgets::LtsBackgroundWidget *mainBackground) override;
|
||||
|
||||
protected:
|
||||
void onPresentationModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
void onGetPresentationContentReply(const GetPresentationContentReply &reply) override { m_requestHelper->requestReply(reply); }
|
||||
|
||||
private:
|
||||
LtsWidgets::LtsDialog *onShowScriptDialog(QWidget *parent);
|
||||
void onImportScript();
|
||||
bool importScript(/*int idDest, */int idSource);
|
||||
|
||||
std::shared_ptr<PresentationManagement::Interface::Dtc> m_dtc;
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
|
||||
std::shared_ptr<PresentationManagement::Interface::Ftc> m_ftc;
|
||||
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_repForeign;
|
||||
std::shared_ptr<Core::Interface::Dtc> m_coreDtc;
|
||||
|
||||
QPointer<PresentationManagement::ScriptDialog> m_scriptDialog;
|
||||
int m_scriptId;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
|
||||
signals:
|
||||
void signalSuccess();
|
||||
|
||||
private slots:
|
||||
void slotSelectScript(int scriptId);
|
||||
void slotNewScript();
|
||||
void slotImportScript(int scriptId);
|
||||
void slotAddScript();
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
#include "pre_storyboard.h"
|
||||
#include "ui_pre_storyboard.h"
|
||||
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
using namespace LtsScriptTimeline;
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
StoryboardDialog::StoryboardDialog(QWidget *parent, LtsSession::LtsSession *session)
|
||||
: LtsWidgets::LtsDialog(parent)
|
||||
, m_ui(new Ui::StoryboardDialog)
|
||||
, m_session(session)
|
||||
, m_alreadyTranslated(false)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &StoryboardDialog::slotPrint);
|
||||
}
|
||||
|
||||
|
||||
StoryboardDialog::~StoryboardDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void StoryboardDialog::slotPrint()
|
||||
{
|
||||
QString headingHtml = (QStringLiteral("<H1>"));
|
||||
headingHtml.append (tr("Scriptname:"));
|
||||
headingHtml.append(m_scriptName);
|
||||
headingHtml.append(QStringLiteral("</H1>"));
|
||||
headingHtml.append(QStringLiteral("<H3>"));
|
||||
headingHtml.append(tr("Script Owner: "));
|
||||
headingHtml.append(m_scriptOwner);
|
||||
headingHtml.append(QStringLiteral("</H3>"));
|
||||
headingHtml.append(QStringLiteral("<H3>"));
|
||||
headingHtml.append(tr("Last modified: "));
|
||||
headingHtml.append(DTG::toStringMSec(m_lastModified));
|
||||
headingHtml.append(QStringLiteral("<br>"));
|
||||
headingHtml.append(tr("Duration: "));
|
||||
QString durationStr = m_duration;
|
||||
headingHtml.append(durationStr);
|
||||
headingHtml.append(QStringLiteral("</H3><br>"));
|
||||
|
||||
LtsPrinting::printView(m_session, this, m_ui->listWidget, headingHtml);
|
||||
}
|
||||
|
||||
|
||||
bool StoryboardDialog::init(const QVector<LtsScriptTimeline::TrackEntry *> &topicVector,
|
||||
const QVector<FilterTopic> &filterTopicVector,
|
||||
const QString &scriptName,
|
||||
const QString &scriptOwner,
|
||||
const qint64 lastModified,
|
||||
const QString duration)
|
||||
{
|
||||
m_topicVector = topicVector; // cpy
|
||||
m_filterTopicVector = filterTopicVector; // cpy
|
||||
m_scriptName = scriptName; // cpy
|
||||
m_scriptOwner = scriptOwner;
|
||||
m_lastModified = lastModified;
|
||||
m_duration = duration;
|
||||
|
||||
// sort storyboard by time
|
||||
std::sort(m_topicVector.begin(), m_topicVector.end(), [](const TrackEntry *a, const TrackEntry *b) -> bool
|
||||
{
|
||||
return a->m_startTime < b->m_startTime;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void StoryboardDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Script Storyboard"));
|
||||
|
||||
if (m_alreadyTranslated)
|
||||
return;
|
||||
|
||||
fillStoryboard();
|
||||
m_alreadyTranslated = true;
|
||||
}
|
||||
|
||||
|
||||
void StoryboardDialog::fillStoryboard()
|
||||
{
|
||||
m_ui->listWidget->clear();
|
||||
|
||||
QVector<FilterTopic> correspondingFilterTopics;
|
||||
int ii1 = 1;
|
||||
for (const LtsScriptTimeline::TrackEntry *te : qAsConst(m_topicVector))
|
||||
{
|
||||
QString itemText = tr("Topic %1: %2 - %3 (%4 seconds)\n Type: %5").arg(
|
||||
ii1).arg(QTime::fromMSecsSinceStartOfDay(te->m_startTime * 1000).toString(),
|
||||
QTime::fromMSecsSinceStartOfDay((te->m_startTime + te->m_length) * 1000).toString()).arg(
|
||||
te->m_length).arg(LtsScriptTimeline::translateTrackEntryType(te->m_type));
|
||||
|
||||
if (!te->m_description.isEmpty())
|
||||
itemText += QStringLiteral("\n ") + tr("Description: %1").arg(te->m_description);
|
||||
|
||||
m_ui->listWidget->addItem(itemText);
|
||||
|
||||
|
||||
// look for filters for this topic:
|
||||
correspondingFilterTopics.clear();
|
||||
for (const FilterTopic &_ft : qAsConst(m_filterTopicVector))
|
||||
{
|
||||
if (_ft.mainTopicId != te->m_topicId)
|
||||
continue;
|
||||
|
||||
correspondingFilterTopics.append(_ft);
|
||||
}
|
||||
|
||||
|
||||
// sort filter topics by start time
|
||||
std::sort(correspondingFilterTopics.begin(), correspondingFilterTopics.end(), [](const FilterTopic &a, const FilterTopic &b) -> bool
|
||||
{
|
||||
return a.filterTopic->m_startTime < b.filterTopic->m_startTime;
|
||||
});
|
||||
|
||||
|
||||
int ii2 = 1;
|
||||
for (const FilterTopic &_ft : qAsConst(correspondingFilterTopics))
|
||||
{
|
||||
if (_ft.mainTopicId != te->m_topicId)
|
||||
continue;
|
||||
|
||||
const LtsScriptTimeline::TrackEntry *fte = _ft.filterTopic;
|
||||
|
||||
QString filterItemText = tr(" > Filter %1: %2 - %3 (%4 seconds)\n Type: %5").arg(
|
||||
ii2).arg(QTime::fromMSecsSinceStartOfDay(fte->m_startTime * 1000).toString(),
|
||||
QTime::fromMSecsSinceStartOfDay((fte->m_startTime + te->m_length) * 1000).toString()).arg(
|
||||
fte->m_length).arg(LtsScriptTimeline::translateTrackEntryType(te->m_type));
|
||||
|
||||
if (!fte->m_description.isEmpty())
|
||||
filterItemText += QStringLiteral("\n ") + tr("Description: %1").arg(fte->m_description);
|
||||
|
||||
m_ui->listWidget->addItem(filterItemText);
|
||||
|
||||
ii2++;
|
||||
}
|
||||
|
||||
ii1++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "filter_topic.h"
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class StoryboardDialog;
|
||||
}
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class StoryboardDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StoryboardDialog(QWidget *parent, LtsSession::LtsSession *session);
|
||||
~StoryboardDialog();
|
||||
bool init(const QVector<LtsScriptTimeline::TrackEntry *> &topicVector,
|
||||
const QVector<FilterTopic> &filterTopicVector,
|
||||
const QString &scriptName,
|
||||
const QString &scriptOwner,
|
||||
const qint64 lastModified,
|
||||
const QString duration);
|
||||
void fillStoryboard();
|
||||
void retranslate() override final;
|
||||
|
||||
private:
|
||||
Ui::StoryboardDialog *m_ui;
|
||||
QVector<LtsScriptTimeline::TrackEntry *> m_topicVector;
|
||||
QVector<FilterTopic> m_filterTopicVector;
|
||||
LtsSession::LtsSession *m_session;
|
||||
QString m_scriptName = QString();
|
||||
QString m_scriptOwner = QString();
|
||||
qint64 m_lastModified = 0;
|
||||
QString m_duration = QString();
|
||||
bool m_alreadyTranslated;
|
||||
|
||||
public slots:
|
||||
void slotPrint();
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>StoryboardDialog</class>
|
||||
<widget class="QWidget" name="StoryboardDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>707</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Dialog for the Topic Designer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-06-09
|
||||
*/
|
||||
|
||||
#include "pre_topic_designer_dialog.h"
|
||||
#include "ui_pre_topic_designer_dialog.h"
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
TopicDesignerDialog::TopicDesignerDialog(QWidget *parent)
|
||||
: LtsDialog(parent)
|
||||
, m_ui(new Ui::TopicDesignerDialog)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
connect(m_ui->widget, &TopicDesigner::signalTopicSelected,
|
||||
this, &TopicDesignerDialog::signalTopicSelected);
|
||||
connect(m_ui->widget, &TopicDesigner::signalDeleteTrackEntry,
|
||||
this, &TopicDesignerDialog::signalDeleteTrackEntry);
|
||||
connect(m_ui->widget, &TopicDesigner::signalUnselect,
|
||||
this, &TopicDesignerDialog::signalUnselect);
|
||||
connect(m_ui->widget, &TopicDesigner::signalChangesMade,
|
||||
this, &LtsWidgets::LtsDialog::signalChangesMade);
|
||||
|
||||
// connect(m_ui->pbToFront, &QPushButton::clicked,
|
||||
// m_ui->widget, &TopicDesigner::to)
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Topic Designer"));
|
||||
}
|
||||
|
||||
|
||||
TopicDesignerDialog::~TopicDesignerDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
QVector<LtsScriptTimeline::TrackEntry *> TopicDesignerDialog::exportTopicList() const
|
||||
{
|
||||
return m_ui->widget->exportTopicList();
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::selectTopic(int topicId)
|
||||
{
|
||||
m_ui->widget->selectTopic(topicId);
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::loadTopicList(const QVector<LtsScriptTimeline::TrackEntry *> &topicsList)
|
||||
{
|
||||
m_ui->widget->loadTopicList(topicsList);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Dialog for the Topic Designer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-06-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TopicDesignerDialog;
|
||||
}
|
||||
|
||||
namespace LtsScriptTimeline
|
||||
{
|
||||
class TrackEntry;
|
||||
}
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicDesignerDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
public:
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TopicDesignerDialog(QWidget *parent = nullptr);
|
||||
~TopicDesignerDialog();
|
||||
|
||||
void loadTopicList(const QVector<LtsScriptTimeline::TrackEntry *> &topicsList);
|
||||
QVector<LtsScriptTimeline::TrackEntry *> exportTopicList() const;
|
||||
void selectTopic(int topicId);
|
||||
|
||||
signals:
|
||||
void signalTopicSelected(int topicId);
|
||||
void signalDeleteTrackEntry(int topicId);
|
||||
void signalUnselect();
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
|
||||
Ui::TopicDesignerDialog *m_ui;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TopicDesignerDialog</class>
|
||||
<widget class="QWidget" name="TopicDesignerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string notr="true">Some text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbToFront">
|
||||
<property name="text">
|
||||
<string>To Front</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbIncIdx">
|
||||
<property name="text">
|
||||
<string>Inc Idx</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbDecIdx">
|
||||
<property name="text">
|
||||
<string>Dec Idx</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbToBack">
|
||||
<property name="text">
|
||||
<string>To Back</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PresentationManagement::TopicDesigner" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PresentationManagement::TopicDesigner</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>topic_designer.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLTE, 2020-03-23
|
||||
#
|
||||
|
||||
ADD_SUBDIRECTORY(Common)
|
||||
ADD_SUBDIRECTORY(ThpManagement)
|
||||
ADD_SUBDIRECTORY(ThpUsbManagement)
|
||||
|
||||
ADD_INTERFACE_LIBRARY(TpmGuiPluginInterface
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tpm_gui_plugin_interface.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
GuiPluginInterface
|
||||
)
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# $Id: CMakeLists.txt 51804 2020-07-31 04:47:28Z fritsche_h $
|
||||
# $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/CMakeLists.txt $
|
||||
# $Author: fritsche_h $
|
||||
#
|
||||
# Created by Mike Wille, SLTE, 2020-03-23
|
||||
#
|
||||
|
||||
SET(src
|
||||
logger.cpp
|
||||
logger.h
|
||||
tpm_exported_scripts_model.cpp
|
||||
tpm_exported_scripts_model.h
|
||||
tpm_process_dialog.cpp
|
||||
tpm_process_dialog.h
|
||||
)
|
||||
|
||||
QT5_WRAP_UI(src
|
||||
tpm_process_dialog.ui
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY2(WS ThpCommon SHARED ${src})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(ThpCommon
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../ # export file
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(ThpCommon
|
||||
Qt6::Core
|
||||
Qt6::Concurrent
|
||||
NGLLogger
|
||||
LtsSession
|
||||
AsmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
#nglcompression
|
||||
#nglsettings
|
||||
#ngltools
|
||||
#LtsSessionData
|
||||
#httq
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(ThpCommon)
|
||||
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id: logger.cpp 46225 2019-03-25 13:59:56Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/logger.cpp $
|
||||
* $Author: rudolphus_g $
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "TPM.Common.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for CentralEffectSimulation
|
||||
* $Id: logger.h 46225 2019-03-25 13:59:56Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/logger.h $
|
||||
* $Author: rudolphus_g $
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
typedef NGL::INGLLogger &LOGGER_T;
|
||||
|
||||
LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace TakeHomePackageManager
|
||||
+632
@@ -0,0 +1,632 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Show the exported scripts and allow them to upload them to the server
|
||||
* $Id: tpm_exported_scripts_model.cpp 53111 2021-03-22 08:21:29Z wille_m $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_exported_scripts_model.cpp $
|
||||
* $Author: wille_m $
|
||||
* Created by Gerlinde Rudolphus, NLE, 2019-03-25
|
||||
*/
|
||||
|
||||
#include "tpm_exported_scripts_model.h"
|
||||
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
|
||||
ExportedScriptsModel::ExportedScriptsModel(QObject *parent)
|
||||
: LtsWidgets::LtsAbstractTableModel<ExportedScriptInformation>(
|
||||
{ tr("id"), tr("Exercise"), tr("Name"), tr("Created"), tr("Last downloaded"), tr("Location"), tr("Last uploaded"), tr("Server")}, parent)
|
||||
, m_logger(getLogger("ExportedScriptsModel"))
|
||||
{}
|
||||
|
||||
bool ExportedScriptsModel::init(const QString &rootDirectoryToScan)
|
||||
{
|
||||
std::shared_ptr<int> _(nullptr, [this](int *) { endResetModel(); }); // TODO: QScopeGuard
|
||||
m_rootDirectoryToScan = rootDirectoryToScan;
|
||||
beginResetModel();
|
||||
m_vecData.clear();
|
||||
|
||||
QVector <int> localExercises;
|
||||
DEBUG_LOG(m_logger) << "ExportedScriptsModel::init rootDirectoryToScan=" << rootDirectoryToScan
|
||||
/*<< " directoryToScan=" << directoryToScan*/;
|
||||
|
||||
//clear(); multiple inits needed, don't clear
|
||||
|
||||
// die Skripte aller Uebungen auf der lokalen Workstation anzeigen.
|
||||
// Die Uebungen sind in der Datei /tmp/THP-xxxxxxx/data.json im Array Exercises enthalten.
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Get all local exercises rootDirectoryToScan=" << rootDirectoryToScan ;
|
||||
QFile file(rootDirectoryToScan + QDir::separator() + QStringLiteral("exercises.json"));
|
||||
if (!file.open(QFile::ReadOnly)) // file only exists after a first download, but that's okay
|
||||
WARNING_LOG(m_logger) << "Cannot open " << file.fileName() << " for read/write: " << file.errorString();
|
||||
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
const QJsonObject obj = doc.object(); // okay to be empty
|
||||
const QJsonArray arr = obj[QStringLiteral("Exercises")].toArray();
|
||||
localExercises.reserve(arr.size());
|
||||
for (const auto &ele : arr)
|
||||
localExercises.append(ele.toInt());
|
||||
}
|
||||
|
||||
WARNING_LOG(m_logger) << "local exericses: " << localExercises.count();
|
||||
|
||||
// Alle lokalen Übungen:
|
||||
for (const int exId : qAsConst(localExercises))
|
||||
{
|
||||
const QString baseDir = exercisePath(rootDirectoryToScan, exId);
|
||||
QFile file(baseDir + QDir::separator() + QStringLiteral("data.json"));
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Cannot open " << file.fileName() << " for reading: " << file.errorString() << " - not critical";
|
||||
// There are no local scripts but maybe some are on the server
|
||||
return true;
|
||||
}
|
||||
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
const QJsonObject obj = doc.object();
|
||||
const QJsonArray presentations = obj[QStringLiteral("presentations")].toArray();
|
||||
|
||||
DEBUG_LOG(m_logger) << "exercise: " << exId << ", presentations: " << presentations.size();
|
||||
|
||||
for (const QJsonValue &val : presentations)
|
||||
{
|
||||
ExportedScriptInformation esi = ExportedScriptInformation::fromJson(val);
|
||||
DEBUG_LOG(m_logger) << "obj=" << QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
const QJsonObject presentationObj = val.toObject();
|
||||
DEBUG_LOG(m_logger) << "presentationObj=" << QJsonDocument(presentationObj).toJson(QJsonDocument::Compact);
|
||||
if (obj.contains(QStringLiteral("exerciseId")))
|
||||
{
|
||||
esi.exerciseId = obj[QStringLiteral("exerciseId")].toInt();
|
||||
esi.exerciseName = obj[QStringLiteral("exerciseName")].toString();
|
||||
if (presentationObj.contains(QStringLiteral("name")) )
|
||||
esi.scriptName = presentationObj[QStringLiteral("name")].toString();
|
||||
if (presentationObj.contains(QStringLiteral("displayName")) )
|
||||
esi.scriptName = presentationObj[QStringLiteral("displayName")].toString();
|
||||
}
|
||||
|
||||
esi.local = true;
|
||||
DEBUG_LOG(m_logger) << "push_back "
|
||||
<< " exportTime=" << esi.exportTime
|
||||
<< " scriptId=" << esi.scriptId
|
||||
<< " scriptName=" << esi.scriptName
|
||||
<< " exerciseId=" << esi.exerciseId
|
||||
<< " exerciseName=" << esi.exerciseName
|
||||
<< " local=" << esi.local;
|
||||
esi.uploaded = ThpUnknownUploadState;
|
||||
|
||||
esi.rootDirectory = rootDirectoryToScan; // to determine if this script is from THP-Download or THP-Export directory (for USB Management, which can copy from both dirs)
|
||||
|
||||
m_vecData.push_back(esi);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ExportedScriptsModel::setServerContent fills the table with local and
|
||||
* server scripts and deletes rows of deleted scripts.
|
||||
* @param jsonArray of scripts from the server
|
||||
* @return true if jsonArray could be parsed and was processed, false if
|
||||
* jsonArray could not be parsed
|
||||
*/
|
||||
void ExportedScriptsModel::setServerContent(const QString &jsonArray)
|
||||
{
|
||||
if (jsonArray.isEmpty()) // no content received yet? no problem, just return
|
||||
return;
|
||||
|
||||
/* these vectors are needed to compare which scripts are already
|
||||
* on the server or are local or are both on the server and local
|
||||
* e.g. if the script was downloaded after it was once uploaded
|
||||
* to the server */
|
||||
QMap<int, QVector<int>> exerciseContentScriptIds; // scripts from server - Key = ExerciseId, value = script ids of exercise
|
||||
QMap<int, QVector<int>> exerciseScriptIds; // scripts from local data.json file - Key = ExerciseId, value = script ids of exercise
|
||||
|
||||
DEBUG_LOG(m_logger) << "ExportedScriptsModel::setServerContent jsonArray =" << jsonArray;
|
||||
QJsonParseError err;
|
||||
const QJsonArray presentations = QJsonDocument::fromJson(jsonArray.toUtf8(), &err).array();
|
||||
DEBUG_LOG(m_logger) << "presentations.size() =" << presentations.size();
|
||||
|
||||
if (err.error != QJsonParseError::NoError)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "json array invalid at offset " << err.offset << ": " << err.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
// put local scripts into local scripts list
|
||||
for (const auto &data : qAsConst(m_vecData))
|
||||
{
|
||||
exerciseScriptIds[data.exerciseId].append(data.scriptId);
|
||||
DEBUG_LOG(m_logger) << "exerciseId=" << data.exerciseId
|
||||
<< " modelScriptIds.append: " << data.scriptId;
|
||||
}
|
||||
|
||||
// put server scripts into server scripts list
|
||||
for (const QJsonValue &val : presentations)
|
||||
{
|
||||
const ExportedScriptInformation esi = ExportedScriptInformation::fromJson(val, false, ThpAlreadyUploaded);
|
||||
exerciseContentScriptIds[esi.exerciseId].append(esi.scriptId);
|
||||
}
|
||||
|
||||
/* look for scripts that are on the server but also on the local side to
|
||||
* either remove the corresponding row from the table if the script is not on
|
||||
* the server and not set as local (that makes it non-local and non-existant
|
||||
* on the server, which means it was at one point on the server, but was
|
||||
* deleted from it after the server script list was received here some
|
||||
* minutes ago) -
|
||||
* or to add the not-uploaded state to the table row if it's local only
|
||||
* (but what about local scripts that were uploaded? => This is handeled at
|
||||
* the next main for-loop below)
|
||||
*/
|
||||
for (int i = m_vecData.size() - 1; i >= 0; --i) // scriptId ist nur im Modell aber nicht im content
|
||||
{
|
||||
const auto &rowData = m_vecData[i];
|
||||
const QVector<int> contentScriptIds = exerciseContentScriptIds.value(rowData.exerciseId);
|
||||
DEBUG_LOG(m_logger) << "m_vecData.at(" << i << ").scriptId=" << rowData.scriptId
|
||||
<< " exerciseId=" << rowData.exerciseId
|
||||
<< " contentScriptIds.contains=" << contentScriptIds.contains(rowData.scriptId)
|
||||
<< " rowData.local=" << rowData.local
|
||||
<< " contentScriptIds.size()=" << contentScriptIds.size();
|
||||
|
||||
if (!contentScriptIds.contains(rowData.scriptId))
|
||||
{
|
||||
// the script already in the table is not available on the server side
|
||||
if (rowData.local == false)
|
||||
{
|
||||
/* script already in table is marked as non-loal, which means - in
|
||||
* combination with the script not being on the server (anymore) - that
|
||||
* the script was removed from the server after the server script list
|
||||
* was received from the server and added to the table. So remove it
|
||||
* from the table */
|
||||
DEBUG_LOG(m_logger) << "removeRow(" << i << ")"
|
||||
<< " ScriptId=" << rowData.scriptId
|
||||
<< " ExerciseId=" << rowData.exerciseId;
|
||||
removeRow(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, if it's marked as local, that means - in combination
|
||||
* with he script not being on the server (anymore) - that the script
|
||||
* is only locally available */
|
||||
setUploadState(i, ThpUploadNotActive, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get all server scripts and add them to the table if they're not already in
|
||||
* the table.LtsUtils::ProjectSettings *ps = L
|
||||
* if the corresponding row already exist then set the uploaded-state to
|
||||
* uploaded, because they came from the server list, which means they were
|
||||
* obviously uploaded at some point */
|
||||
for (const QJsonValue &val : presentations)
|
||||
{
|
||||
ExportedScriptInformation esi = ExportedScriptInformation::fromJson(val, false, ThpAlreadyUploaded);
|
||||
QVector<int> modelScriptIds = exerciseScriptIds.value(esi.exerciseId);
|
||||
DEBUG_LOG(m_logger) << " exportTime=" << esi.exportTime
|
||||
<< " scriptId=" << esi.scriptId
|
||||
<< " exerciseId=" << esi.exerciseId
|
||||
<< " exerciseName=" << esi.exerciseName
|
||||
<< " scriptName=" << esi.scriptName
|
||||
<< " fileSize=" << esi.fileSize
|
||||
<< " modelScriptIds.size=" << modelScriptIds.size();
|
||||
|
||||
// if a new script was added on the server and not available in this model already, then add it to the model
|
||||
if (!modelScriptIds.contains(esi.scriptId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "insertRow()";
|
||||
insertRow(esi);
|
||||
continue;
|
||||
}
|
||||
|
||||
// update model
|
||||
for (int i = 0; i < m_vecData.size(); i++)
|
||||
{
|
||||
const auto &rowData = m_vecData[i];
|
||||
if (rowData.scriptId == esi.scriptId &&
|
||||
rowData.exerciseId == esi.exerciseId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "setUploadState i=" << i
|
||||
<< " esi.scriptId=" << esi.scriptId
|
||||
<< " esi.exerciseId=" << esi.exerciseId
|
||||
<< " esi.fileSize=" << esi.fileSize
|
||||
<< " esi.uploadTime=" << esi.uploadTime;
|
||||
setUploadState(i, ThpAlreadyUploaded, esi.uploadTime, esi.fileSize);
|
||||
break; // can only match 1 time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
qint64 ExportedScriptsModel::downloadTime(const ExportedScriptInformation &val) const
|
||||
{
|
||||
if (!val.local) // can't be downloaded if it's not local
|
||||
return 0;
|
||||
|
||||
QString filename(QStringLiteral("%1/THP-Download/Exercise_%2/%3/index.html").arg(QDir::tempPath()).arg(val.exerciseId).arg(val.scriptId));
|
||||
DEBUG_LOG(m_logger) << "downloadTime: filename " << filename;
|
||||
|
||||
QFileInfo fi(filename);
|
||||
if (!fi.exists())
|
||||
return 0;
|
||||
|
||||
return fi.lastModified().toMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
|
||||
QVariant ExportedScriptsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!indexIsValid(index))
|
||||
return QVariant();
|
||||
|
||||
const ExportedScriptInformation &val = m_vecData[index.row()];
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if (!m_isOC
|
||||
/* because non-oc app has no "downloaded" column, telling the
|
||||
* user he has a newer version to download (by making the uploaded
|
||||
* cell fat) makes no sense */
|
||||
|
||||
|| !val.local
|
||||
/* non-downloaded scripts can't be older than the script on the server
|
||||
* because there obviously is no downloaded (local) script */
|
||||
|
||||
|| index.column() != ColUploadedTime
|
||||
|
||||
|| val.uploadTime <= (downloadTime(val) + (10 * 1000) /* 10 second grace */))
|
||||
/* if the script was downloaded from the server before the script was
|
||||
* updated / uploaded to the server again, mark the uploaded time cell
|
||||
* as fat to indicate the local, downloaded script is outdated */
|
||||
break;
|
||||
|
||||
QFont font;
|
||||
font.setBold(true);
|
||||
return font;
|
||||
}
|
||||
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case ColId:
|
||||
return val.scriptId;
|
||||
case ColExercise:
|
||||
return val.exerciseName;
|
||||
case ColName:
|
||||
return val.scriptName;
|
||||
case ColCreated:
|
||||
return QDateTime::fromMSecsSinceEpoch(val.exportTime);
|
||||
case ColDownloaded:
|
||||
{
|
||||
qint64 dlTime = downloadTime(val);
|
||||
if (dlTime == 0)
|
||||
return QVariant();
|
||||
return QDateTime::fromMSecsSinceEpoch(dlTime);
|
||||
}
|
||||
case ColUploadedTime:
|
||||
return QDateTime::fromMSecsSinceEpoch(val.uploadTime);
|
||||
case ColLocation:
|
||||
return val.local ? tr("Local") : tr("Server");
|
||||
case ColUploaded:
|
||||
switch (val.uploaded)
|
||||
{
|
||||
case ThpConnectToHost:
|
||||
return tr("Connect to host");
|
||||
case ThpUploadActive:
|
||||
return tr("Upload Active");
|
||||
case ThpUploadError:
|
||||
return tr("Upload Error");
|
||||
case ThpUploadNotActive:
|
||||
return tr("Not uploaded");
|
||||
case ThpUnknownUploadState:
|
||||
return tr("Unknown upload status");
|
||||
case ThpAlreadyUploaded:
|
||||
return tr("Already uploaded");
|
||||
}
|
||||
}
|
||||
|
||||
case Qt::UserRole:
|
||||
{
|
||||
return val.scriptId;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool ExportedScriptsModel::createDataJson(const QString &rootDirectory,
|
||||
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc,
|
||||
int exerciseId) const // TODO: static, static logger
|
||||
{
|
||||
const QString baseDir = exercisePath(rootDirectory, exerciseId);
|
||||
|
||||
if (!QDir().mkpath(baseDir)) // NOTE: returns true if already exists
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to create path " << baseDir;
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile file(baseDir + QStringLiteral("data.json"));
|
||||
DEBUG_LOG(m_logger) << "createDataJson=" << file.fileName();
|
||||
if (!file.open(QFile::ReadWrite))
|
||||
{
|
||||
QString msg(tr("Could not open data file in script directory: %1").arg(file.errorString()));
|
||||
ERROR_LOG(m_logger) << msg << " - " << file.fileName();
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
if (obj[QStringLiteral("exerciseId")].toInt() == exerciseId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << baseDir << " exists for exerciseId " << QString::number(exerciseId);
|
||||
return true;
|
||||
}
|
||||
|
||||
const ExerciseManagement::Exercise exercise = exmDtc->exercise(exerciseId);
|
||||
const AssetManagement::TrainingArea ta = asmDtc->trainingArea(exercise.trainingAreaId());
|
||||
|
||||
obj[QStringLiteral("title")] = QString::fromStdString(exercise.name());
|
||||
obj[QStringLiteral("exerciseId")] = exercise.id();
|
||||
obj[QStringLiteral("exerciseName")] = QString::fromStdString(exercise.name());
|
||||
obj[QStringLiteral("exerciseArea")] = QString::fromStdString(ta.name());
|
||||
obj[QStringLiteral("cycleTime")] = QString(QDateTime::fromMSecsSinceEpoch(exercise.beginTime()).toString() +
|
||||
QStringLiteral(" - ") + QDateTime::fromMSecsSinceEpoch(exercise.endTime()).toString());
|
||||
obj[QStringLiteral("exerciseStart")] = exercise.beginTime();
|
||||
obj[QStringLiteral("exerciseEnd")] = exercise.endTime();
|
||||
obj[QStringLiteral("exercisingForces")] = QString::fromStdString(exercise.forces());
|
||||
obj[QStringLiteral("exercisingPurpose")] = QString::fromStdString(exercise.description());
|
||||
|
||||
file.resize(0);
|
||||
file.write(QJsonDocument(obj).toJson());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ExportedScriptsModel::addDownloadData(const ExportedScriptInformation &esi)
|
||||
{
|
||||
// Add exercise to ExportRootPath
|
||||
{
|
||||
// modify exercises.json
|
||||
DEBUG_LOG(m_logger) << "Add exercise to ExportRootPath";
|
||||
|
||||
if (!QDir(esi.rootDirectory).exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot modify exercises.json as the info's root directory '"<<esi.rootDirectory<<"' does not exist!";
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(esi.rootDirectory + QDir::separator() + QStringLiteral("exercises.json"));
|
||||
if (!file.open(QFile::ReadWrite))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open " << file.fileName() << " for read/write: " << file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString key = QStringLiteral("Exercises");
|
||||
QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
QJsonArray arr = obj.value(key).toArray();
|
||||
|
||||
if (!arr.contains(esi.exerciseId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "arr.append Exercise=" << esi.exerciseId;
|
||||
arr.append(esi.exerciseId);
|
||||
}
|
||||
|
||||
obj.insert(key, arr);
|
||||
file.resize(0);
|
||||
file.write(QJsonDocument(obj).toJson());
|
||||
INFO_LOG(m_logger) << " file.write " << QJsonDocument(obj).toJson();
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
// NOTE: mkdir actually not necessary because the decompressed bzip file of the script already created the exercise directory
|
||||
const QString baseDir = exercisePath(esi.rootDirectory, esi.exerciseId);
|
||||
if (!QDir().mkpath(baseDir)) // NOTE: returns true if dir already exists
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot create destination path " << baseDir;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// modify data.json
|
||||
QFile file(baseDir + QDir::separator() + QStringLiteral("data.json"));
|
||||
DEBUG_LOG(m_logger) << "File= " << file.fileName();
|
||||
if (!file.open(QFile::ReadWrite))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open " << file.fileName() << " for read/write: " << file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString keyArray = QStringLiteral("presentations");
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
QJsonArray arr = obj.value(keyArray).toArray();
|
||||
bool exported = false;
|
||||
DEBUG_LOG(m_logger) << "arr.size=" << arr.size();
|
||||
|
||||
for (int i = 0; i < arr.size(); ++i)
|
||||
{
|
||||
auto arresi = ExportedScriptInformation::fromJson(arr.at(i));
|
||||
if (arresi.scriptId == esi.scriptId &&
|
||||
arresi.exerciseId == esi.exerciseId)
|
||||
{
|
||||
arresi.jsonPath = esi.jsonPath;
|
||||
arr[i] = esi.toJson();
|
||||
exported = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exported)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "info scriptId=" << esi.scriptId
|
||||
<< " Name=" << esi.scriptName
|
||||
<< " Exercise=" << esi.exerciseName;
|
||||
arr.append(esi.toJson());
|
||||
}
|
||||
|
||||
obj.insert(keyArray, arr);
|
||||
auto content = QJsonDocument(obj).toJson();
|
||||
|
||||
DEBUG_LOG(m_logger) << "content =" << content;
|
||||
|
||||
file.resize(0);
|
||||
file.write(content);
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
bool ExportedScriptsModel::setLocalState(const int row, const bool localHost)
|
||||
{
|
||||
ExportedScriptInformation data = getRowData(row);
|
||||
|
||||
data.local = localHost;
|
||||
//data.exportTime = exportTime;
|
||||
|
||||
DEBUG_LOG(m_logger) << "setLocalState row=" << row
|
||||
<< " scriptId=" << data.scriptId
|
||||
<< " data.scriptName=" << data.scriptName
|
||||
<< " Exercise=" << data.exerciseName;
|
||||
|
||||
bool result = setRowData(row, data);
|
||||
if (result && localHost && m_rootDirectoryToScan.contains(QStringLiteral("Download")))
|
||||
{
|
||||
data.rootDirectory = m_rootDirectoryToScan;
|
||||
setRowData(row, data); //again for new download path mabe not needed
|
||||
addDownloadData(data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ExportedScriptsModel::setUploadState(const int row,
|
||||
const UploadState uploadState,
|
||||
const qint64 uploadTime,
|
||||
const qint64 fileSize)
|
||||
{
|
||||
ExportedScriptInformation data = getRowData(row);
|
||||
data.uploaded = uploadState;
|
||||
data.uploadTime = uploadTime;
|
||||
data.fileSize = fileSize;
|
||||
return setRowData(row, data);
|
||||
}
|
||||
|
||||
bool ExportedScriptsModel::removeRow(int row)
|
||||
{
|
||||
ExportedScriptInformation data = getRowData(row);
|
||||
|
||||
if (!LtsWidgets::LtsAbstractTableModel<ExportedScriptInformation>::removeRow(row))
|
||||
return false;
|
||||
|
||||
QString baseDir = exercisePath(data.rootDirectory, data.exerciseId);
|
||||
QString filename = baseDir + QStringLiteral("data.json");
|
||||
DEBUG_LOG(m_logger) << "filename= '" << filename << "'";
|
||||
QFile file(baseDir + QStringLiteral("data.json"));
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "!file.open '" << filename << "'"
|
||||
<< " no local scripts";
|
||||
return true;
|
||||
}
|
||||
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
const int exId = obj.value(QStringLiteral("exerciseId")).toInt();
|
||||
QJsonArray arr;
|
||||
|
||||
for (const auto &esi : qAsConst(m_vecData))
|
||||
{
|
||||
if (esi.exerciseId == exId)
|
||||
arr += esi.toJson();
|
||||
}
|
||||
|
||||
obj[QStringLiteral("presentations")] = arr;
|
||||
file.resize(0);
|
||||
auto content = QJsonDocument(obj).toJson();
|
||||
DEBUG_LOG(m_logger) << "content =" << content;
|
||||
|
||||
return file.write(QJsonDocument(obj).toJson());
|
||||
}
|
||||
|
||||
QString ExportedScriptsModel::exercisePath(const QString &rootDirectory, const int exerciseId) const
|
||||
{
|
||||
QString path = QStringLiteral("%1/Exercise_%2/").arg(rootDirectory).arg(exerciseId);
|
||||
#ifndef WIN32
|
||||
path.prepend(QStringLiteral("/"));
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
|
||||
//
|
||||
// ExportedScriptInformation
|
||||
//
|
||||
QJsonValue ExportedScriptInformation::toJson() const
|
||||
{
|
||||
return QJsonObject({
|
||||
{ QStringLiteral("displayName"), scriptName },
|
||||
{ QStringLiteral("path"), jsonPath },
|
||||
{ QStringLiteral("scriptId"), scriptId },
|
||||
{ QStringLiteral("exportTime"), exportTime },
|
||||
{ QStringLiteral("fileSize"), fileSize },
|
||||
{ QStringLiteral("uploadTime"), uploadTime },
|
||||
{ QStringLiteral("exerciseName"), exerciseName },
|
||||
{ QStringLiteral("exerciseId"), exerciseId }
|
||||
});
|
||||
}
|
||||
|
||||
ExportedScriptInformation ExportedScriptInformation::fromJson(const QJsonValue &val,
|
||||
const bool local,
|
||||
const UploadState uploadState)
|
||||
{
|
||||
const QJsonObject obj = val.toObject();
|
||||
|
||||
ExportedScriptInformation esi;
|
||||
esi.local = local;
|
||||
esi.scriptName = obj[QStringLiteral("displayName")].toString();
|
||||
if (esi.scriptName.isEmpty())
|
||||
esi.scriptName = obj[QStringLiteral("name")].toString();
|
||||
esi.jsonPath = obj[QStringLiteral("path")].toString();
|
||||
esi.scriptId = obj[QStringLiteral("scriptId")].toInt();
|
||||
esi.exportTime = qRound64(obj[QStringLiteral("exportTime")].toDouble());
|
||||
esi.fileSize = obj[QStringLiteral("fileSize")].toInt();
|
||||
esi.uploaded = uploadState;
|
||||
esi.uploadTime = qRound64(obj[QStringLiteral("uploadTime")].toDouble());
|
||||
esi.exerciseName = obj[QStringLiteral("exerciseName")].toString();
|
||||
esi.exerciseId = obj[QStringLiteral("exerciseId")].toInt();
|
||||
|
||||
Q_ASSERT(esi.scriptId != -1);
|
||||
Q_ASSERT(esi.exerciseId != -1);
|
||||
|
||||
if (esi.scriptId != -1 && esi.exerciseId != -1)
|
||||
esi.valid = true;
|
||||
|
||||
return esi;
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Show the exported scripts and allow them to upload them to the server
|
||||
* $Id: tpm_exported_scripts_model.h 53111 2021-03-22 08:21:29Z wille_m $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_exported_scripts_model.h $
|
||||
* $Author: wille_m $
|
||||
* Created by Gerlinde Rudolphus, NLE, 2019-03-25
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <logger.h>
|
||||
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
|
||||
#include <Plugins/AssetManagement/asm_data_plugin_interface.h>
|
||||
#include <Common/thpcommon_export.h>
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
|
||||
enum UploadState
|
||||
{
|
||||
ThpUnknownUploadState,
|
||||
ThpUploadNotActive,
|
||||
ThpConnectToHost,
|
||||
ThpUploadActive,
|
||||
ThpAlreadyUploaded,
|
||||
ThpUploadError,
|
||||
};
|
||||
|
||||
struct ExportedScriptInformation
|
||||
{
|
||||
bool valid { false };
|
||||
|
||||
QString exerciseName;
|
||||
QString scriptName;
|
||||
QString jsonPath;
|
||||
QString rootDirectory; // temp
|
||||
qint64 exerciseId = -1;
|
||||
qint64 exportTime = 0;
|
||||
qint64 fileSize = 0;
|
||||
bool local = true; // On local Host
|
||||
UploadState uploaded = ThpUnknownUploadState;
|
||||
qint64 uploadTime = 0;
|
||||
int scriptId = -1;
|
||||
|
||||
int id() const { return scriptId; }
|
||||
|
||||
QJsonValue toJson() const;
|
||||
static ExportedScriptInformation fromJson(const QJsonValue &val,
|
||||
const bool local = true,
|
||||
const UploadState uploadStates = ThpUnknownUploadState);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class THPCOMMON_EXPORT ExportedScriptsModel : public LtsWidgets::LtsAbstractTableModel<ExportedScriptInformation>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
ColId,
|
||||
ColExercise,
|
||||
ColName,
|
||||
ColCreated,
|
||||
ColDownloaded,
|
||||
ColLocation,
|
||||
ColUploadedTime,
|
||||
ColUploaded,
|
||||
};
|
||||
explicit ExportedScriptsModel(QObject *parent = nullptr);
|
||||
|
||||
bool init(const QString &rootDirectoryToScan);
|
||||
void setServerContent(const QString &jsonArray);
|
||||
void setOC(bool isOC) { m_isOC = isOC; }
|
||||
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
bool removeRow(int row) override;
|
||||
bool setLocalState(const int row, const bool localHost);
|
||||
bool setUploadState(const int row, const UploadState uploadState, const qint64 uploadTime, const qint64 fileSize);
|
||||
bool createDataJson(const QString &rootDirectory, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc,
|
||||
int exerciseId) const;
|
||||
void addDownloadData(const ExportedScriptInformation &esi);
|
||||
|
||||
private:
|
||||
QString exercisePath(const QString &rootDirectory, const int exerciseId) const;
|
||||
qint64 downloadTime(const ExportedScriptInformation &val) const;
|
||||
|
||||
private:
|
||||
bool m_isOC { false };
|
||||
QString m_rootDirectoryToScan;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
#include "tpm_process_dialog.h"
|
||||
#include "ui_tpm_process_dialog.h"
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
ProcessOverlay::ProcessOverlay(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::ProcessOverlay)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
connect(m_ui->pbCancel, &QPushButton::clicked,
|
||||
this, [this]()
|
||||
{
|
||||
m_ui->pbCancel->setEnabled(false);
|
||||
emit signalCancel();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
ProcessOverlay::~ProcessOverlay()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void ProcessOverlay::setCancelEnabled(bool enabled)
|
||||
{
|
||||
m_ui->pbCancel->setEnabled(enabled);
|
||||
}
|
||||
|
||||
|
||||
void ProcessOverlay::setStatus(const QString &text, qint64 totalFiles, qint64 curFile, qint64 totalSize, qint64 curPos, const QString &curName)
|
||||
{
|
||||
if (!text.isEmpty()) // only set new text if not empty (we dont want to send the text on every update..
|
||||
m_ui->lblStatus->setText(text);
|
||||
|
||||
if (!curName.isEmpty()) // only set new text if not empty (we dont want to send the text on every update..
|
||||
m_ui->lblFilename->setText(curName);
|
||||
|
||||
double progressBytes = (totalSize == 0) ? (double)0 : ((double)curPos / (double)totalSize);
|
||||
double progressFiles = (((double)curFile - 1) / (double)totalFiles);
|
||||
double progressTotal = progressFiles + (progressBytes / (double)totalFiles);
|
||||
|
||||
progressBytes = qRound(progressBytes * 100);
|
||||
progressFiles = qRound(progressFiles * 100);
|
||||
progressTotal = qRound(progressTotal * 100);
|
||||
|
||||
m_ui->pbarFiles->setValue(progressFiles);
|
||||
m_ui->pbarBytes->setValue(progressBytes);
|
||||
m_ui->pbarProgress->setValue(progressTotal);
|
||||
|
||||
QLocale l;
|
||||
|
||||
if (curFile == 0)
|
||||
m_ui->lblFiles->setText(QStringLiteral(" - "));
|
||||
else
|
||||
m_ui->lblFiles->setText(QStringLiteral("%1 / %2").arg(l.toString(curFile)).arg(l.toString(totalFiles)));
|
||||
|
||||
if (curPos == 0)
|
||||
m_ui->lblBytes->setText(QStringLiteral(" - "));
|
||||
else
|
||||
m_ui->lblBytes->setText(QStringLiteral("%1 / %2").arg(l.toString(curPos)).arg(l.toString(totalSize)));
|
||||
}
|
||||
} // namespace TakehomePackageManager
|
||||
qt6-after/qt6-migrated-legatus/Lts/Plugins/TakeHomePackageManager/OldTHP/Common/tpm_process_dialog.h
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/thpcommon_export.h>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ProcessOverlay;
|
||||
}
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
class THPCOMMON_EXPORT ProcessOverlay : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProcessOverlay(QWidget *parent = nullptr);
|
||||
~ProcessOverlay();
|
||||
|
||||
void setStatus(const QString &text = QString(), qint64 totalFiles = 1, qint64 curFile = 1, qint64 totalSize = 0, qint64 curPos = 0, const QString &curName = QString());
|
||||
void setCancelEnabled(bool enabled = true);
|
||||
|
||||
signals:
|
||||
void signalCancel();
|
||||
|
||||
private:
|
||||
Ui::ProcessOverlay *m_ui;
|
||||
bool m_decompressing { false };
|
||||
};
|
||||
} // namespace TakehomePackageManager
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProcessOverlay</class>
|
||||
<widget class="QWidget" name="ProcessOverlay">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>700</width>
|
||||
<height>220</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>700</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="lblBytes">
|
||||
<property name="text">
|
||||
<string notr="true"> - </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Progress</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QProgressBar" name="pbarFiles">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="lblFiles">
|
||||
<property name="text">
|
||||
<string notr="true"> - </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblStatus">
|
||||
<property name="text">
|
||||
<string notr="true">Preparing ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QProgressBar" name="pbarBytes">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbCancel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="3">
|
||||
<widget class="Line" name="line">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="lblFilename">
|
||||
<property name="text">
|
||||
<string notr="true"> - </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Bytes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="2">
|
||||
<widget class="QProgressBar" name="pbarProgress">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Filename</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# $Id: CMakeLists.txt 51804 2020-07-31 04:47:28Z fritsche_h $
|
||||
# $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/CMakeLists.txt $
|
||||
# $Author: fritsche_h $
|
||||
#
|
||||
# Created by Gerlinde Rudolphus, NLE, 2019-03-25
|
||||
#
|
||||
|
||||
#
|
||||
# Common
|
||||
#
|
||||
SET(thp_SRCS
|
||||
tpm_gui_plugin.cpp
|
||||
tpm_gui_plugin.h
|
||||
tpm_exported_scripts_dialog.cpp
|
||||
tpm_exported_scripts_dialog.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
)
|
||||
|
||||
QT5_WRAP_UI(thp_SRCS
|
||||
tpm_exported_scripts_dialog.ui
|
||||
)
|
||||
|
||||
#TODO: auto-remove "libTakeHomePackageManagerGuiPlugin.so" from lib as this lib replaces it
|
||||
|
||||
NGL_ADD_LIBRARY2(WS ThpManagementGuiPlugin MODULE ${thp_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(ThpManagementGuiPlugin
|
||||
ThpCommon
|
||||
TpmGuiPluginInterface
|
||||
Qt6::Widgets
|
||||
Qt6::Network
|
||||
Qt6::WebSockets
|
||||
NGLLogger
|
||||
LtsWidgets
|
||||
LtsSession
|
||||
LtsDataView
|
||||
nglcompression
|
||||
nglsettings
|
||||
ngltools
|
||||
AsmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
LtsSessionData
|
||||
httq
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(ThpManagementGuiPlugin)
|
||||
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id: logger.cpp 46225 2019-03-25 13:59:56Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/logger.cpp $
|
||||
* $Author: rudolphus_g $
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "TPM.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for CentralEffectSimulation
|
||||
* $Id: logger.h 46225 2019-03-25 13:59:56Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/logger.h $
|
||||
* $Author: rudolphus_g $
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
typedef NGL::INGLLogger &LOGGER_T;
|
||||
|
||||
LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace TakeHomePackageManager
|
||||
+1244
File diff suppressed because it is too large.
Load diff
+214
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Show the exported scripts and allow them to upload them to the server
|
||||
* $Id: tpm_exported_scripts_dialog.h 51804 2020-07-31 04:47:28Z fritsche_h $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_exported_scripts_dialog.h $
|
||||
* $Author: fritsche_h $
|
||||
*
|
||||
* Created by Gerlinde Rudolphus, NLE, 2019-03-25
|
||||
* Rebuilt to use httq by Mike Wille, NLE, 2020-07-07
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <Common/tpm_exported_scripts_model.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <QUrlQuery>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ExportedScriptsDialog;
|
||||
}
|
||||
namespace NGL
|
||||
{
|
||||
class Compress;
|
||||
}
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
class QTemporaryFile;
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QNetworkRequest;
|
||||
class QFileSystemWatcher;
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
class ProcessOverlay;
|
||||
|
||||
class HttpProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HttpProcess(ExportedScriptInformation &&esi, QObject *parent);
|
||||
virtual ~HttpProcess();
|
||||
|
||||
ProcessOverlay *process() const { return m_process; }
|
||||
|
||||
|
||||
signals:
|
||||
void signalReadyRead();
|
||||
//void signalFailed(int status, const QString &msg);
|
||||
void signalSuccess();
|
||||
void signalTimeout();
|
||||
void signalCancel();
|
||||
void signalError();
|
||||
|
||||
|
||||
private slots:
|
||||
void slotReadyRead();
|
||||
void slotError();
|
||||
void slotSuccess();
|
||||
|
||||
|
||||
protected slots:
|
||||
void stopTimeout();
|
||||
void resetTimeout();
|
||||
|
||||
|
||||
private:
|
||||
void doConnections(QNetworkReply *r);
|
||||
|
||||
|
||||
protected:
|
||||
// do not connect to QNetworkReply's readyRead, connect to this classe's signalReadyRead
|
||||
QNetworkReply *post(const QString &path, QIODevice *data, const QUrlQuery &q = QUrlQuery(), const QString &contentType = QStringLiteral("application/octet-stream"));
|
||||
QNetworkReply *get(const QString &path, const QUrlQuery &q = QUrlQuery());
|
||||
QNetworkReply *deleteResource(const QString &path, const QUrlQuery &q = QUrlQuery());
|
||||
|
||||
ExportedScriptInformation m_esi;
|
||||
bool m_isError { false };
|
||||
NGL::INGLLogger &m_logger;
|
||||
ProcessOverlay *m_process;
|
||||
bool m_wasCanceled { false };
|
||||
bool m_isTimeout { false };
|
||||
|
||||
|
||||
private:
|
||||
static QNetworkRequest forgeRequest(const QString &path, const QUrlQuery &q, const QString &contentType = QString());
|
||||
|
||||
QNetworkAccessManager *m_nam;
|
||||
QTimer *m_timeout;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class UploadProcess : public HttpProcess
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UploadProcess(const QString &rootFolder, ExportedScriptInformation &&esi, QObject *parent);
|
||||
|
||||
signals:
|
||||
//void signalDone();
|
||||
|
||||
private slots:
|
||||
void compressionDone();
|
||||
|
||||
private:
|
||||
void abortCompress();
|
||||
|
||||
QTemporaryFile *m_tempFile;
|
||||
NGL::Compress *m_compress;
|
||||
QString m_rootDir;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DownloadProcess : public HttpProcess
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DownloadProcess(const QString &rootFolder, int modelRowId, ExportedScriptInformation &&esi, QObject *parent);
|
||||
|
||||
int modelRowId() const { return m_modelRowId; }
|
||||
|
||||
private slots:
|
||||
void downloadFinished();
|
||||
|
||||
signals:
|
||||
void signalDone();
|
||||
|
||||
private:
|
||||
QTemporaryFile *m_tempFile;
|
||||
NGL::Compress *m_compress { nullptr };
|
||||
int m_modelRowId { -1 };
|
||||
QString m_rootFolder;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RemoveProcess : public HttpProcess
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RemoveProcess(int modelRowId, ExportedScriptInformation &&esi, QObject *parent);
|
||||
int modelRowId() const { return m_modelRowId; }
|
||||
|
||||
signals:
|
||||
void signalDone();
|
||||
|
||||
private:
|
||||
int m_modelRowId { -1 };
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ExportedScriptsDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExportedScriptsDialog(QWidget *parent = nullptr);
|
||||
~ExportedScriptsDialog();
|
||||
|
||||
void retranslate() override;
|
||||
bool init(LtsSession::LtsSession *session);
|
||||
static QString getContentFolder(const QString &rootFolder, int exerciseId);
|
||||
|
||||
private slots:
|
||||
void uploadScript();
|
||||
void downloadScript();
|
||||
void removeScriptFromServer();
|
||||
void removeScriptLocal();
|
||||
void openScript();
|
||||
void onSelectionChanged();
|
||||
|
||||
private:
|
||||
enum class WsConnectionStatus
|
||||
{
|
||||
NotConnected,
|
||||
Connecting,
|
||||
Disconnected,
|
||||
Error,
|
||||
Connected,
|
||||
};
|
||||
|
||||
void startUpload();
|
||||
QString getContentFolder(int exerciseId) const;
|
||||
QString getRootFolder() const;
|
||||
bool initModel();
|
||||
void setWsConnectionStatus(WsConnectionStatus status);
|
||||
void setWsConnectionStatusLabel();
|
||||
|
||||
private:
|
||||
ExportedScriptsModel *m_model;
|
||||
Ui::ExportedScriptsDialog *m_ui;
|
||||
LtsSession::LtsSession *m_session;
|
||||
int m_exerciseId;
|
||||
QFileSystemWatcher *m_fsWatcher;
|
||||
QString m_lastServerContent;
|
||||
WsConnectionStatus m_wsStatus { WsConnectionStatus::NotConnected };
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace TakeHomePackageManager
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ExportedScriptsDialog</class>
|
||||
<widget class="QWidget" name="ExportedScriptsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>834</width>
|
||||
<height>491</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>The following Scripts are already exported. You can remove them from your local hard disk or upload them to the server here.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Server connection status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblWsStatus">
|
||||
<property name="text">
|
||||
<string notr="true">-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsDataView::LtsDataView" name="ltsDataView">
|
||||
<property name="showColumnCount" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolButtonsVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for ExerciseManangement
|
||||
* $Id: tpm_gui_plugin.cpp 48572 2019-10-02 11:47:04Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_gui_plugin.cpp $
|
||||
* $Author: rudolphus_g $
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#include "tpm_gui_plugin.h"
|
||||
#include "tpm_exported_scripts_dialog.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
|
||||
{
|
||||
return std::make_shared<InterfaceImpl>(session);
|
||||
}
|
||||
|
||||
|
||||
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
|
||||
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Tpm"))
|
||||
{}
|
||||
|
||||
|
||||
bool InterfaceImpl::fetchInterfaces()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString InterfaceImpl::menuGroup() const
|
||||
{
|
||||
return tr("Presentation");
|
||||
}
|
||||
|
||||
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
|
||||
{
|
||||
QVector<LtsWidgets::PluginData> ret;
|
||||
LtsWidgets::PluginData plData;
|
||||
plData.menuGroup = menuGroup();
|
||||
if (m_session->app() == LtsAppDescriptor::App::Scripts)
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eSpecial;
|
||||
else
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eAfterAction;
|
||||
plData.identifier = QLatin1String("PresentationManagement.ScriptDialog.ManageExportedScripts");
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:export_documents.svg"));
|
||||
plData.menuText = tr("Manage Exported Scripts");
|
||||
// plData.operatorRight = OperatorRights::ScriptEditorEdit;
|
||||
plData.createWidgetFunc = [this](QWidget *)
|
||||
{
|
||||
return LtsWidgets::initDialog(new ExportedScriptsDialog(), m_session);
|
||||
};
|
||||
ret.append(plData);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Gui Plugin for MarkerManagement
|
||||
* $Id: tpm_gui_plugin.h 49807 2020-02-06 09:53:16Z ehrlicher $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_gui_plugin.h $
|
||||
* $Author: ehrlicher $
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <OldTHP/tpm_gui_plugin_interface.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
|
||||
{
|
||||
Q_PLUGIN_METADATA(IID "gui:3:tpm.man")
|
||||
Q_INTERFACES(GuiPluginBase::Plugin)
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
GuiPlugin() = default;
|
||||
~GuiPlugin() = default;
|
||||
|
||||
QString pluginName() override { return QLatin1String("TakeHomePackageManager"); }
|
||||
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override
|
||||
{
|
||||
return partition == IDL::PartitionType::Exercise;
|
||||
}
|
||||
};
|
||||
|
||||
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface, public ForeignTpmGuiInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InterfaceImpl(LtsSession::LtsSession *session);
|
||||
|
||||
bool fetchInterfaces() override;
|
||||
QString menuGroup() const override;
|
||||
QVector<LtsWidgets::PluginData> getActions() override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise; }
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# $Id: CMakeLists.txt 51804 2020-07-31 04:47:28Z fritsche_h $
|
||||
# $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/CMakeLists.txt $
|
||||
# $Author: fritsche_h $
|
||||
#
|
||||
# Created by Mike Wille, SLTE, 2020-03-23
|
||||
#
|
||||
|
||||
SET(src
|
||||
tpm_usb_gui_plugin.cpp
|
||||
tpm_usb_gui_plugin.h
|
||||
tpm_usb_dialog.cpp
|
||||
tpm_usb_dialog.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
)
|
||||
|
||||
QT5_WRAP_UI(src
|
||||
tpm_usb_dialog.ui
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY2(WS ThpUsbManagementGuiPlugin MODULE ${src})
|
||||
NGL_TARGET_LINK_LIBRARIES(ThpUsbManagementGuiPlugin
|
||||
ThpCommon
|
||||
TpmGuiPluginInterface
|
||||
Qt6::Widgets
|
||||
Qt6::Network
|
||||
Qt6::WebSockets
|
||||
NGLLogger
|
||||
LtsWidgets
|
||||
LtsSession
|
||||
LtsDataView
|
||||
nglcompression
|
||||
nglsettings
|
||||
ngltools
|
||||
LtsSessionData
|
||||
|
||||
# for creating data.json
|
||||
AsmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(ThpUsbManagementGuiPlugin)
|
||||
|
||||
qt6-after/qt6-migrated-legatus/Lts/Plugins/TakeHomePackageManager/OldTHP/ThpUsbManagement/logger.cpp
Executable
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id: logger.cpp 46225 2019-03-25 13:59:56Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/logger.cpp $
|
||||
* $Author: rudolphus_g $
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "TPM.USB.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for CentralEffectSimulation
|
||||
* $Id: logger.h 46225 2019-03-25 13:59:56Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/logger.h $
|
||||
* $Author: rudolphus_g $
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
typedef NGL::INGLLogger &LOGGER_T;
|
||||
|
||||
LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace TakeHomePackageManager
|
||||
+1699
File diff suppressed because it is too large.
Load diff
+138
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Show the exported scripts and allow them to upload them to the server
|
||||
* $Id: tpm_exported_scripts_dialog.h 51804 2020-07-31 04:47:28Z fritsche_h $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_exported_scripts_dialog.h $
|
||||
* $Author: fritsche_h $
|
||||
*
|
||||
* Created by Mike Wille, SLTE, 2020-03-23
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <QFileInfoList>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class USBDialog;
|
||||
}
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
class ExportedScriptsModel;
|
||||
|
||||
enum eLayerType
|
||||
{
|
||||
elevation,
|
||||
map,
|
||||
sceneObject,
|
||||
scene
|
||||
};
|
||||
|
||||
struct layerMappinEntry
|
||||
{
|
||||
eLayerType type;
|
||||
QString description;
|
||||
int maxScale;
|
||||
int minScale;
|
||||
QString name;
|
||||
QString url;
|
||||
|
||||
public:
|
||||
|
||||
layerMappinEntry()
|
||||
: type(eLayerType::map), description(QStringLiteral("NOTSET")), maxScale(125), minScale(-1), name(QStringLiteral("_name")), url(QStringLiteral("_url"))
|
||||
{
|
||||
|
||||
}
|
||||
layerMappinEntry(eLayerType _type, QString _description, int _maxScale, int _minScale, QString _name, QString _url)
|
||||
: type(_type), description(_description), maxScale(_maxScale), minScale(_minScale), name(_name), url(_url)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class USBDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief USBDialog => WARNING: throws! catch exception!
|
||||
* @param session
|
||||
* @param parent
|
||||
*/
|
||||
explicit USBDialog(LtsSession::LtsSession *session, QWidget *parent = nullptr);
|
||||
~USBDialog();
|
||||
|
||||
void retranslate() override;
|
||||
|
||||
static QString getContentFolder(const QString &rootFolder, int exerciseId);
|
||||
QString getContentFolder(const QString &rootFolder) const;
|
||||
|
||||
static QString exerciseDirectoryName(int exerciseId);
|
||||
static QString getScriptFolder(const QString &rootFolder, int exerciseId, int scriptId);
|
||||
|
||||
signals:
|
||||
void nextMap();
|
||||
|
||||
private slots:
|
||||
void slotSelectionChanged();
|
||||
|
||||
void slotCopy();
|
||||
void slotCopyMaps();
|
||||
void slotCopyWinBin();
|
||||
void slotCopyWinBinP2();
|
||||
void slotCopyWinBinP3();
|
||||
|
||||
void slotRemove();
|
||||
void slotRemoveMaps();
|
||||
|
||||
void slotChangePath();
|
||||
void onNextMap();
|
||||
void generateLayerMappingXML();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
enum class What
|
||||
{
|
||||
ScriptWasDeletedFromExercise,
|
||||
ExerciseDirectoryWasDeleted,
|
||||
NewExerciseDirectoryWasCreated,
|
||||
ScriptWasCopiedToExercise,
|
||||
};
|
||||
|
||||
void adjustJsonFiles(What what);
|
||||
void initModel();
|
||||
void initUsbModel();
|
||||
void scriptDeleted(int scriptId);
|
||||
void scriptCopied(int scriptId);
|
||||
QFileInfoList prepareFileInfoListForFolder(QString src, QFileInfoList fil);
|
||||
|
||||
QString getContentFolder(int exerciseId) const;
|
||||
QString getContentFolder() const;
|
||||
QString getRootFolder(bool forceDownloadDir = false) const;
|
||||
QString exerciseDirectoryName() const;
|
||||
QString getScriptFolder(const QString &rootFolder, int scriptId) const;
|
||||
QString getScriptFolder(int scriptId) const;
|
||||
|
||||
ExportedScriptsModel *m_localThpModel;
|
||||
ExportedScriptsModel *m_usbThpModel;
|
||||
Ui::USBDialog *m_ui;
|
||||
LtsSession::LtsSession *m_session;
|
||||
int m_exerciseId;
|
||||
int m_paths;
|
||||
QMap<QString, QFileInfoList> m_files;
|
||||
|
||||
QString m_usbRoot;
|
||||
NGL::INGLLogger &m_logger;
|
||||
int m_finished_mapCopys;
|
||||
};
|
||||
} // namespace TakeHomePackageManager
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>USBDialog</class>
|
||||
<widget class="QWidget" name="USBDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1081</width>
|
||||
<height>541</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QGroupBox" name="verticalGroupBox">
|
||||
<property name="title">
|
||||
<string>Local</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>THPs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="tvLocal">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbCopy">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy selected THPs to USB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Maps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tvLocalMaps">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Path</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbCopyMaps">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy selected Maps to USB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="verticalGroupBox_2">
|
||||
<property name="title">
|
||||
<string>On USB</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPath">
|
||||
<property name="text">
|
||||
<string>(none)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbCHange">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>THPs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tvUSB">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbRemove">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove selected THPs from USB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_5">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Maps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tvUSBMaps">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbRemoveMaps">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove selected Maps from USB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for ExerciseManangement
|
||||
* $Id: tpm_gui_plugin.cpp 48572 2019-10-02 11:47:04Z rudolphus_g $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_gui_plugin.cpp $
|
||||
* $Author: rudolphus_g $
|
||||
*
|
||||
* Created by Mike Wille, SLTE, 2020-03-23
|
||||
*/
|
||||
|
||||
#include "tpm_usb_gui_plugin.h"
|
||||
#include "tpm_usb_dialog.h"
|
||||
#include "logger.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
|
||||
{
|
||||
return std::make_shared<InterfaceImpl>(session);
|
||||
}
|
||||
|
||||
|
||||
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
|
||||
: GuiPluginBase::Interface(session, getLogger("Plugin"))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::fetchInterfaces()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString InterfaceImpl::menuGroup() const
|
||||
{
|
||||
return tr("Presentation");
|
||||
}
|
||||
|
||||
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
|
||||
{
|
||||
|
||||
QVector<LtsWidgets::PluginData> ret;
|
||||
|
||||
LtsWidgets::PluginData plData;
|
||||
plData.menuGroup = menuGroup();
|
||||
|
||||
if (m_session->app() == LtsAppDescriptor::App::Scripts)
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eSpecial;
|
||||
else
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eAfterAction;
|
||||
|
||||
plData.identifier = QLatin1String("THP.USB.Dialog");
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:export_documents.svg"));
|
||||
plData.menuText = tr("USB Management");
|
||||
// plData.operatorRight = OperatorRights::ScriptEditorEdit;
|
||||
plData.createWidgetFunc = [this](QWidget *)
|
||||
{
|
||||
return LtsWidgets::createThrowableDialog<USBDialog>(m_session);
|
||||
};
|
||||
ret.append(plData);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Gui Plugin for MarkerManagement
|
||||
* $Id: tpm_gui_plugin.h 49807 2020-02-06 09:53:16Z ehrlicher $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_03_salted_caramel/Lts/Plugins/TakeHomePackageManager/tpm_gui_plugin.h $
|
||||
* $Author: ehrlicher $
|
||||
*
|
||||
* Created by Mike Wille, SLTE, 2020-03-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <OldTHP/tpm_gui_plugin_interface.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
|
||||
{
|
||||
Q_PLUGIN_METADATA(IID "gui:3:tpm.usb")
|
||||
Q_INTERFACES(GuiPluginBase::Plugin)
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
GuiPlugin() = default;
|
||||
~GuiPlugin() = default;
|
||||
|
||||
QString pluginName() override { return QLatin1String("ThpUsbManager"); }
|
||||
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override
|
||||
{
|
||||
return partition == IDL::PartitionType::Exercise;
|
||||
}
|
||||
};
|
||||
|
||||
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface, public ForeignTpmGuiInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InterfaceImpl(LtsSession::LtsSession *session);
|
||||
|
||||
bool fetchInterfaces() override;
|
||||
QString menuGroup() const override;
|
||||
QVector<LtsWidgets::PluginData> getActions() override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise; }
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* HMI Plugin for Exercisemanagemt (Interface for access from other Plugins)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
|
||||
class ForeignTpmGuiInterface
|
||||
{
|
||||
public:
|
||||
ForeignTpmGuiInterface() = default;
|
||||
virtual ~ForeignTpmGuiInterface() = default;
|
||||
static QString pluginName() { return QStringLiteral("TpmGuiPlugin"); }
|
||||
};
|
||||
|
||||
} // namespace TakeHomePackageManager
|
||||
Executable
+135
@@ -0,0 +1,135 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLSE, 2017-02-10
|
||||
#
|
||||
|
||||
|
||||
# EventFilter
|
||||
SET(EventFilter_SRCS
|
||||
EventFilter/AttributeEditingModeUI.h
|
||||
EventFilter/AttributeEditingModeUI.cpp
|
||||
EventFilter/AttributeSelectionModeUI.h
|
||||
EventFilter/AttributeSelectionModeUI.cpp
|
||||
|
||||
EventFilter/FilterWindow.h
|
||||
EventFilter/FilterWindow.cpp
|
||||
EventFilter/FilterTableEntry.h
|
||||
EventFilter/FilterTableEntry.cpp
|
||||
EventFilter/FilterTableEntryAttribute.h
|
||||
EventFilter/FilterTableEntryAttribute.cpp
|
||||
|
||||
EventFilter/interpreter/FilterWorker.h
|
||||
EventFilter/interpreter/FilterWorker.cpp
|
||||
|
||||
EventFilter/widgets/AbstractAttributeWidget.cpp
|
||||
EventFilter/widgets/ComboBox.cpp
|
||||
EventFilter/widgets/TimeRangeWidget.cpp
|
||||
EventFilter/widgets/AreaWidget.cpp
|
||||
EventFilter/widgets/DefaultRangeWidget.cpp
|
||||
EventFilter/widgets/CheckBoxWidget.cpp
|
||||
EventFilter/widgets/RadiusWidget.cpp
|
||||
|
||||
EventFilter/interpreter/InfoWindow.h
|
||||
EventFilter/interpreter/InfoWindow.cpp
|
||||
EventFilter/interpreter/FilterEquationFunctions.cpp
|
||||
EventFilter/interpreter/FilterValueInterpreter.cpp
|
||||
|
||||
EventFilter/widgets/AbstractAttributeWidget.h
|
||||
EventFilter/widgets/ComboBox.h
|
||||
EventFilter/widgets/TimeRangeWidget.h
|
||||
EventFilter/widgets/AreaWidget.h
|
||||
EventFilter/widgets/DefaultRangeWidget.h
|
||||
EventFilter/widgets/CheckBoxWidget.h
|
||||
EventFilter/widgets/RadiusWidget.h
|
||||
|
||||
EventFilter/interpreter/FilterEquationFunctions.h
|
||||
EventFilter/interpreter/FilterValueInterpreter.h
|
||||
|
||||
detail_data.h
|
||||
detail_data.cpp
|
||||
excon_filter.h
|
||||
excon_filter.cpp
|
||||
logger.h
|
||||
logger.cpp
|
||||
)
|
||||
|
||||
SET(EventFilter_UICS
|
||||
EventFilter/ui/FilterWindowUi.ui
|
||||
)
|
||||
|
||||
|
||||
# Timeline
|
||||
SET(tln_view_gui_SRCS
|
||||
attribute_value_lookup.cpp
|
||||
attribute_value_lookup.h
|
||||
tln_view_gui_plugin.cpp
|
||||
tln_view_gui_plugin.h
|
||||
tln_dialog.cpp
|
||||
tln_dialog.h
|
||||
tln_dialog_model.cpp
|
||||
tln_dialog_model.h
|
||||
tln_cache_dialog.cpp
|
||||
tln_cache_dialog.h
|
||||
tln_show_details.cpp
|
||||
tln_show_details.h
|
||||
tln_event_list.h
|
||||
tln_event_list.cpp
|
||||
tln_event_list_model.h
|
||||
tln_event_list_model.cpp
|
||||
tln_event_list_columns.h
|
||||
tln_event_list_columns.cpp
|
||||
tln_legend.h
|
||||
tln_legend.cpp
|
||||
|
||||
${EventFilter_SRCS}
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(tln_view_gui_SRCS
|
||||
tln_dialog.ui
|
||||
tln_cache_dialog.ui
|
||||
tln_show_details.ui
|
||||
tln_event_list.ui
|
||||
tln_event_list_columns.ui
|
||||
tln_legend.ui
|
||||
|
||||
${EventFilter_UICS}
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(WS TlnViewGuiPlugin MODULE ${tln_view_gui_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(TlnViewGuiPlugin
|
||||
Qt5::Widgets
|
||||
Qt5::WebSockets
|
||||
|
||||
LtsAppManager
|
||||
LtsDataView
|
||||
LtsTimelineClassic
|
||||
LtsPrinting
|
||||
LtsSession
|
||||
LtsSessionData
|
||||
LtsUtilsCore # data mod
|
||||
LtsUtilsGuiDds
|
||||
LtsUtilsSettings
|
||||
LtsWidgets
|
||||
NGLLogger
|
||||
ngltools # dtg
|
||||
|
||||
AvmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
IsmDataPluginInterface
|
||||
MrkDataPluginInterface
|
||||
OpmDataPluginInterface
|
||||
PdmDataPluginInterface
|
||||
PpmDataPluginInterface
|
||||
|
||||
FlmExplorerGuiPluginInterface
|
||||
FltAesGuiPluginInterface # SitMap Filter
|
||||
TlnDataPluginInterface
|
||||
TlnViewGuiPluginInterface
|
||||
|
||||
MrkCommon # SitMap Filter Helper
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(TlnViewGuiPlugin)
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for attributes for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
//#include "FilterWindow.h" // for debug messagebox
|
||||
#include "AttributeEditingModeUI.h"
|
||||
#include "../detail_data.h"
|
||||
|
||||
#include "widgets/TimeRangeWidget.h"
|
||||
#include "widgets/DefaultRangeWidget.h"
|
||||
#include "widgets/ComboBox.h"
|
||||
#include "widgets/CheckBoxWidget.h"
|
||||
#include "widgets/AreaWidget.h"
|
||||
#include "widgets/RadiusWidget.h"
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
AbstractAttributeWidget *EditingModeUI::createAttributeUIWidget(DetailData *detailData, const QString &attributeType,
|
||||
int eventType, const QString &initialValue) // create a widget, suitable for the attribute
|
||||
{
|
||||
AbstractAttributeWidget *resultWidget = nullptr;
|
||||
QString concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
|
||||
int attributeUIType = detailData->attributeUITypeLookup.getUIType(concreteAttributeType);
|
||||
|
||||
if (attributeUIType == -1) // not found? abort!
|
||||
return nullptr;
|
||||
|
||||
//WARNING_LOG(m_logger) << "createAttributeUIWidget: for attributeType " << attributeType << " with string " << initialValue << " and attribute ui type " << attributeUIType;
|
||||
|
||||
const DetailData::AttributeParameterLookup::ParameterMap &pm = detailData->attributeParameterLookup.getParameterMap(concreteAttributeType); //const DetailData::UIInitialValuesLookup::ParameterValuesMap& pvm = filterData->uiInitialValuesLookup.getUIInitialValuesMap(attributeUIType); // initial values to be used to create widgets with intiaial values.....
|
||||
|
||||
switch (attributeUIType)
|
||||
{
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_COMBO_BOX: // do not use pm !
|
||||
{
|
||||
resultWidget = new ComboBox(detailData, concreteAttributeType, eventType, initialValue); // get the combobox for the attribute (which is then filled with possible values)
|
||||
break;
|
||||
}
|
||||
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET:
|
||||
{
|
||||
bool minb = false;
|
||||
unsigned int min = pm.value(DetailData::UI_PARAM_TYPE_MIN).toUInt(&minb);
|
||||
|
||||
bool maxb = false;
|
||||
unsigned int max = pm.value(DetailData::UI_PARAM_TYPE_MAX).toUInt(&maxb);
|
||||
|
||||
QString prefix = pm.value(DetailData::UI_PARAM_TYPE_PREFIX).toString();
|
||||
|
||||
QString suffix = pm.value(DetailData::UI_PARAM_TYPE_SUFFIX).toString();
|
||||
|
||||
|
||||
if (!minb || !maxb) // || prefix.isEmpty() || suffix.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "createAttributeUIWidget: !minb (" << minb << ") || !maxb (" << maxb << ")"; // || prefix.isEmpty ("<<prefix.isEmpty()<<") || suffix.isEmpty ("<<suffix.isEmpty()<<")" << ;
|
||||
break;
|
||||
}
|
||||
|
||||
resultWidget = new DefaultRangeWidget(min, max, prefix, suffix, initialValue);
|
||||
break;
|
||||
}
|
||||
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET:
|
||||
{
|
||||
bool n1k = false;
|
||||
int n1 = pm.value(DetailData::UI_PARAM_TYPE_N1).toUInt(&n1k);
|
||||
|
||||
bool n2k = false;
|
||||
int n2 = pm.value(DetailData::UI_PARAM_TYPE_N2).toUInt(&n2k);
|
||||
|
||||
bool o1k = false;
|
||||
int o1 = pm.value(DetailData::UI_PARAM_TYPE_O1).toUInt(&o1k);
|
||||
|
||||
bool o2k = false;
|
||||
int o2 = pm.value(DetailData::UI_PARAM_TYPE_O2).toUInt(&o2k);
|
||||
|
||||
bool rk = false;
|
||||
int r = pm.value(DetailData::UI_PARAM_TYPE_RAD).toUInt(&rk);
|
||||
|
||||
if (n1k && n2k && o1k && o2k && rk)
|
||||
{
|
||||
resultWidget = new RadiusWidget(n1, n2, o1, o2, r); // set by zwmstl_timelineFilterData TODO: initial value !
|
||||
break;
|
||||
}
|
||||
|
||||
WARNING_LOG(m_logger) << "DetailData::ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET: errorious values!";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET:
|
||||
{
|
||||
bool n1k = false;
|
||||
int n1 = pm.value(DetailData::UI_PARAM_TYPE_N1).toUInt(&n1k);
|
||||
|
||||
bool n2k = false;
|
||||
int n2 = pm.value(DetailData::UI_PARAM_TYPE_N2).toUInt(&n2k);
|
||||
|
||||
bool o1k = false;
|
||||
int o1 = pm.value(DetailData::UI_PARAM_TYPE_O1).toUInt(&o1k);
|
||||
|
||||
bool o2k = false;
|
||||
int o2 = pm.value(DetailData::UI_PARAM_TYPE_O2).toUInt(&o2k);
|
||||
|
||||
if (n1k && n2k && o1k && o2k)
|
||||
{
|
||||
resultWidget = new AreaWidget(n1, n2, o1, o2); // set by zwmstl_timelineFilterData TODO: initial value !
|
||||
break;
|
||||
}
|
||||
|
||||
WARNING_LOG(m_logger) << "DetailData::ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET: errorious values!";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_CHECKBOX:
|
||||
{
|
||||
resultWidget = new CheckBoxWidget(detailData, concreteAttributeType, initialValue); // 1 = 'true'-value from the list (must not have that wordly negative sound)
|
||||
break;
|
||||
}
|
||||
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET:
|
||||
{
|
||||
TimeRangeWidget *trw = new TimeRangeWidget(detailData, initialValue); // update parameter lists filled by EventFilter-using component for specific widgets
|
||||
detailData->createRetrieveCurrentTimeCallback(trw->m_edit1);
|
||||
detailData->createRetrieveCurrentTimeCallback(trw->m_edit2);
|
||||
resultWidget = trw;
|
||||
break;
|
||||
}
|
||||
|
||||
default: // invalid attribute type!
|
||||
{
|
||||
WARNING_LOG(m_logger) << "createAttributeUIWidget: invalid attribute type #" << attributeUIType << "!";
|
||||
//return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//resultWidget->setStyleSheet("background-color:#CC9B97;"); // layer 3
|
||||
return resultWidget;
|
||||
}
|
||||
|
||||
void EditingModeUI::addAttributeContainer(int eventType, const QString &initialValue)
|
||||
{
|
||||
//attributeValuesLayout->addWidget(createAttributeUIWidget(attributeType), 0, Qt::AlignTop);
|
||||
|
||||
AbstractAttributeWidget *attributeUIWidget = createAttributeUIWidget(m_detailData, attributeType, eventType, initialValue);
|
||||
|
||||
if (attributeUIWidget == nullptr)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "addAttributeContainer: !attributeUIWidget";
|
||||
return;
|
||||
}
|
||||
|
||||
connect(attributeUIWidget, &AbstractAttributeWidget::destroyed, this, &EditingModeUI::signalChanges);
|
||||
connect(attributeUIWidget, &AbstractAttributeWidget::signalChanges, this, &EditingModeUI::signalChanges);
|
||||
|
||||
attributeValuesLayout->insertWidget(0, attributeUIWidget, 0, Qt::AlignTop);
|
||||
attributeUIWidget->setFocus(); // set focus to new widget
|
||||
}
|
||||
|
||||
EditingModeUI::EditingModeUI(DetailData *detailData, const QString &attributeType, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, attributeType(attributeType)
|
||||
, m_detailData(detailData)
|
||||
, m_logger(getLogger("EventFilter.EditingModeUI"))
|
||||
{
|
||||
QVBoxLayout *editingModeLayout = new QVBoxLayout;
|
||||
|
||||
QWidget *filterTextWidget = new QWidget; // contains the filter text + widget to delete whole filter
|
||||
QHBoxLayout *filterTextLayout = new QHBoxLayout;
|
||||
filterTextWidget->setLayout(filterTextLayout);
|
||||
|
||||
pbDelete = new QPushButton(QStringLiteral("-"));
|
||||
pbDelete->setToolTip(tr("Delete this attribute and all its values"));
|
||||
pbDelete->setPalette(QPalette(QColor("red")));
|
||||
pbDelete->setMaximumWidth(30);
|
||||
|
||||
lbFilterText = new QLabel;
|
||||
|
||||
filterTextLayout->addWidget(lbFilterText, 0, Qt::AlignLeft);
|
||||
filterTextLayout->addWidget(pbDelete, 1, Qt::AlignLeft);
|
||||
|
||||
|
||||
QWidget *attributeValuesWidget = new QWidget;
|
||||
attributeValuesLayout = new QVBoxLayout();
|
||||
attributeValuesWidget->setLayout(attributeValuesLayout); // add layout to widget
|
||||
pbAddAttributeContainer = new QPushButton(tr("Add Value"));
|
||||
pbAddAttributeContainer->setPalette(QPalette(QColor("green")));
|
||||
|
||||
// add all widgets to editing mode main widget
|
||||
setLayout(editingModeLayout);
|
||||
editingModeLayout->addWidget(filterTextWidget, 0, Qt::AlignTop);
|
||||
|
||||
// horizontal line after filter text
|
||||
QWidget *horizontalLineWidget = new QWidget;
|
||||
horizontalLineWidget->setFixedHeight(2);
|
||||
horizontalLineWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
horizontalLineWidget->setStyleSheet(QStringLiteral("background-color: #c0c0c0;"));
|
||||
editingModeLayout->addWidget(horizontalLineWidget, 0, Qt::AlignTop);
|
||||
|
||||
editingModeLayout->addWidget(pbAddAttributeContainer, 0, Qt::AlignTop | Qt::AlignLeft);
|
||||
editingModeLayout->addWidget(attributeValuesWidget, 0, Qt::AlignTop); // add attribute values "list" to this, so it can be searched through for attribute values
|
||||
}
|
||||
|
||||
EditingModeUI::~EditingModeUI()
|
||||
{
|
||||
const auto children = findChildren<AbstractAttributeWidget*>();
|
||||
for (auto child : children)
|
||||
child->disconnect(this);
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for attributes for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QVBoxLayout;
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
class AbstractAttributeWidget;
|
||||
|
||||
|
||||
class EditingModeUI : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EditingModeUI(DetailData *detailData, const QString &attributeType, QWidget *parent);
|
||||
~EditingModeUI();
|
||||
|
||||
void addAttributeContainer(int eventType, const QString &initialValue = QString()); // 0 = default val (do not set -1 invalid !)
|
||||
|
||||
QLabel *lbFilterText;
|
||||
QPushButton *pbDelete;
|
||||
QVBoxLayout *attributeValuesLayout;
|
||||
QPushButton *pbAddAttributeContainer; // does not end this mode, adds an attribute container
|
||||
|
||||
private:
|
||||
Timeline::AbstractAttributeWidget *createAttributeUIWidget(DetailData *detailData, const QString &attributeType,
|
||||
int eventType, const QString &initialValue);
|
||||
|
||||
signals:
|
||||
void signalChanges();
|
||||
private:
|
||||
QString attributeType;
|
||||
DetailData *m_detailData;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for events for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "../detail_data.h"
|
||||
#include "AttributeSelectionModeUI.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
QComboBox *SelectionModeUI::createAttributesComboBox(int eventType)
|
||||
{
|
||||
QComboBox *cbAttributes = new QComboBox();
|
||||
|
||||
// 1. get all event type's attribute types!
|
||||
// 2. get all attribute type's attribute texts! getAttributeText(..)
|
||||
|
||||
DetailData::AttributeEventLookup::AttributeList attributeList = m_detailData->attributeEventLookup.getEventsAttributeList(eventType);
|
||||
|
||||
for (auto i = attributeList.constBegin(); i != attributeList.constEnd(); ++i)
|
||||
{
|
||||
const QString &attributeKey = m_detailData->attributeRedirectionLookup.getRedirection(*i); // key (derefd')!
|
||||
|
||||
// Do not allow filtering for INTERPRETER_TYPE_NONE (e.g. Marker)
|
||||
if (m_detailData->attributeInterpreterLookup.getInterpreterType(attributeKey) == DetailData::INTERPRETER_TYPE_NONE)
|
||||
continue;
|
||||
|
||||
QString cbAttribute = m_detailData->attributeTypeLookup.getAttributeText(attributeKey);
|
||||
|
||||
if (cbAttribute.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "SelectionModeUI::createAttributesComboBox: event type " << eventType << " has no attribute text for attribute " << attributeKey << " for attribute event lookup - not added";
|
||||
}
|
||||
else
|
||||
{
|
||||
cbAttributes->addItem(cbAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
return cbAttributes;
|
||||
}
|
||||
|
||||
|
||||
SelectionModeUI::SelectionModeUI(DetailData *detailData, const int eventType)
|
||||
: eventType(eventType)
|
||||
, m_detailData(detailData)
|
||||
, m_logger(getLogger("EventFilter.AttributeEditingModeUI"))
|
||||
{
|
||||
selectionModeWidget = new QWidget();
|
||||
selectionModeLayout = new QHBoxLayout();
|
||||
|
||||
lbFilterText = new QLabel(tr("Select attribute type to filter:"));
|
||||
cbAttributeType = createAttributesComboBox(eventType); // create a combobox with all attributes for the given event type
|
||||
|
||||
pbAddEditingMode = new QPushButton(tr("OK"));
|
||||
pbAddEditingMode->setToolTip(tr("Add this attribute and start adding values"));
|
||||
pbAddEditingMode->setPalette(QPalette(QColor("green")));
|
||||
pbAddEditingMode->setMaximumWidth(30);
|
||||
|
||||
pbDeleteFilter = new QPushButton(QStringLiteral("-"));
|
||||
pbDeleteFilter->setPalette(QPalette(QColor("red")));
|
||||
pbDeleteFilter->setToolTip(tr("Delete this attribute and all its values"));
|
||||
pbDeleteFilter->setMaximumWidth(30);
|
||||
|
||||
selectionModeLayout->addWidget(lbFilterText, 0, Qt::AlignCenter);
|
||||
selectionModeLayout->addWidget(cbAttributeType, 0, Qt::AlignTop);
|
||||
selectionModeLayout->addWidget(pbAddEditingMode, 0, Qt::AlignTop);
|
||||
selectionModeLayout->addWidget(pbDeleteFilter, 1, Qt::AlignTop);
|
||||
|
||||
selectionModeWidget->setLayout(selectionModeLayout);
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for events for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class SelectionModeUI : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
SelectionModeUI &operator=(const SelectionModeUI &); // no implementation
|
||||
|
||||
public:
|
||||
QComboBox *createAttributesComboBox(int eventType);
|
||||
|
||||
// >>>>>>> (EVENT_TYPE has (ATTRIBUTE_TYPE has (FilterData::ATTRIBUTE_UI_TYPE and POSSIBLE_VALUES)))
|
||||
|
||||
explicit SelectionModeUI(DetailData *detailData, const int eventType);
|
||||
|
||||
~SelectionModeUI()
|
||||
{
|
||||
delete lbFilterText;
|
||||
delete cbAttributeType;
|
||||
delete pbAddEditingMode;
|
||||
delete selectionModeLayout;
|
||||
delete selectionModeWidget;
|
||||
}
|
||||
|
||||
int eventType;
|
||||
QWidget *selectionModeWidget;
|
||||
QHBoxLayout *selectionModeLayout;
|
||||
QLabel *lbFilterText;
|
||||
QComboBox *cbAttributeType;
|
||||
QPushButton *pbAddEditingMode;
|
||||
QPushButton *pbDeleteFilter;
|
||||
DetailData *m_detailData;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* entry to manage a specific filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "FilterTableEntry.h"
|
||||
#include "FilterTableEntryAttribute.h"
|
||||
#include "interpreter/FilterWorker.h"
|
||||
#include "../detail_data.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QSizePolicy>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
FilterTableEntry::FilterTableEntry(DetailData *detailData, const int &eventType, const bool &active, QWidget *parent) // directly creates ftw with selected event type
|
||||
: QGroupBox(parent)
|
||||
, m_logger(getLogger("EventFilter.FilterTableEntry"))
|
||||
, m_eventType(eventType)
|
||||
|
||||
// ui
|
||||
, m_mainLayout(new QVBoxLayout())
|
||||
, m_topLayout(new QHBoxLayout())
|
||||
, m_centerLayout(new QHBoxLayout())
|
||||
, m_cbEventSelector(nullptr) // prepare cb
|
||||
, m_pbDelete(new QPushButton(QStringLiteral("-")))
|
||||
, m_pbFoundEvents(new QPushButton(tr("Show Events")))
|
||||
, m_pbFilterActive(new QPushButton(tr("Active")))
|
||||
, m_pbOK(new QPushButton(tr("OK")))
|
||||
, m_lbSelectText(new QLabel(tr("Select event type to filter:")))
|
||||
, m_detailData(detailData)
|
||||
{
|
||||
m_cbEventSelector = getEventTypesComboBox();
|
||||
|
||||
m_pbDelete->setPalette(QPalette(QColor("red")));
|
||||
m_pbDelete->setToolTip(tr("Delete this filter and all its attributes"));
|
||||
|
||||
m_pbFilterActive->setPalette(QPalette(QColor("orange")));
|
||||
m_pbFoundEvents->setPalette(QPalette(QColor("orange")));
|
||||
m_pbOK->setPalette(QPalette(QColor("green")));
|
||||
|
||||
m_pbOK->setToolTip(tr("Add this filter and start adding attributes (when needed)"));
|
||||
connect(m_pbFilterActive, &QPushButton::clicked, this, &FilterTableEntry::signalChanges);
|
||||
|
||||
// soft init: only init cb & ok-button (mini-selection mode)
|
||||
|
||||
|
||||
setLayout(m_mainLayout);
|
||||
|
||||
|
||||
// top layout
|
||||
QWidget *topLayoutWidget = new QWidget(this);
|
||||
//topLayoutWidget->setStyleSheet("background-color:#97B0CC"); //#D6FFFF;"); // layer 1
|
||||
|
||||
topLayoutWidget->setLayout(m_topLayout);
|
||||
|
||||
m_mainLayout->addWidget(topLayoutWidget, 0, Qt::AlignTop); // add top widget with top alingment
|
||||
|
||||
|
||||
// start mini-selection mode
|
||||
m_topLayout->addWidget(m_lbSelectText, 0, Qt::AlignLeft);
|
||||
m_topLayout->addWidget(m_cbEventSelector, 0, Qt::AlignLeft);
|
||||
|
||||
m_pbOK->setMinimumWidth(30);
|
||||
m_pbOK->setMaximumWidth(30);
|
||||
m_topLayout->addWidget(m_pbOK, 0, Qt::AlignLeft);
|
||||
connect(m_pbOK, &QPushButton::clicked, this, &FilterTableEntry::slotSelectEventType); // end selection mode => start editing mode
|
||||
|
||||
connect(m_pbDelete, &QPushButton::clicked, this, &FilterTableEntry::deleteLater);
|
||||
m_pbDelete->setMinimumWidth(30);
|
||||
m_pbDelete->setMaximumWidth(30);
|
||||
m_topLayout->addWidget(m_pbDelete, 1, Qt::AlignLeft);
|
||||
|
||||
QWidget *centerLayoutWidget = new QWidget(this);
|
||||
centerLayoutWidget->setStyleSheet(topLayoutWidget->styleSheet());
|
||||
centerLayoutWidget->setLayout(m_centerLayout);
|
||||
m_mainLayout->addWidget(centerLayoutWidget, 0);
|
||||
|
||||
if (m_eventType > -1)
|
||||
slotSelectEventType(); // start making it a ready to use event filter for a specific event
|
||||
|
||||
m_pbFoundEvents->setEnabled(active);
|
||||
m_pbFilterActive->setCheckable(true);
|
||||
m_pbFilterActive->setChecked(active);
|
||||
m_pbFilterActive->setToolTip(m_pbFilterActive->isChecked() ? tr("Filter is active") : tr("Filter is inactive"));
|
||||
}
|
||||
|
||||
FilterTableEntry::~FilterTableEntry()
|
||||
{
|
||||
const auto children = findChildren<FilterTableEntryAttribute *>();
|
||||
for (auto child : children)
|
||||
child->disconnect(this);
|
||||
}
|
||||
|
||||
void FilterTableEntry::updateData()
|
||||
{
|
||||
for (int i = 0; i < m_centerLayout->count(); i++)
|
||||
{
|
||||
FilterTableEntryAttribute *ftec = dynamic_cast<FilterTableEntryAttribute *>(m_centerLayout->itemAt(i)->widget()); // try to convert to fte
|
||||
|
||||
if (!ftec) // not an ftec
|
||||
{
|
||||
WARNING_LOG(m_logger) << "FilterTableEntry::filterText(): !ftec";
|
||||
continue;
|
||||
}
|
||||
|
||||
ftec->updateData(m_detailData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QComboBox *FilterTableEntry::getEventTypesComboBox()
|
||||
{
|
||||
QComboBox *cbEventTypes = new QComboBox();
|
||||
cbEventTypes->addItems(m_detailData->eventTypeLookup.getEventTexts());
|
||||
cbEventTypes->model()->sort(0);
|
||||
connect(cbEventTypes, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &FilterTableEntry::signalChanges);
|
||||
|
||||
return cbEventTypes;
|
||||
}
|
||||
|
||||
|
||||
const QJsonObject FilterTableEntry::filter(bool typeSafe) const
|
||||
{
|
||||
// get all attribute filters
|
||||
|
||||
if (m_eventType == -1/* || !m_filterActive*/)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "FilterTableEntry has no event type.";
|
||||
//warn("fte: fte has no event type (still in selection mode?)");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_centerLayout->count()) // if there are no children, do not worry, it should be possible to just filter by the event type
|
||||
{
|
||||
//info("fte: empty");
|
||||
}
|
||||
|
||||
|
||||
QJsonObject result;
|
||||
|
||||
QString eventTypeString;
|
||||
|
||||
if (typeSafe)
|
||||
eventTypeString = QString::number(m_eventType);
|
||||
else
|
||||
eventTypeString = m_detailData->eventTypeLookup.getEventText(m_eventType); // getEventTypeString(eventType);
|
||||
|
||||
if (!eventTypeString.length())
|
||||
return QJsonObject();
|
||||
|
||||
//info("fte: event type #" + QString::number(eventType) + " = " + eventTypeString);
|
||||
|
||||
|
||||
result[QStringLiteral("EventType")] = eventTypeString;
|
||||
|
||||
QJsonArray attributes;
|
||||
for (int i = 0; i < m_centerLayout->count(); i++)
|
||||
{
|
||||
FilterTableEntryAttribute *ftec = dynamic_cast<FilterTableEntryAttribute *>(m_centerLayout->itemAt(i)->widget()); // try to convert to fte
|
||||
|
||||
if (!ftec) // not an ftec
|
||||
{
|
||||
WARNING_LOG(m_logger) << "FilterTableEntry::filterText(): !ftec";
|
||||
continue;
|
||||
}
|
||||
|
||||
//info("fte: ftec found");
|
||||
|
||||
QJsonObject filterTile = ftec->filter(typeSafe); // the typeSafe parameter kills off the STR_COMPARE as we only safe ID's or ints, so do not implement it
|
||||
|
||||
if (filterTile.isEmpty()) // ftec has no result, continue!
|
||||
continue;
|
||||
|
||||
attributes.append(filterTile);
|
||||
}
|
||||
|
||||
result[QStringLiteral("Attributes")] = attributes;
|
||||
result[QStringLiteral("Active")] = m_pbFilterActive->isChecked();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void FilterTableEntry::slotSelectEventType() // end selection mode => start editing mode
|
||||
{
|
||||
delete m_lbSelectText; // delete help text (not needed anymore)
|
||||
|
||||
// end selection mode
|
||||
if (m_cbEventSelector) // if there are no attribute filters yet..
|
||||
{
|
||||
if (m_eventType == -1) // do not reload if already set (set by constructor when set-function is used)
|
||||
{
|
||||
m_eventType = m_detailData->eventTypeLookup.getEventType(m_cbEventSelector->currentText()); // DOES NOT WORK ANYMORE: m_cbEventSelector->currentIndex();
|
||||
}
|
||||
|
||||
m_lbEventName = new QLabel(QString(tr("Filter by event type: <b>%1</b>")).arg(m_detailData->eventTypeLookup.getEventText(m_eventType))); //m_cbEventSelector->currentText()); // get event name
|
||||
m_lbEventName->setMinimumWidth(m_cbEventSelector->width()); // gets the optics straight! FIXME: width was never set
|
||||
|
||||
delete m_cbEventSelector; // event type is now fixed, replace cb with lb
|
||||
m_cbEventSelector = nullptr; // don't forget to set to 0 or this if-clause can't see that cb is already deleted => crash
|
||||
|
||||
m_topLayout->insertWidget(0, m_lbEventName); // add where the cb was
|
||||
}
|
||||
|
||||
if (m_eventType == -1)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "slotSelectEventType: m_eventType == -1";
|
||||
return;
|
||||
}
|
||||
|
||||
delete m_pbOK; // delete ok button
|
||||
|
||||
|
||||
|
||||
|
||||
// start editing mode
|
||||
|
||||
// horizontal line under add button
|
||||
QWidget *horizontalLineWidget = new QWidget();
|
||||
horizontalLineWidget->setFixedHeight(2);
|
||||
horizontalLineWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
horizontalLineWidget->setStyleSheet(QStringLiteral("background-color: #c0c0c0;"));
|
||||
m_mainLayout->insertWidget(1, horizontalLineWidget, 0, Qt::AlignTop);
|
||||
|
||||
delete m_pbDelete; // must be recreated because of the stretch at the end whil in selection mode
|
||||
m_pbDelete = new QPushButton(QStringLiteral("-"));
|
||||
m_pbDelete->setToolTip(tr("Delete this filter and all its attributes"));
|
||||
m_pbDelete->setPalette(QPalette(QColor("red")));
|
||||
connect(m_pbDelete, &QPushButton::clicked, this, &FilterTableEntry::deleteLater);
|
||||
m_pbDelete->setMinimumWidth(30);
|
||||
m_pbDelete->setMaximumWidth(30);
|
||||
m_topLayout->addWidget(m_pbDelete, 0, Qt::AlignLeft);
|
||||
|
||||
m_topLayout->addWidget(m_pbFilterActive, 0, Qt::AlignLeft);
|
||||
connect(m_pbFilterActive, &QPushButton::clicked, this, &FilterTableEntry::slotFilterActiveClicked);
|
||||
|
||||
connect(m_pbFoundEvents, &QPushButton::clicked, this, &FilterTableEntry::slotShowEvents);
|
||||
m_pbFoundEvents->setToolTip(tr("Show all events that fit to this filter"));
|
||||
m_topLayout->addWidget(m_pbFoundEvents, 1, Qt::AlignLeft);
|
||||
|
||||
|
||||
|
||||
|
||||
// do not add attributes if there are none
|
||||
DetailData::AttributeEventLookup::AttributeList attributeList = m_detailData->attributeEventLookup.getEventsAttributeList(m_eventType);
|
||||
|
||||
|
||||
// remove unfilterables:
|
||||
QMutableListIterator<QString> it(attributeList);
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
const QString attributeType = it.next();
|
||||
|
||||
if (m_detailData->attributeInterpreterLookup.getInterpreterType(attributeType) == DetailData::INTERPRETER_TYPE_NONE)
|
||||
it.remove();
|
||||
}
|
||||
|
||||
if (attributeList.isEmpty())
|
||||
return;
|
||||
|
||||
|
||||
QPushButton *pbAddAttribute = new QPushButton(tr("Add Attribute"));
|
||||
pbAddAttribute->setPalette(QPalette(QColor("green")));
|
||||
connect(pbAddAttribute, &QPushButton::clicked, this, &FilterTableEntry::slotAddAttribute);
|
||||
//pbAddFilter->setMinimumWidth(30);
|
||||
//pbAddFilter->setMaximumWidth(30);
|
||||
m_mainLayout->insertWidget(2, pbAddAttribute, 0, Qt::AlignLeft);
|
||||
}
|
||||
|
||||
|
||||
void FilterTableEntry::slotShowEvents()
|
||||
{
|
||||
QJsonArray a;
|
||||
a.append(filter(true /* type safe! */));
|
||||
emit signalShowEvents(a);
|
||||
}
|
||||
|
||||
|
||||
void FilterTableEntry::slotFilterActiveClicked()
|
||||
{
|
||||
if (m_pbFilterActive->isChecked())
|
||||
{
|
||||
m_pbFilterActive->setPalette(QPalette(QColor("orange")));
|
||||
m_pbFilterActive->setToolTip(tr("Filter is active"));
|
||||
m_pbFoundEvents->setPalette(QPalette(QColor("orange")));
|
||||
m_pbFoundEvents->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pbFilterActive->setPalette(QPalette(QColor("grey")));
|
||||
m_pbFilterActive->setToolTip(tr("Filter is inactive"));
|
||||
m_pbFoundEvents->setPalette(QPalette(QColor("grey")));
|
||||
m_pbFoundEvents->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FilterTableEntry::slotAddAttribute()
|
||||
{
|
||||
addAttribute();
|
||||
}
|
||||
|
||||
|
||||
bool FilterTableEntry::hasAttributes() const
|
||||
{
|
||||
qWarning() << "hasAttributes? children: " << m_centerLayout->children().count();
|
||||
return !!m_centerLayout->children().count();
|
||||
}
|
||||
|
||||
|
||||
FilterTableEntryAttribute *FilterTableEntry::addAttribute(const QString &attributeType)
|
||||
{
|
||||
FilterTableEntryAttribute *ftec = new FilterTableEntryAttribute(m_detailData, m_eventType, attributeType, this);
|
||||
connect(ftec, &FilterTableEntryAttribute::signalChanges, this, &FilterTableEntry::signalChanges);
|
||||
connect(ftec, &FilterTableEntryAttribute::destroyed, this, &FilterTableEntry::signalChanges);
|
||||
m_centerLayout->insertWidget(0, ftec, 1, Qt::AlignLeft); // add all FTECs to the left
|
||||
|
||||
return ftec;
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* entry to manage a specific filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FilterTableEntryAttribute.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QComboBox>
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QList>
|
||||
#include <QGroupBox>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class FilterTableEntry : public QGroupBox //QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FilterTableEntry(DetailData *detailData, const int &eventType = -1, const bool &active = true, QWidget *parent = nullptr);
|
||||
~FilterTableEntry();
|
||||
const QJsonObject filter(bool typeSafe = false) const;
|
||||
/**
|
||||
* @brief addFilter adds a filter to the filter table layout and returns the new pointer (for set-functionality)
|
||||
* @return new created ftw pointer
|
||||
*/
|
||||
FilterTableEntryAttribute *addAttribute(const QString &attributeType = QString());
|
||||
bool hasAttributes() const;
|
||||
void updateData();
|
||||
|
||||
|
||||
private:
|
||||
NGL::INGLLogger &m_logger;
|
||||
QComboBox *getEventTypesComboBox();
|
||||
|
||||
int m_eventType;
|
||||
|
||||
// ui
|
||||
QVBoxLayout *m_mainLayout{nullptr}; // for topLayout,
|
||||
QHBoxLayout *m_topLayout{nullptr}; // for event, delete, show events
|
||||
QHBoxLayout *m_centerLayout{nullptr}; // for many filtering types
|
||||
QComboBox *m_cbEventSelector{nullptr};
|
||||
QLabel *m_lbEventName{nullptr};
|
||||
QPushButton *m_pbDelete{nullptr};
|
||||
QPushButton *m_pbFoundEvents{nullptr};
|
||||
QPushButton *m_pbFilterActive{nullptr};
|
||||
QPushButton *m_pbOK{nullptr};
|
||||
QLabel *m_lbSelectText{nullptr};
|
||||
DetailData *m_detailData{nullptr};
|
||||
|
||||
signals:
|
||||
void signalShowEvents(const QJsonArray &filter); // provided by filter text (use filter, get all fitting events by setting SHOW/HIDE to false and returning only the list of affected events)
|
||||
void signalChanges();
|
||||
|
||||
private slots:
|
||||
void slotAddAttribute();
|
||||
void slotFilterActiveClicked();
|
||||
void slotSelectEventType();
|
||||
void slotShowEvents();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief slotSetFoundEventsCount sets the variable for how much events could be found with this filter (called by parent, holding this fte)
|
||||
* @param foundEvents count of events found with this filter
|
||||
*/
|
||||
|
||||
//void slotSetFoundEventsCount(int foundEvents);
|
||||
};
|
||||
|
||||
}
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* attribute entry to manage a specific attribute
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "interpreter/FilterWorker.h"
|
||||
#include "FilterTableEntryAttribute.h"
|
||||
#include "widgets/AbstractAttributeWidget.h"
|
||||
#include "logger.h"
|
||||
#include "../detail_data.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
FilterTableEntryAttribute::FilterTableEntryAttribute(DetailData *detailData, int eventType, const QString &attributeType, QWidget *parent)
|
||||
: QGroupBox(parent)
|
||||
, m_eventType(eventType)
|
||||
, m_attributeType(attributeType) // CAN be invalid
|
||||
, m_selectionModeUI(nullptr)
|
||||
, m_editionModeUI(nullptr)
|
||||
, m_attributesLayout(new QVBoxLayout())
|
||||
, m_detailData(detailData)
|
||||
, m_logger(getLogger("EventFilter.FilterTableEntryAttribute"))
|
||||
{
|
||||
//this->setStyleSheet("background-color:#436C99;"); // layer 2
|
||||
this->setTitle(QString());
|
||||
|
||||
setLayout(m_attributesLayout);
|
||||
|
||||
|
||||
/* Selection Mode Explanation:
|
||||
*
|
||||
* 1. Mode: Empty Mode DEPRECATED & DELETED!
|
||||
*
|
||||
* > Empty Widget
|
||||
* > PushButton "+" to end Empty Mode and goto Selection Mode
|
||||
* > goes onto 2. Mode
|
||||
*
|
||||
*
|
||||
* 2. Mode: Selection Mode
|
||||
*
|
||||
* > ComboBox with Event-specific types: (Munition, Players, etc.)
|
||||
* > PushButton "+" to END Selection Mode (turns ComboBox to QLabel, so that Event-specific Type is FIXED)
|
||||
*
|
||||
*
|
||||
* 3. Mode: Editing Mode
|
||||
*
|
||||
* > Useable Widget
|
||||
* > Label with chosen Event-specific Type
|
||||
* > ComboBox with Type-specific attributes: (adding Munition-Types if the Event-specific type was Munition)
|
||||
* >> (has to load Type-specific attributes relating to the selected Event-specific type! Munition -> Munition types)
|
||||
* > PushButton "+" to add another Type-specific attribute:
|
||||
* >> adds another ComboBox and PushButton for further adding more attributes
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
//setStyleSheet("FilterTableEntryAttribute { border: 1px solid black }");
|
||||
|
||||
slotAddSelectionMode();
|
||||
|
||||
if (!attributeType.isEmpty())
|
||||
{
|
||||
m_selectionModeUI->cbAttributeType->setCurrentIndex(m_selectionModeUI->cbAttributeType->findData(QVariant::fromValue<QString>(attributeType))); // set initial value by id
|
||||
slotAddEditingMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
FilterTableEntryAttribute::~FilterTableEntryAttribute()
|
||||
{
|
||||
delete m_editionModeUI; // not a widget, not parented
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::updateData(DetailData *detailData)
|
||||
{
|
||||
if (!m_editionModeUI)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < m_editionModeUI->attributeValuesLayout->count(); i++) // now get values for attribute value(s) list (from attribute layout, only available in editing mode)
|
||||
{
|
||||
AbstractAttributeWidget *aaw = /*qobject_cast*/dynamic_cast<AbstractAttributeWidget *>(m_editionModeUI->attributeValuesLayout->itemAt(i)->widget());
|
||||
|
||||
if (!aaw) // not a aaw derived class
|
||||
continue;
|
||||
|
||||
aaw->updateData(detailData);
|
||||
connect(aaw, &AbstractAttributeWidget::deleteClicked, this, [this]()
|
||||
{
|
||||
emit attributeChanged(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const QJsonObject FilterTableEntryAttribute::filter(bool typeSafe) const // ftea alias "ftec"
|
||||
{
|
||||
if (m_attributeType.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "filterText: m_attributeType == -1";
|
||||
//warn("ftec: missing attribute type while getting filter text from attribute (still in selection mode?)");
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
|
||||
QString attributeTypeName;
|
||||
|
||||
if (typeSafe)
|
||||
attributeTypeName = m_attributeType;
|
||||
else
|
||||
{
|
||||
attributeTypeName = m_detailData->attributeTypeLookup.getAttributeText(m_attributeType); //getAttributeTypeString(m_attributeType);
|
||||
}
|
||||
|
||||
if (attributeTypeName.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "filterText: !attributeTypeName.length()";
|
||||
//warn("ftec: missing attribute text while getting filter text from attribute");
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
|
||||
QJsonObject result;
|
||||
result[QStringLiteral("AttributeType")] = attributeTypeName;
|
||||
|
||||
// translate all attributes + their value(s)
|
||||
// must be: * Attributes : [Attr Type]{[Attr Value],[Attr Value], ...}
|
||||
|
||||
|
||||
QJsonArray values;
|
||||
|
||||
if (m_editionModeUI)
|
||||
{
|
||||
for (int i = 0; i < m_editionModeUI->attributeValuesLayout->count(); i++) // now get values for attribute value(s) list (from attribute layout, only available in editing mode)
|
||||
{
|
||||
AbstractAttributeWidget *aaw = /*qobject_cast*/dynamic_cast<AbstractAttributeWidget *>(m_editionModeUI->attributeValuesLayout->itemAt(i)->widget());
|
||||
|
||||
if (!aaw) // not a aaw derived class
|
||||
continue;
|
||||
|
||||
//info("ftec: aaw derived class found");
|
||||
|
||||
QString value = aaw->filterText(typeSafe); // ishygddt without a derived class
|
||||
|
||||
if (value.isEmpty())
|
||||
continue;
|
||||
|
||||
values.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result[QStringLiteral("AttributeValues")] = values;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::slotAddSelectionMode()
|
||||
{
|
||||
// end Empty Mode
|
||||
/*if (!m_emptyModeUI)
|
||||
return;
|
||||
|
||||
delete m_emptyModeUI;
|
||||
m_emptyModeUI = 0;*/
|
||||
|
||||
// 2. Mode: Selection Mode
|
||||
m_selectionModeUI = new SelectionModeUI(m_detailData, m_eventType);
|
||||
|
||||
connect(m_selectionModeUI->pbAddEditingMode, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotAddEditingMode);
|
||||
connect(m_selectionModeUI->pbDeleteFilter, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotDeleteAttributeContainer);
|
||||
|
||||
m_attributesLayout->addWidget(m_selectionModeUI->selectionModeWidget, 0, Qt::AlignTop);
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::slotAddEditingMode(bool createBlankContainer)
|
||||
{
|
||||
// end selection mode
|
||||
if (!m_selectionModeUI)
|
||||
return;
|
||||
|
||||
// 3. Mode: Editing Mode
|
||||
QString attributeTypeString;
|
||||
|
||||
if (m_attributeType.isEmpty()) // get text from combobox, when attribute type not given
|
||||
{
|
||||
attributeTypeString = m_selectionModeUI->cbAttributeType->currentText();
|
||||
m_attributeType = m_detailData->attributeTypeLookup.getAttributeType(attributeTypeString);
|
||||
}
|
||||
else // get text from filter data, when attribute type given by set-function
|
||||
{
|
||||
attributeTypeString = m_detailData->attributeTypeLookup.getAttributeText(m_attributeType);
|
||||
// do not set attribute type when it is already given!
|
||||
}
|
||||
|
||||
delete m_selectionModeUI;
|
||||
m_selectionModeUI = nullptr;
|
||||
|
||||
if (m_attributeType.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "slotAddEditingMode: invalid attribute type string!";
|
||||
return;
|
||||
}
|
||||
|
||||
m_editionModeUI = new EditingModeUI(m_detailData, m_attributeType, nullptr); // munition
|
||||
|
||||
connect(m_editionModeUI, &EditingModeUI::signalChanges, this, &FilterTableEntryAttribute::signalChanges);
|
||||
connect(m_editionModeUI, &EditingModeUI::destroyed, this, &FilterTableEntryAttribute::signalChanges);
|
||||
|
||||
connect(m_editionModeUI->pbAddAttributeContainer, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotAddAttributeContainer);
|
||||
connect(m_editionModeUI->pbDelete, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotDeleteAttributeContainer);
|
||||
m_editionModeUI->lbFilterText->setText(tr("Filter by attribute type: <b>%1</b>").arg(attributeTypeString));
|
||||
|
||||
m_attributesLayout->addWidget(m_editionModeUI, 0, Qt::AlignTop);
|
||||
|
||||
// add first attribute container to events layout
|
||||
if (createBlankContainer)
|
||||
slotAddAttributeContainer();
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::slotDeleteAttributeContainer() // delete attribute (munition, player, etc.)
|
||||
{
|
||||
emit attributeChanged(false);
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::slotAddAttributeContainer()
|
||||
{
|
||||
emit signalChanges();
|
||||
emit attributeChanged(true);
|
||||
if (m_editionModeUI != nullptr)
|
||||
m_editionModeUI->addAttributeContainer(m_eventType);
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* attribute entry to manage a specific attribute
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AttributeEditingModeUI.h"
|
||||
#include "AttributeSelectionModeUI.h"
|
||||
#include <QGroupBox>
|
||||
|
||||
class QLabel;
|
||||
class QVBoxLayout;
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class FilterTableEntryAttribute : public QGroupBox //QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FilterTableEntryAttribute(DetailData *detailData, int eventType, const QString &attributeType, QWidget *parent = nullptr);
|
||||
~FilterTableEntryAttribute();
|
||||
const QJsonObject filter(bool typeSafe = false) const;
|
||||
void updateData(DetailData *detailData);
|
||||
|
||||
int m_eventType;
|
||||
QString m_attributeType;
|
||||
|
||||
// ui
|
||||
//EmptyModeUI* m_emptyModeUI;
|
||||
SelectionModeUI *m_selectionModeUI;
|
||||
EditingModeUI *m_editionModeUI;
|
||||
|
||||
QVBoxLayout *m_attributesLayout;
|
||||
QLabel *m_lbSelectText;
|
||||
DetailData *m_detailData;
|
||||
|
||||
signals:
|
||||
void signalChanges();
|
||||
void attributeChanged(const bool &hasAttribute);
|
||||
|
||||
private:
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
private slots:
|
||||
void slotAddAttributeContainer();
|
||||
void slotDeleteAttributeContainer(); // delete attribute (munition, player, etc.)
|
||||
void slotAddSelectionMode(); // to end Empty Mode
|
||||
void slotAddEditingMode(bool createBlankContainer = true); // to end Selection Mode
|
||||
};
|
||||
|
||||
}
|
||||
+326
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* table widget to manage filters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "FilterWindow.h"
|
||||
#include "ui_FilterWindowUi.h"
|
||||
#include "FilterTableEntry.h"
|
||||
#include "interpreter/FilterWorker.h"
|
||||
#include "../detail_data.h"
|
||||
#include "logger.h"
|
||||
#include <FileManagement/flm_translation.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
|
||||
#include <QScopeGuard>
|
||||
#endif
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
FilterWindow::FilterWindow(DetailData *detailData,
|
||||
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
|
||||
LtsSession::LtsSession *session,
|
||||
QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
, m_flmIfc(flmIfc)
|
||||
, m_ui(new Ui::FilterWindow)
|
||||
, updateTimer(new QTimer(this))
|
||||
, m_detailData(detailData)
|
||||
//, m_filterWorker(new FilterWorker(detailData))
|
||||
, m_logger(getLogger("EventFilter.FilterWindow"))
|
||||
, m_session(session)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setMinimumSize(1500, 800);
|
||||
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add,
|
||||
this, &FilterWindow::slotAddNewFilter);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Show,
|
||||
this, &FilterWindow::slotShowEvents);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Save,
|
||||
this, &FilterWindow::slotSave);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load,
|
||||
this, &FilterWindow::slotLoad);
|
||||
|
||||
// m_buttonBox->connectButton(LtsWidgets::DialogButton::Hide,
|
||||
// this, &FilterWindow::slotHide);
|
||||
|
||||
|
||||
// UPDATER
|
||||
connect(updateTimer, &QTimer::timeout, this, &FilterWindow::slotUpdate);
|
||||
updateTimer->setInterval(5000);
|
||||
updateTimer->start();
|
||||
|
||||
// // HACK: but works good for FAT
|
||||
// QTimer *hack = new QTimer(this);
|
||||
// hack->setInterval(750);
|
||||
// // NOTE: super difficult to track changes, so make apply always available
|
||||
// connect(hack, &QTimer::timeout, this, &FilterWindow::slotChangesMade);
|
||||
// hack->start();
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Timeline-Filter_Functions"));
|
||||
}
|
||||
|
||||
|
||||
FilterWindow::~FilterWindow()
|
||||
{
|
||||
const QList<FilterTableEntry*> lst = findChildren<FilterTableEntry*>();
|
||||
for (FilterTableEntry *fte : lst)
|
||||
fte->disconnect(this);
|
||||
updateTimer->stop();
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Filters"));
|
||||
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setText(tr("Add Filter"));
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Show)->setText(tr("Show Events"));
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::slotSave()
|
||||
{
|
||||
int fileId = m_flmIfc->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(),
|
||||
filterToDoc(exportFilter()));
|
||||
if (fileId > 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
|
||||
__unchange__();
|
||||
}
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Could not save file in library ";
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::slotUpdate()
|
||||
{
|
||||
for (int i = 0; i < m_ui->filterContainer->count(); i++)
|
||||
{
|
||||
FilterTableEntry *fte = qobject_cast<FilterTableEntry *>(m_ui->filterContainer->itemAt(i)->widget()); // try to convert to fte
|
||||
|
||||
if (!fte) // not an fte (e.g. ignore add button)
|
||||
continue;
|
||||
|
||||
fte->updateData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FilterTableEntry *FilterWindow::addNewFilter(const int eventType, bool active)
|
||||
{
|
||||
FilterTableEntry *fte = new FilterTableEntry(m_detailData, eventType, active, this);
|
||||
|
||||
connect(fte, &FilterTableEntry::signalChanges, this, &FilterWindow::slotChangesMade);
|
||||
connect(fte, &FilterTableEntry::destroyed, this, &FilterWindow::slotChangesMade);
|
||||
connect(fte, &FilterTableEntry::signalShowEvents, this, &FilterWindow::signalShowEvents);
|
||||
//m_ui->filterContainer->insertWidget(1, fte); // after the ADD button !
|
||||
m_ui->filterContainer->addWidget(fte);
|
||||
|
||||
slotChangesMade();
|
||||
|
||||
return fte;
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::slotAddNewFilter()
|
||||
{
|
||||
addNewFilter();
|
||||
}
|
||||
|
||||
|
||||
const QJsonArray FilterWindow::exportFilter() const
|
||||
{
|
||||
if (!m_ui->filterContainer->count())
|
||||
return QJsonArray();
|
||||
|
||||
QJsonArray result;
|
||||
|
||||
for (int i = 0; i < m_ui->filterContainer->count(); i++)
|
||||
{
|
||||
FilterTableEntry *fte = qobject_cast<FilterTableEntry *>(m_ui->filterContainer->itemAt(i)->widget()); // try to convert to fte
|
||||
|
||||
if (!fte) // not an fte (e.g. ignore add button)
|
||||
continue;
|
||||
|
||||
const QJsonObject filterTile = fte->filter(true /* type safe !! */);
|
||||
if (filterTile.isEmpty()) // fte has no result, continue!
|
||||
continue;
|
||||
|
||||
result.append(filterTile);
|
||||
}
|
||||
|
||||
//filterTextEdit->setText(filterText);
|
||||
qWarning() << "filter text:" << result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const QByteArray FilterWindow::filterToDoc(const QJsonArray &flt)
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::TLNTimelineFilter);
|
||||
obj[QStringLiteral("Filter")] = flt;
|
||||
|
||||
QJsonDocument doc(obj);
|
||||
return doc.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
bool FilterWindow::apply()
|
||||
{
|
||||
slotApplyFilter();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::aboutToClose()
|
||||
{
|
||||
//emit signalApplyFilter(QString());
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::slotApplyFilter()
|
||||
{
|
||||
emit signalApplyFilter(exportFilter());
|
||||
//emit signalChangesMade(); // => slotChangesMade(); // NOTE: super difficult to track changes, so make apply always available
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::slotShowEvents()
|
||||
{
|
||||
emit signalShowEvents(exportFilter());
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::slotLoad()
|
||||
{
|
||||
QByteArray content;
|
||||
int fileId = m_flmIfc->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::TLNTimelineFilter));
|
||||
if (fileId > 0)
|
||||
{
|
||||
// first ask if filters can be replaced by loaded ones
|
||||
int msgResult = QMessageBox::question(this,
|
||||
tr("Load filter set"),
|
||||
tr("Do you really want to discard current filter set to load the requested filter set?\n"
|
||||
"\n"
|
||||
"Yes, discard current filter set and load a filter set.\n"
|
||||
"No, do not make any changes."),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No);
|
||||
|
||||
if (msgResult != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
if (!m_flmIfc->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TLNTimelineFilter)))
|
||||
{
|
||||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this,
|
||||
tr("Invalid xml file content"),
|
||||
windowTitle(),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes,
|
||||
texts);
|
||||
}
|
||||
else
|
||||
{
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(content));
|
||||
const QJsonObject obj(doc.object());
|
||||
const QJsonArray tlnFilter(obj.value(QStringLiteral("Filter")).toArray());
|
||||
|
||||
loadFilters(tlnFilter);
|
||||
slotChangesMade();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FilterWindow::loadFilters(const QJsonArray &filter)
|
||||
{
|
||||
setUnchangeable();
|
||||
|
||||
// call setUnchangeable(false) before the scope (whenever) of this fn endsq
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
|
||||
auto unchangableReset = qScopeGuard([this] { setUnchangeable(false); });
|
||||
#else
|
||||
std::shared_ptr<int> unchangeableReset(nullptr, [this](int *) { setUnchangeable(false); });
|
||||
#endif
|
||||
|
||||
|
||||
// get model filter lsit by filter text
|
||||
FilterWorker::GetModelFilterListResult result = FilterWorker::getModelFilterList(m_detailData, filter, true);
|
||||
if (!FilterWorker::getInstance()->handleResultValues(result.resultValueList, this, true))
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("The selected filter set is invalid and cannot be loaded."), tr("Cannot load filter"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// now, after we know that the filter set is valid: first remove all old filters from Filter Set
|
||||
while (m_ui->filterContainer->count())
|
||||
{
|
||||
delete m_ui->filterContainer->itemAt(0)->widget(); // delete (removes them from the layout automatically)
|
||||
}
|
||||
|
||||
|
||||
const ModelFilterList &modelFilterList = result.result;
|
||||
|
||||
// now create all new filters and add to laoyut
|
||||
int lastEventType = -1;
|
||||
FilterTableEntry *lastFTW = nullptr;
|
||||
|
||||
QString lastAttributeType; // empty = events only
|
||||
FilterTableEntryAttribute *lastFTEA = nullptr;
|
||||
|
||||
for (const FilterWorker::ModelFilter &mf : modelFilterList)
|
||||
{
|
||||
if (lastEventType != mf.eventType || lastEventType == -1 || !lastFTW) // create a new FTE when we are not the same event type anymore (or there never was a fte)
|
||||
{
|
||||
lastEventType = mf.eventType;
|
||||
lastFTW = addNewFilter(mf.eventType, mf.active); // create a new event filter
|
||||
}
|
||||
|
||||
if (mf.attributeType == QString()) // attribute type 0 = EVENT_ONLY (create event, but do not add attribute entry !
|
||||
continue;
|
||||
|
||||
if (lastAttributeType != mf.attributeType || lastAttributeType.isEmpty() || !lastFTEA)
|
||||
{
|
||||
lastAttributeType = mf.attributeType;
|
||||
lastFTEA = lastFTW->addAttribute(mf.attributeType); // create a new attribute filter
|
||||
}
|
||||
|
||||
EditingModeUI *emui = lastFTEA->m_editionModeUI;
|
||||
|
||||
if (!emui)
|
||||
continue;
|
||||
|
||||
emui->addAttributeContainer(mf.eventType, mf.attributeValue); // create a new attribute container witht he given value
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* table widget to manage filters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QJsonArray>
|
||||
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class FilterWindow;
|
||||
}
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
class FilterTableEntry;
|
||||
class FilterWorker;
|
||||
|
||||
class FilterWindow : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FilterWindow(DetailData *detailData,
|
||||
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
|
||||
LtsSession::LtsSession *session,
|
||||
QWidget *parent = nullptr);
|
||||
~FilterWindow();
|
||||
FilterTableEntry *addNewFilter(const int eventType = -1, bool active = true); // invalid
|
||||
|
||||
//void addFilterToTable(const NGLDAO::EventFilter &eventFilter);
|
||||
void clearSavedFiltersList();
|
||||
void updateData();
|
||||
const QJsonArray exportFilter() const;
|
||||
const QByteArray filterToDoc(const QJsonArray &flt);
|
||||
bool loadFilters(const QJsonArray &filter);
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
bool apply() override;
|
||||
void aboutToClose() override;
|
||||
|
||||
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmIfc;
|
||||
Ui::FilterWindow *m_ui;
|
||||
QTimer *updateTimer;
|
||||
DetailData *m_detailData;
|
||||
//FilterWorker *m_filterWorker;
|
||||
NGL::INGLLogger &m_logger;
|
||||
LtsSession::LtsSession *m_session;
|
||||
|
||||
signals:
|
||||
void signalConvertFilterText(const QString &);
|
||||
void signalShowEvents(const QJsonArray &events);
|
||||
void signalApplyFilter(const QJsonArray &filter);
|
||||
void signalReloadSavedFiltersList();
|
||||
void signalDeleteFilter(int);
|
||||
void signalReplaceFilter(int);
|
||||
void signalReplaceFilterNow(int, const QString &);
|
||||
//void signalFilterInTableChanged(const NGLDAO::EventFilter &); // redirection
|
||||
//void signalNewFilter(const NGLDAO::EventFilter &); // redirection
|
||||
|
||||
public slots:
|
||||
void slotLoad();
|
||||
void slotSave();
|
||||
void slotUpdate();
|
||||
void slotAddNewFilter();
|
||||
|
||||
private slots:
|
||||
void slotApplyFilter();
|
||||
void slotShowEvents();
|
||||
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
+309
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* equations methods for filter/interpreter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "logger.h"
|
||||
#include "FilterEquationFunctions.h"
|
||||
#include "FilterValueInterpreter.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QRect>
|
||||
#include <QVariant>
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
static bool inTime(DetailData *detailData, const QVariant &value, const QString &interpreterText)
|
||||
{
|
||||
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
|
||||
bool ok = false;
|
||||
|
||||
unsigned int time = value.toUInt(&ok);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
WARNING_LOG(logger) << "inTime: value error!" << value.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
InterpreterResult ir = interpretValue(detailData, DetailData::INTERPRETER_TYPE_RANGE, interpreterText);
|
||||
|
||||
if (ir.resultType == InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS && ir.resultList.count() == 2)
|
||||
{
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
|
||||
unsigned int t1 = ir.resultList.at(0).toUInt(&ok1);
|
||||
unsigned int t2 = ir.resultList.at(1).toUInt(&ok2);
|
||||
|
||||
if (ok1 && ok2 && t1 <= time && t2 >= time)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Detail Data Filter Text
|
||||
static bool inArea(DetailData *detailData, const QVariant &value, const QString &interpreterText)
|
||||
{
|
||||
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
|
||||
(void)detailData;
|
||||
|
||||
QStringList areaValuesList = value.toString().split(QLatin1Char('x'));
|
||||
|
||||
if (areaValuesList.count() != 2)
|
||||
{
|
||||
WARNING_LOG(logger) << "inArea: areaValuesList.count() != 2 (" << areaValuesList.count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList interpreterValuesList = interpreterText.split(QLatin1Char('x'));
|
||||
|
||||
if (interpreterValuesList.count() != 4)
|
||||
{
|
||||
WARNING_LOG(logger) << "inArea: interpreterValuesList.count() != 4 (" << interpreterValuesList.count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nb = false;
|
||||
int n = areaValuesList.at(0).toInt(&nb);
|
||||
|
||||
bool ob = false;
|
||||
int o = areaValuesList.at(1).toInt(&ob);
|
||||
|
||||
|
||||
bool n1b = false;
|
||||
int n1 = interpreterValuesList.at(0).toInt(&n1b);
|
||||
|
||||
bool n2b = false;
|
||||
int n2 = interpreterValuesList.at(1).toInt(&n2b);
|
||||
|
||||
bool o1b = false;
|
||||
int o1 = interpreterValuesList.at(2).toInt(&o1b);
|
||||
|
||||
bool o2b = false;
|
||||
int o2 = interpreterValuesList.at(3).toInt(&o2b);
|
||||
|
||||
|
||||
|
||||
/*/ Y
|
||||
* | N1
|
||||
* O1 |
|
||||
* ----------- X
|
||||
* | O2
|
||||
* N2 |
|
||||
/*/
|
||||
|
||||
|
||||
|
||||
if (!nb || !ob || !n1b || !n2b || !o1b || !o2b)
|
||||
{
|
||||
WARNING_LOG(logger) << "inArea: !nb || !ob || !n1b || !n2b || !o1b || !o2b";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QRect range;
|
||||
range.adjust(o1, n1, o2, n2);
|
||||
|
||||
if (range.contains(o, n))
|
||||
{
|
||||
WARNING_LOG(logger) << "inArea: in area!";
|
||||
return true;
|
||||
}
|
||||
|
||||
WARNING_LOG(logger) << "inArea: not in area";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool inRad(DetailData *detailData, const QVariant &value, const QString &interpreterText)
|
||||
{
|
||||
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
|
||||
(void)detailData;
|
||||
|
||||
QStringList radValuesList = value.toString().split(QLatin1Char('x'));
|
||||
|
||||
if (radValuesList.count() != 2)
|
||||
{
|
||||
WARNING_LOG(logger) << "inRad: radValuesList.count() != 2 (" << radValuesList.count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList interpreterValuesList = interpreterText.split(QLatin1Char('x'));
|
||||
|
||||
if (interpreterValuesList.count() != 3)
|
||||
{
|
||||
WARNING_LOG(logger) << "inArea: interpreterValuesList.count() != 3 (" << interpreterValuesList.count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nb = false;
|
||||
int n = radValuesList.at(0).toInt(&nb);
|
||||
|
||||
bool ob = false;
|
||||
int o = radValuesList.at(1).toInt(&ob);
|
||||
|
||||
|
||||
bool n1b = false;
|
||||
int n1 = interpreterValuesList.at(0).toInt(&n1b);
|
||||
|
||||
bool o1b = false;
|
||||
int o1 = interpreterValuesList.at(1).toInt(&o1b);
|
||||
|
||||
bool r1b = false;
|
||||
int r1 = interpreterValuesList.at(2).toInt(&r1b);
|
||||
|
||||
|
||||
|
||||
/*/ Y
|
||||
* | 'C' = center
|
||||
* = '=' = radius
|
||||
* ---==C==--- X
|
||||
* =
|
||||
* |
|
||||
/*/
|
||||
|
||||
|
||||
|
||||
if (!nb || !ob || !n1b || !o1b || !r1b)
|
||||
{
|
||||
WARNING_LOG(logger) << "inRad: !nb || !ob || !n1b || !o1b || !r1b";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QRect range;
|
||||
range.adjust(o1 - r1, n1 - r1, o1 + r1, n1 + r1);
|
||||
|
||||
if (range.contains(o, n))
|
||||
{
|
||||
WARNING_LOG(logger) << "inRad: in radius!";
|
||||
return true;
|
||||
}
|
||||
|
||||
WARNING_LOG(logger) << "inRad: not in radius";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool isIntEqual(DetailData *detailData, const QVariant &value, const QString &interpreterText) // filter for 0 ?
|
||||
{
|
||||
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
|
||||
(void)detailData;
|
||||
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
|
||||
//qWarning() << "isIntEqual: val1 =" << value << " val2 =" << interpreterText;
|
||||
|
||||
int i1 = value.toInt(&ok1);
|
||||
int i2 = interpreterText.toInt(&ok2);
|
||||
|
||||
if (!ok1 || !ok2)
|
||||
{
|
||||
WARNING_LOG(logger) << "isIntEqual: STR to INT conversion error! ok1 (" << ok1 << ") ok2 (" << ok2 << ") value (" << value.toString() << ") intTxt (" << interpreterText << ")";
|
||||
}
|
||||
|
||||
if (ok1 && ok2 && i1 == i2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool checkValue(DetailData *detailData, int attributeInterpreterType, const QVariant &value, const QString &interpreterText)
|
||||
{
|
||||
switch(attributeInterpreterType)
|
||||
{
|
||||
case DetailData::INTERPRETER_TYPE_TIME:
|
||||
{
|
||||
return inTime(detailData, value, interpreterText); // inTime is a range checker
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_AREA:
|
||||
{
|
||||
return inArea(detailData, value, interpreterText);
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_RAD: // TODO: test !!
|
||||
{
|
||||
return inRad(detailData, value, interpreterText);
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_STR_COMPARE: // TODO: rm - unused
|
||||
{
|
||||
//WARNING_LOG(logger) << "INTERPRETER_TYPE_STR_COMPARE value " << value.toString() << " text " << interpreterText;
|
||||
|
||||
if (value.toString() == interpreterText) // ez
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_ID_COMPARE:
|
||||
{
|
||||
bool tryIt = isIntEqual(detailData, value, interpreterText);
|
||||
|
||||
// NOTE: everything typesafe, ids only
|
||||
// if (!tryIt) // means: cannot convert text OR is not equal; reason: is text OR is not equal; solution: probably value string - getIDKeyFromValue!!
|
||||
// {
|
||||
// int newTry = detailData->attributeValueLookup.getValueIDKeyFromValueString(attributeType, interpreterText);
|
||||
|
||||
// if (newTry == -1) // not even a value string (solution does not work)
|
||||
// {
|
||||
// DEBUG_LOG(logger) << "checkValue: no key found";
|
||||
// tryIt = false;
|
||||
// }
|
||||
// else // okay, seems to be a value string
|
||||
// {
|
||||
// tryIt = isIntEqual(detailData, value, QString::number(newTry));
|
||||
// }
|
||||
// }
|
||||
|
||||
return tryIt;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* attribute types with ui type for combobox can redirect unproblematically
|
||||
* => attribute types with special ui type(s) should not be redirected
|
||||
* so if the attempt to lookup a attribute interpreter type fails, try another lookup with redirection
|
||||
* side effects can only happen if new attribute types are not completly integrated */
|
||||
|
||||
// TODO: endless loops possible in some way?
|
||||
|
||||
|
||||
// QString newAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
|
||||
|
||||
// //qWarning() << "checkValue: newAttributeType" << newAttributeType << " attributeType" << attributeType;
|
||||
|
||||
// if (newAttributeType != attributeType) // not equal = redirection
|
||||
// {
|
||||
// return checkValue(detailData, newAttributeType, value, interpreterText); // try again with redirected attribute type
|
||||
// }
|
||||
|
||||
//qWarning() << "checkValue: attribute type"<<attributeType<<"not handled";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FilterEquationFunctions::checkValue(DetailData *detailData, const QString &attributeType, const QVariant &value, const QString &interpreterText)
|
||||
{
|
||||
int attributeInterpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType); // get interpretertype (e.g. for area_pos for pos)
|
||||
return checkValue(detailData, attributeInterpreterType, value, interpreterText);
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* equations methods for filter/interpreter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class QVariant;
|
||||
class QString;
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
namespace FilterEquationFunctions
|
||||
{
|
||||
bool checkValue(DetailData *detailData, const QString &attributeType, const QVariant &value, const QString &interpreterText);
|
||||
}
|
||||
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter for filter in excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "FilterValueInterpreter.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QRect>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
static InterpreterResult interpretAreaText(const QString &areaText)
|
||||
{
|
||||
QStringList areaList = areaText.split(QLatin1Char('x'));
|
||||
|
||||
if (areaList.count() != 4) // must be 4 values (N1, N2, O1, O2)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_COUNT_NOT_FOUR);
|
||||
}
|
||||
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
bool ok3 = false;
|
||||
bool ok4 = false;
|
||||
|
||||
int n1 = areaList.at(0).toInt(&ok1);
|
||||
int n2 = areaList.at(1).toInt(&ok2);
|
||||
int o1 = areaList.at(2).toInt(&ok3);
|
||||
int o2 = areaList.at(3).toInt(&ok4);
|
||||
|
||||
/*/ Y
|
||||
* | N1
|
||||
* O1 |
|
||||
* ----------- X
|
||||
* | O2
|
||||
* N2 |
|
||||
/*/
|
||||
|
||||
if (!ok1) // do not set coord if some value could nbot be converted
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_N1);
|
||||
}
|
||||
|
||||
if (!ok2)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_N2);
|
||||
}
|
||||
|
||||
if (!ok3)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_O1);
|
||||
}
|
||||
|
||||
if (!ok4)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_O2);
|
||||
}
|
||||
|
||||
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
|
||||
ir.resultList.append(QRect(o1, n1, o2, n2));
|
||||
return ir;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static InterpreterResult interpretToInt(const QString &text)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
int result = text.toInt(&ok); // add more informations like: INFO_INT_IS_NEGATIVE [if (result < 0)] if needed
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_TOINT_CANNOT_INTERPRET_VALUE);
|
||||
}
|
||||
|
||||
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
|
||||
ir.resultList.append(result);
|
||||
return ir;
|
||||
}
|
||||
|
||||
static InterpreterResult interpretRangeText(const QString &rangeText)
|
||||
{
|
||||
QStringList rangeList = rangeText.split(QLatin1Char('-')); // 123456789-123456900 (why does ('-') not work ???)
|
||||
|
||||
if (rangeList.count() != 2)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_COUNT_NOT_TWO);
|
||||
}
|
||||
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
|
||||
unsigned int t1 = rangeList.at(0).toUInt(&ok1);
|
||||
unsigned int t2 = rangeList.at(1).toUInt(&ok2);
|
||||
|
||||
if (!ok1)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_CANNOT_INTERPRET_T1);
|
||||
}
|
||||
|
||||
if (!ok2)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_CANNOT_INTERPRET_T2);
|
||||
}
|
||||
|
||||
if (t1 > t2)
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_BEGIN_GREATER_THAN_END);
|
||||
}
|
||||
|
||||
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
|
||||
ir.resultList.append(t1);
|
||||
ir.resultList.append(t2);
|
||||
|
||||
return ir;
|
||||
}
|
||||
|
||||
|
||||
InterpreterResult interpretValue(DetailData *detailData, int attributeInterpreterType, const QString &value)
|
||||
{
|
||||
(void)detailData;
|
||||
|
||||
switch (attributeInterpreterType)
|
||||
{
|
||||
case DetailData::INTERPRETER_TYPE_ID_COMPARE:
|
||||
{
|
||||
return interpretToInt(value);
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_RANGE:
|
||||
{
|
||||
return interpretRangeText(value);
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_AREA:
|
||||
{
|
||||
return interpretAreaText(value);
|
||||
}
|
||||
|
||||
// TODO: radius
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_STR_COMPARE: // TODO: rm - unused
|
||||
{
|
||||
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
|
||||
ir.resultList.append(value);
|
||||
return ir;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_ATTRIBUTE_HAS_NO_INTERPRETER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
InterpreterResult interpretValue(DetailData *detailData, const QString &attributeType, const QString &value)
|
||||
{
|
||||
int interpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType); // -1 = invalid
|
||||
return interpretValue(detailData, interpreterType, value);
|
||||
}
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter for filter in excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class InterpreterResult
|
||||
{
|
||||
public:
|
||||
enum class InterpreterResultTypes
|
||||
{
|
||||
RESULT_UNKNOWN,
|
||||
RESULT_SUCCESS,
|
||||
//RESULT_UNKNOWN_INTERPRETER_TYPE,
|
||||
RESULT_ATTRIBUTE_HAS_NO_INTERPRETER,
|
||||
|
||||
RESULT_RANGETEXT_COUNT_NOT_TWO,
|
||||
RESULT_RANGETEXT_BEGIN_GREATER_THAN_END,
|
||||
RESULT_RANGETEXT_CANNOT_INTERPRET_T1,
|
||||
RESULT_RANGETEXT_CANNOT_INTERPRET_T2,
|
||||
|
||||
RESULT_AREATEXT_COUNT_NOT_FOUR,
|
||||
RESULT_AREATEXT_CANNOT_INTERPRET_N1,
|
||||
RESULT_AREATEXT_CANNOT_INTERPRET_N2,
|
||||
RESULT_AREATEXT_CANNOT_INTERPRET_O1,
|
||||
RESULT_AREATEXT_CANNOT_INTERPRET_O2,
|
||||
|
||||
RESULT_TOINT_CANNOT_INTERPRET_VALUE
|
||||
};
|
||||
|
||||
explicit InterpreterResult(const InterpreterResult::InterpreterResultTypes &res)
|
||||
: resultType(res)
|
||||
{
|
||||
}
|
||||
|
||||
InterpreterResult()
|
||||
: resultType(InterpreterResultTypes::RESULT_UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
InterpreterResultTypes resultType;
|
||||
QList<QVariant> additionalInformation;
|
||||
|
||||
QList<QVariant> resultList;
|
||||
};
|
||||
|
||||
InterpreterResult interpretValue(DetailData *detailData, int attributeInterpreterType, const QString &value);
|
||||
InterpreterResult interpretValue(DetailData *detailData, const QString &attributeType, const QString &value);
|
||||
|
||||
}
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter to convert text-filter to model filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "FilterWorker.h"
|
||||
#include "InfoWindow.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QApplication>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
FilterWorker* FilterWorker::s_instance = nullptr;
|
||||
FilterWorker* FilterWorker::getInstance()
|
||||
{
|
||||
if (!s_instance)
|
||||
{
|
||||
s_instance = new FilterWorker();
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
|
||||
FilterWorker::~FilterWorker()
|
||||
{
|
||||
//qWarning() << "~FilterWorker";
|
||||
}
|
||||
|
||||
|
||||
void FilterWorker::deleteInstance()
|
||||
{
|
||||
// TODO: rm
|
||||
// if (s_instance)
|
||||
// {
|
||||
// delete s_instance;
|
||||
// s_instance = 0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //qWarning() << "~FilterWorker [no instance to delete!]";
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
FilterWorker::FilterWorker()
|
||||
{
|
||||
#define addErrorHandler(x,y) { FilterWorker::ErrorHandler eh; eh.errorText = y; eh.errorParamCount = eh.errorText.split(QLatin1Char('%'), QString::SkipEmptyParts).count(); m_errorHandlerLookupMap.insert(x, eh); }(void)this
|
||||
|
||||
|
||||
// WARNING: addErrorHandler auto discover paramCOunt: .find("%").count ! also, do not use single %'s more than once
|
||||
addErrorHandler(GetModelFilterListResult::ERR_ATTRIBUTE_BLOCK_NOT_CLOSED, tr("Attribute block not closed: \n\'%1'"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_ATTRIBUTE_HAS_NO_VALUES, tr("Attribute '%1' has no values"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_COLON_MISUSE, tr("Colon misuse: \n\'%1'"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_EVENT_HAS_NOT_ATTRIBUTE, tr("Attribute type '%1' does not belong to event type '%2': \n'%3'"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_NO_EVENT_NAME, tr("No event name given for filter '%1'"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_STRING, tr("Attribute type for '%1' does not exist"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_UNKNOWN_EVENT_TYPE, tr("Event type '%1' does not exist"));
|
||||
//addErrorHandler(GetModelFilterListResult::INFO_EVENT_ONLY_FILTER, tr("%1: Filtering by event type only"));
|
||||
//addErrorHandler(GetModelFilterListResult::INFO_NO_FILTERS, tr("No filters selected - now resetting Timeline Filters"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_VALUE_NOT_FOUND, tr("The attribute value '%1' is not a value of attribute type '%2'"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_NO_VALUE_GIVEN, tr("There are no values given inside the brackets: \n'%1'"));
|
||||
addErrorHandler(GetModelFilterListResult::ERR_TOO_MUCH_BRACKETS, tr("Too much brackets: \n'%1'"));
|
||||
}
|
||||
|
||||
|
||||
/* PRIVATE */ FilterWorker::Result makeResult(const int resultValue, const QString& additionalInformation = QString())
|
||||
{
|
||||
FilterWorker::Result result;
|
||||
|
||||
result.resultValue = resultValue;
|
||||
|
||||
if (!additionalInformation.isEmpty())
|
||||
{
|
||||
result.additionalInformation.append(additionalInformation);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* PRIVATE */ FilterWorker::Result makeResult(const int resultValue, const QStringList& additionalInformationList)
|
||||
{
|
||||
FilterWorker::Result result;
|
||||
|
||||
result.resultValue = resultValue;
|
||||
result.additionalInformation.append(additionalInformationList);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FilterWorker::GetModelFilterListResult FilterWorker::getModelFilterList(DetailData *detailData, const QJsonArray &filter, bool fromTypeSafe) // returns a ResultStruct, as the user has to know WHAT failures he did when writing the filter text by himself!
|
||||
{
|
||||
GetModelFilterListResult result;
|
||||
|
||||
if (filter.isEmpty()) // no text, no filters
|
||||
{
|
||||
//result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::INFO_NO_FILTERS));
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto i1 = filter.constBegin(); i1 != filter.constEnd(); ++i1) // seperate Event Type from Rest & get attribute list per event type >>> "Shot" "Munition{...},Bla{...},..." <<<
|
||||
{
|
||||
const QJsonObject ¤tFilter = (*i1).toObject();
|
||||
|
||||
//#warning TODO: used?
|
||||
// if (currentFilter.isEmpty())
|
||||
// {
|
||||
// result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_NO_EVENT_NAME,
|
||||
// QString::number(i1)));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (currentFilter[QStringLiteral("Active")].toBool(false))
|
||||
// continue;
|
||||
|
||||
QString eventTypeString = currentFilter[QStringLiteral("EventType")].toString(); // get event type string & look if event type string exists & get attribute keys for event type 0 = Event Type
|
||||
int eventType = -1;
|
||||
|
||||
if (fromTypeSafe)
|
||||
{
|
||||
bool ok = false;
|
||||
eventType = eventTypeString.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
eventType = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eventType = detailData->eventTypeLookup.getEventType(eventTypeString); // get event type by its string fromt he lookup list
|
||||
}
|
||||
|
||||
|
||||
QString eventTypeName = detailData->eventTypeLookup.getEventText(eventType);
|
||||
if (!eventTypeName.isEmpty())
|
||||
eventTypeString = eventTypeName;
|
||||
|
||||
|
||||
if (eventType == -1)
|
||||
{
|
||||
result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_UNKNOWN_EVENT_TYPE,
|
||||
eventTypeString));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
bool active = currentFilter[QStringLiteral("Active")].toBool(false);
|
||||
const QJsonArray &attributes = currentFilter[QStringLiteral("Attributes")].toArray();
|
||||
|
||||
if (attributes.isEmpty()) // if there are NO attributes, then add this a event-only-filter
|
||||
{
|
||||
ModelFilter mf; // already done!
|
||||
mf.eventType = eventType;
|
||||
mf.attributeType = QString(); // aka 'ATTRIBUTE_TYPE_EVENT_ONLY'
|
||||
mf.active = active;
|
||||
//mf.attributeValue = 0; QString is invalid when created
|
||||
result.result.append(mf);
|
||||
|
||||
continue; // next!
|
||||
}
|
||||
|
||||
// otherwise.. is/are attribute(s) then must have one Event Type and the Attributes (as one)
|
||||
|
||||
for (auto i2 = attributes.constBegin(); i2 != attributes.constEnd(); i2++) // process every value for that attribute
|
||||
{
|
||||
const QJsonObject &attribute = (*i2).toObject();
|
||||
QString attributeType = attribute[QStringLiteral("AttributeType")].toString(); // type => "GearType"
|
||||
|
||||
if (!fromTypeSafe)
|
||||
{
|
||||
attributeType = detailData->attributeTypeLookup.getAttributeType(attributeType); // get attribute type by attribute type string
|
||||
}
|
||||
|
||||
|
||||
// NOTE: fix this in ngldao timeline, too
|
||||
attributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
|
||||
|
||||
|
||||
if (attributeType.isEmpty()) // no attribute type found from attribute type string? next!
|
||||
{
|
||||
result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_STRING,
|
||||
attributeType));
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: fix this in ngldao timeline
|
||||
|
||||
// TODO: FIXME: we must trust that the attribute type is in the event *for now*. Because there is no backwards-lookup from *redirected* attributes back to the original !
|
||||
|
||||
|
||||
// if (!detailData->attributeEventLookup.isAttributeInEvent(eventType, attributeType)) // check if event has that attribute
|
||||
// {
|
||||
// QStringList vl;
|
||||
// vl.append(attributeTypeString);
|
||||
// vl.append(eventTypeString);
|
||||
// vl.append(currentFilterString);
|
||||
|
||||
// result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_EVENT_HAS_NOT_ATTRIBUTE,
|
||||
// vl));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
|
||||
// check if this is an pure string
|
||||
int interpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType);
|
||||
|
||||
if (interpreterType == DetailData::INTERPRETER_TYPE_NONE)
|
||||
{
|
||||
continue; // ignore, not filterable
|
||||
}
|
||||
|
||||
|
||||
const QJsonArray &attributeValues = attribute[QStringLiteral("AttributeValues")].toArray(); // values => "M3,M5, ..."
|
||||
for (auto i3 = attributeValues.constBegin(); i3 != attributeValues.constEnd(); ++i3)
|
||||
{
|
||||
QString attributeValueString = (*i3).toString(); // get single value >>> "M3" <<<
|
||||
|
||||
// remember: attribute value id is -2 for attribute types without entries in attribute value lookup <<<< Ist das noch so?
|
||||
|
||||
ModelFilter mf; // create a model filter for every value
|
||||
mf.eventType = eventType;
|
||||
mf.attributeType = attributeType;
|
||||
mf.active = active;
|
||||
mf.attributeValue = attributeValueString;
|
||||
result.result.append(mf);
|
||||
|
||||
// qWarning() << "new model filter: event type " << eventType << " attr type " << attributeType << " attr val " << attributeValueString << " active " << mf.active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool FilterWorker::handleResultValues(const QVector<Result> &resultList, QWidget* parentWidget, bool ignoreInfos)
|
||||
{
|
||||
bool errorOccured = false;
|
||||
InfoWindowEntryList iwel;
|
||||
|
||||
for (int i = 0; i < resultList.count(); i++)
|
||||
{
|
||||
FilterWorker::Result result = resultList.at(i);
|
||||
int resultValue = result.resultValue;
|
||||
|
||||
if (!errorOccured && (resultValue & GetModelFilterListResult::ERR) == GetModelFilterListResult::ERR) // check if ERROR-bit is set (when there are no errors yet)
|
||||
{
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
if (ignoreInfos && (resultValue & GetModelFilterListResult::INFO) == GetModelFilterListResult::INFO)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// lookup error handler
|
||||
InfoWindowEntry iwe;
|
||||
const ErrorHandler& eh = m_errorHandlerLookupMap.value(result.resultValue);
|
||||
if (!eh.isValid())
|
||||
{
|
||||
iwe.text = tr("Unhandled error (%1)");
|
||||
iwe.infoType = InfoWindowEntry::InfoTypes::Error;
|
||||
iwel.append(iwe);
|
||||
|
||||
continue; // cannot handle, handle next info
|
||||
}
|
||||
|
||||
|
||||
// add info to text
|
||||
int additionalInformationCount = result.additionalInformation.count();
|
||||
QString iweText = eh.errorText;
|
||||
|
||||
if (eh.errorParamCount) // only fill text if there is some text to fill with
|
||||
{
|
||||
for (int i2 = 0; i2 < eh.errorParamCount; i2++) // add every REQUESTED parameter by getting the value from the list (check if count is hogh enough, otherwise parameter will be '???')
|
||||
{
|
||||
if (additionalInformationCount >= eh.errorParamCount) // only add from addInfo list if the requested error param iterator < add info count !
|
||||
{
|
||||
iweText = iweText.arg(result.additionalInformation.at(i2));
|
||||
}
|
||||
else // add info is missing, fill with '???'
|
||||
{
|
||||
iweText = iweText.arg(QStringLiteral("???"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iwe.text = iweText;
|
||||
iwel.append(iwe);
|
||||
}
|
||||
|
||||
|
||||
if (iwel.count())
|
||||
{
|
||||
InfoWindow* iw = new InfoWindow(iwel, parentWidget);
|
||||
iw->show();
|
||||
}
|
||||
|
||||
return !errorOccured; // must return true if NO errors occured
|
||||
}
|
||||
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter to convert text-filter to model filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
#include <QMap>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class FilterWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
FilterWorker();
|
||||
~FilterWorker();
|
||||
static FilterWorker* s_instance;
|
||||
|
||||
public:
|
||||
static FilterWorker* getInstance();
|
||||
static void deleteInstance(); // TODO: to qt instance
|
||||
|
||||
// static Q_CONSTEXPR QLatin1Char filterSeparator() { return QLatin1Char(';'); }
|
||||
// static Q_CONSTEXPR QLatin1Char filterEventNamespace() { return QLatin1Char(':'); }
|
||||
// static Q_CONSTEXPR QLatin1Char attributeSeparator() { return QLatin1Char('+'); }
|
||||
// static Q_CONSTEXPR QLatin1Char attributeValueSeparator() { return QLatin1Char(','); }
|
||||
// static Q_CONSTEXPR QLatin1Char bracketOpen() { return QLatin1Char('{'); }
|
||||
// static Q_CONSTEXPR QLatin1Char bracketClose() { return QLatin1Char('}'); }
|
||||
|
||||
struct ModelFilter
|
||||
{
|
||||
int eventType = -1;
|
||||
QString attributeType;
|
||||
bool active = false;
|
||||
QString attributeValue; // stores IDs or values (position ("xxxx.xxx;xxxx.xxx"), doubles, etc.)
|
||||
};
|
||||
|
||||
struct Result
|
||||
{
|
||||
int resultValue = -1;
|
||||
QStringList additionalInformation;
|
||||
};
|
||||
|
||||
struct GetModelFilterListResult
|
||||
{
|
||||
// 4 Bit ResultType => [0000] [0000] <= 4 Bit ResultValues
|
||||
|
||||
enum ResultType
|
||||
{
|
||||
ERR = 0x80, // bit 8 set - 1000 0000
|
||||
WARN = 0x40, // bit 7 set - 0100 0000
|
||||
INFO = 0x20, // bit 6 set - 0010 0000
|
||||
};
|
||||
|
||||
enum ResultValues
|
||||
{
|
||||
//INFO_NO_FILTERS = INFO | 0,
|
||||
//INFO_EVENT_ONLY_FILTER = INFO | 1,
|
||||
|
||||
ERR_NO_EVENT_NAME = ERR | 0,
|
||||
ERR_COLON_MISUSE = ERR | 1,
|
||||
ERR_UNKNOWN_EVENT_TYPE = ERR | 2,
|
||||
ERR_ATTRIBUTE_HAS_NO_VALUES = ERR | 3,
|
||||
ERR_ATTRIBUTE_BLOCK_NOT_CLOSED = ERR | 4,
|
||||
ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_STRING = ERR | 5,
|
||||
//ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_TYPE = ERR | 6,
|
||||
ERR_EVENT_HAS_NOT_ATTRIBUTE = ERR | 7,
|
||||
ERR_VALUE_NOT_FOUND = ERR | 8,
|
||||
ERR_NO_VALUE_GIVEN = ERR | 9,
|
||||
ERR_TOO_MUCH_BRACKETS = ERR | 10,
|
||||
};
|
||||
|
||||
QVector<Result> resultValueList;
|
||||
QVector<ModelFilter> result;
|
||||
};
|
||||
|
||||
static GetModelFilterListResult getModelFilterList(DetailData *detailData, const QJsonArray &filter, bool fromTypeSafe = false); // returns a ResultStruct, as the user has to know WHAT failures he did when writing the filter text by himself!
|
||||
bool handleResultValues(const QVector<Result> &resultList, QWidget* parentWidget = nullptr, bool ignoreInfos = false); // returns true if NO error(s) occured (info & warnings are okay) - false = ERRORS !!!
|
||||
|
||||
private:
|
||||
class ErrorHandler
|
||||
{
|
||||
public:
|
||||
ErrorHandler(const QString& errorText = QString(), const int errorParamCount = 0)
|
||||
: errorText(errorText)
|
||||
, errorParamCount(errorParamCount)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
if (errorText.isEmpty() && !errorParamCount)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString errorText;
|
||||
int errorParamCount;
|
||||
};
|
||||
|
||||
using ErrorHandlerLookupMap = QMap<int, ErrorHandler>;
|
||||
ErrorHandlerLookupMap m_errorHandlerLookupMap;
|
||||
};
|
||||
|
||||
using ModelFilterList = QVector<FilterWorker::ModelFilter>;
|
||||
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* window to provide errors and informations when applying filter to excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "InfoWindow.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
InfoWindow::InfoWindow(const InfoWindowEntryList &infoWindowEntryList, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, infoWindowEntryList(infoWindowEntryList)
|
||||
|
||||
|
||||
// ui
|
||||
, mainLayout(new QVBoxLayout())
|
||||
, pbPrev(new QPushButton(tr("< Previous")))
|
||||
, lbIndicator(new QLabel())
|
||||
, pbNext(new QPushButton(tr("Next >")))
|
||||
, pbOK(new QPushButton(tr("OK")))
|
||||
, teText(new QTextEdit(tr("Missing Message")))
|
||||
|
||||
, listPosition(-1) // invalid / not positioned
|
||||
{
|
||||
if (!infoWindowEntryList.count())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
connect(pbPrev, &QPushButton::clicked, this, &InfoWindow::slotPrev);
|
||||
connect(pbNext, &QPushButton::clicked, this, &InfoWindow::slotNext);
|
||||
connect(pbOK , &QPushButton::clicked, this, &InfoWindow::deleteLater);
|
||||
|
||||
|
||||
// top buttons (< & >)
|
||||
QHBoxLayout* topButtonsLayout = new QHBoxLayout();
|
||||
pbPrev->setEnabled(false); // set prev disabled by default (as there is no prev)
|
||||
topButtonsLayout->addWidget(pbPrev);
|
||||
topButtonsLayout->addWidget(lbIndicator);
|
||||
topButtonsLayout->addWidget(pbNext);
|
||||
pbNext->setEnabled(false); // set next disabled by default (as there CAN be no next)
|
||||
QWidget* topButtonsWidget = new QWidget();
|
||||
topButtonsWidget->setLayout(topButtonsLayout);
|
||||
mainLayout->addWidget(topButtonsWidget);
|
||||
|
||||
|
||||
// text field for info / error / warning text
|
||||
mainLayout->addWidget(teText);
|
||||
|
||||
|
||||
// bottom buttons (ignore, ignore all, cancel)
|
||||
QHBoxLayout* bottomButtonsLayout = new QHBoxLayout();
|
||||
bottomButtonsLayout->addWidget(pbOK);
|
||||
QWidget* bottomButtonsWidget = new QWidget();
|
||||
bottomButtonsWidget->setLayout(bottomButtonsLayout);
|
||||
mainLayout->addWidget(bottomButtonsWidget);
|
||||
|
||||
|
||||
// fill first thingy....
|
||||
slotNext();
|
||||
|
||||
this->setLayout(mainLayout);
|
||||
}
|
||||
|
||||
void InfoWindow::checkNavigationButtons(int newPosition)
|
||||
{
|
||||
int listCount = infoWindowEntryList.count();
|
||||
|
||||
if (newPosition -1 >= 0) // if there is no prev, do not show prev
|
||||
{
|
||||
pbPrev->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
pbPrev->setEnabled(false);
|
||||
}
|
||||
|
||||
if (newPosition +2 > listCount) // if there is no next, do not show next
|
||||
{
|
||||
pbNext->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pbNext->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void InfoWindow::slotPrev()
|
||||
{
|
||||
int listCount = infoWindowEntryList.count();
|
||||
int prevListPosition = listPosition - 1 /* 0 -1 = -1 */;
|
||||
|
||||
checkNavigationButtons(prevListPosition);
|
||||
|
||||
if (prevListPosition >= 0 && prevListPosition < listCount) // if there is a prev one
|
||||
{
|
||||
teText->setText(infoWindowEntryList.at(prevListPosition).text); // set text
|
||||
|
||||
QString indicatorString = QStringLiteral("%1/%2");
|
||||
lbIndicator->setText(indicatorString.arg(prevListPosition + 1 /* so there is no "Info 0" */).arg(listCount)); // set indicator like: "Info 4/8"
|
||||
|
||||
listPosition = prevListPosition; // set new current list position
|
||||
}
|
||||
}
|
||||
|
||||
void InfoWindow::slotNext()
|
||||
{
|
||||
int listCount = infoWindowEntryList.count();
|
||||
int nextListPosition = listPosition + 1 /* -1 + 1 = 0 */;
|
||||
|
||||
checkNavigationButtons(nextListPosition);
|
||||
|
||||
if (nextListPosition >= 0 && nextListPosition < listCount) // if there is a next one (some safety checks)
|
||||
{
|
||||
teText->setText(infoWindowEntryList.at(nextListPosition).text); // set text
|
||||
|
||||
QString indicatorString = QStringLiteral("%1/%2");
|
||||
lbIndicator->setText(indicatorString.arg(nextListPosition + 1 /* so there is no "Info 0" */).arg(listCount)); // set indicator like: "Info 4/8"
|
||||
|
||||
listPosition = nextListPosition; // set new current list position
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* window to provide errors and informations when applying filter to excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
#include <QLabel>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
struct InfoWindowEntry
|
||||
{
|
||||
enum class InfoTypes
|
||||
{
|
||||
Error,
|
||||
Info,
|
||||
Warning
|
||||
};
|
||||
|
||||
QString title;
|
||||
QString text;
|
||||
InfoTypes infoType = InfoTypes::Info; // error, info, warning
|
||||
};
|
||||
|
||||
typedef QVector<InfoWindowEntry> InfoWindowEntryList;
|
||||
|
||||
|
||||
class InfoWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InfoWindow(const InfoWindowEntryList &infoWindowEntryList, QWidget* parent = nullptr);
|
||||
~InfoWindow() = default;
|
||||
|
||||
private:
|
||||
InfoWindowEntryList infoWindowEntryList;
|
||||
QVBoxLayout* mainLayout;
|
||||
QPushButton* pbPrev;
|
||||
QLabel* lbIndicator;
|
||||
QPushButton* pbNext;
|
||||
QPushButton* pbOK;
|
||||
QTextEdit* teText;
|
||||
int listPosition; // current position in list which information is currently shown
|
||||
|
||||
void checkNavigationButtons(int newPosition);
|
||||
|
||||
|
||||
public slots:
|
||||
void slotPrev();
|
||||
void slotNext();
|
||||
};
|
||||
|
||||
}
|
||||
+1357
File diff suppressed because it is too large.
Load diff
+81
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FilterWindow</class>
|
||||
<widget class="QWidget" name="FilterWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>628</width>
|
||||
<height>393</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Filter Table</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Closing this window will reset all filters for the timeline.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaContent">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>610</width>
|
||||
<height>358</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="filterContainer"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* abstract widget with basic/easy implementation of new widget types in Filter Table
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
AbstractAttributeWidget::AbstractAttributeWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_abstractMainLayout(new QHBoxLayout(this))
|
||||
{
|
||||
QPushButton *pbDelete(new QPushButton(QStringLiteral("-")));
|
||||
pbDelete->setPalette(QPalette(QColor("red")));
|
||||
pbDelete->setToolTip(tr("Delete this value"));
|
||||
|
||||
m_abstractMainLayout->addWidget(pbDelete);
|
||||
connect(pbDelete, &QPushButton::clicked, this, &AbstractAttributeWidget::slotDelete);
|
||||
}
|
||||
|
||||
void AbstractAttributeWidget::slotDelete()
|
||||
{
|
||||
//delete this; // deletes itself from the parents layout. DONE! <= UGH! Ich als Azubi halt :)
|
||||
emit deleteClicked();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void AbstractAttributeWidget::addCustomWidget(QWidget* widget)
|
||||
{
|
||||
m_abstractMainLayout->insertWidget(0, widget, 1, Qt::AlignLeft); // add widget to the left
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* abstract widget with basic/easy implementation of new widget types in Filter Table
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QHBoxLayout;
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class AbstractAttributeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AbstractAttributeWidget(QWidget *parent = nullptr);
|
||||
virtual QString filterText(bool typeSafe = false) const = 0; // only returns the chosen values for this attribute
|
||||
virtual void updateData(DetailData *detailData) = 0;
|
||||
|
||||
protected:
|
||||
void addCustomWidget(QWidget* widget); // use this method to add the abstracted widget to this base classes ready layout
|
||||
protected:
|
||||
QHBoxLayout *m_abstractMainLayout;
|
||||
|
||||
private slots:
|
||||
void slotDelete();
|
||||
|
||||
signals:
|
||||
void signalChanges();
|
||||
void deleteClicked();
|
||||
};
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select area with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "AreaWidget.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QSpinBox>
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
AreaWidget::AreaWidget(int n1, int n2, int o1, int o2, QWidget *parent)
|
||||
: AbstractAttributeWidget(parent)
|
||||
, sbN1(new QSpinBox())
|
||||
, sbN2(new QSpinBox())
|
||||
, sbO1(new QSpinBox())
|
||||
, sbO2(new QSpinBox())
|
||||
{
|
||||
connect(sbN1, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
|
||||
connect(sbN2, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
|
||||
connect(sbO1, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
|
||||
connect(sbO2, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
|
||||
|
||||
QString sbNPrefix = tr("N ");
|
||||
QString sbOPrefix = tr("O ");
|
||||
|
||||
sbN1->setPrefix(sbNPrefix);
|
||||
sbN2->setPrefix(sbNPrefix);
|
||||
sbO1->setPrefix(sbOPrefix);
|
||||
sbO2->setPrefix(sbOPrefix);
|
||||
|
||||
sbN1->setRange(n1, n2);
|
||||
sbN2->setRange(n1, n2);
|
||||
sbO1->setRange(o1, o2);
|
||||
sbO2->setRange(o1, o2);
|
||||
|
||||
sbN1->setValue(n1);
|
||||
sbN2->setValue(n2);
|
||||
sbO1->setValue(o1);
|
||||
sbO2->setValue(o2);
|
||||
|
||||
|
||||
QGridLayout* mainLayout = new QGridLayout();
|
||||
|
||||
mainLayout->addWidget(sbN1, 0, 1); // top center
|
||||
mainLayout->addWidget(sbN2, 2, 1); // bottom center
|
||||
mainLayout->addWidget(sbO1, 1, 0); // left center
|
||||
mainLayout->addWidget(sbO2, 1, 2); // right center
|
||||
|
||||
QWidget* mainLayoutWidget = new QWidget();
|
||||
mainLayoutWidget->setLayout(mainLayout);
|
||||
|
||||
this->addCustomWidget(mainLayoutWidget);
|
||||
}
|
||||
|
||||
QString AreaWidget::filterText(bool typeSafe) const
|
||||
{
|
||||
Q_UNUSED(typeSafe);
|
||||
return QStringLiteral("%1x%2x%3x%4").arg(sbN1->cleanText(), sbN2->cleanText(), sbO1->cleanText(), sbO2->cleanText());
|
||||
}
|
||||
|
||||
void AreaWidget::updateData(DetailData *detailData)
|
||||
{
|
||||
// data cannot change
|
||||
Q_UNUSED(detailData);
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select area with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
|
||||
|
||||
class QSpinBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class AreaWidget : public AbstractAttributeWidget//QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AreaWidget(int n1, int n2, int o1, int o2, QWidget *parent = nullptr);
|
||||
QString filterText(bool typeSafe = false) const override;
|
||||
void updateData(DetailData *detailData) override;
|
||||
|
||||
private:
|
||||
QSpinBox* sbN1;
|
||||
QSpinBox* sbN2;
|
||||
QSpinBox* sbO1;
|
||||
QSpinBox* sbO2;
|
||||
};
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select true / false
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#include "CheckBoxWidget.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
CheckBoxWidget::CheckBoxWidget(DetailData *detailData, const QString &attributeType, const QString &initialValue, QWidget* parent)
|
||||
: AbstractAttributeWidget(parent)
|
||||
, cbCheck(new QCheckBox(this))
|
||||
{
|
||||
connect(cbCheck, &QCheckBox::stateChanged, this, &CheckBoxWidget::signalChanges);
|
||||
|
||||
trueValue = detailData->attributeValueLookup.getValueStringFromValueId(attributeType, 1);
|
||||
falseValue = detailData->attributeValueLookup.getValueStringFromValueId(attributeType, 0);
|
||||
|
||||
cbCheck->setText(trueValue);
|
||||
|
||||
addCustomWidget(cbCheck);
|
||||
|
||||
if (initialValue.isEmpty())
|
||||
return;
|
||||
|
||||
cbCheck->setChecked(initialValue != QStringLiteral("0"));
|
||||
}
|
||||
|
||||
|
||||
void CheckBoxWidget::setText(const QString &text)
|
||||
{
|
||||
cbCheck->setText(text);
|
||||
}
|
||||
|
||||
|
||||
QString CheckBoxWidget::filterText(bool typeSafe) const
|
||||
{
|
||||
QString filterText;
|
||||
|
||||
if (cbCheck->isChecked())
|
||||
{
|
||||
if (typeSafe)
|
||||
filterText += QStringLiteral("1");
|
||||
else
|
||||
filterText += trueValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (typeSafe)
|
||||
filterText += QStringLiteral("0");
|
||||
else
|
||||
filterText += falseValue;
|
||||
}
|
||||
|
||||
return filterText;
|
||||
}
|
||||
|
||||
|
||||
void CheckBoxWidget::updateData(DetailData *)
|
||||
{
|
||||
// data cannot change
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select true / false
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class CheckBoxWidget : public AbstractAttributeWidget//QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CheckBoxWidget(DetailData *detailData, const QString &attributeType, const QString &initialValue, QWidget *parent = nullptr);
|
||||
QString filterText(bool typeSafe = false) const override;
|
||||
void updateData(DetailData *) override;
|
||||
void setText(const QString &text);
|
||||
|
||||
private:
|
||||
QCheckBox* cbCheck;
|
||||
QString trueValue;
|
||||
QString falseValue;
|
||||
};
|
||||
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select pre-defined value
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "ComboBox.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
// combobox must be aware of getting his own data, as he needs to update himself (performance and coding reasons)
|
||||
ComboBox::ComboBox(DetailData *detailData, const QString &attributeType, int eventType, const QString &initialValue, QWidget* parent)
|
||||
: AbstractAttributeWidget(parent)
|
||||
, m_cbValues(new QComboBox())
|
||||
, m_eventType(eventType)
|
||||
, m_logger(getLogger("EventFilter.ComboBox"))
|
||||
{
|
||||
connect(m_cbValues, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ComboBox::signalChanges);
|
||||
|
||||
addCustomWidget(m_cbValues);
|
||||
|
||||
m_concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType); // returns 'attributeType' if there is no redirection
|
||||
|
||||
updateData(detailData);
|
||||
|
||||
if (initialValue.isEmpty())
|
||||
return;
|
||||
|
||||
bool k = false;
|
||||
int initialValueKey = initialValue.toInt(&k);// everything is typesafe now, saved as index keys, not values which index have to be looked up anymore
|
||||
|
||||
if (initialValueKey < 0 || !k) // invalid!
|
||||
{
|
||||
WARNING_LOG(m_logger) << "ComboBox::c_tor: initialValueKey < 0 (" << initialValueKey << ")" << "initialValue: " << initialValue;
|
||||
return;
|
||||
}
|
||||
|
||||
// select initial value
|
||||
m_cbValues->setCurrentIndex(m_cbValues->findData(initialValueKey, Qt::UserRole)); // set initial value by id WARNING: does not check for invalid index
|
||||
}
|
||||
|
||||
|
||||
void ComboBox::updateData(DetailData *detailData)
|
||||
{
|
||||
int lastSelectedKey = -1;
|
||||
|
||||
if (m_cbValues->currentIndex() > 0) // none selected yet (if m_cbValues has to be built first)
|
||||
lastSelectedKey = m_cbValues->itemData(m_cbValues->currentIndex()).toInt();
|
||||
|
||||
// now reset and load new data
|
||||
QSignalBlocker blocker(m_cbValues);
|
||||
m_cbValues->clear();
|
||||
m_avm = detailData->m_attributeValueLookupDtc.getAttributeValueMap(m_eventType, m_concreteAttributeType);
|
||||
if (m_avm.isEmpty())
|
||||
m_avm = detailData->attributeValueLookup.getAttributeValueMap(m_concreteAttributeType); // get new avm
|
||||
|
||||
for (auto i = m_avm.constBegin(); i != m_avm.constEnd(); ++i)
|
||||
{
|
||||
m_cbValues->addItem(i.value()
|
||||
#ifdef DEBUG
|
||||
+ " (" + QString::number(i.key()) + ")"
|
||||
#endif
|
||||
, i.key()); // add value and key (storing key as userdata)
|
||||
}
|
||||
|
||||
if (lastSelectedKey < 0) // only set new index if there was a last selected index first
|
||||
{
|
||||
m_cbValues->setCurrentIndex(0); // set to the first entry
|
||||
return; // done!
|
||||
}
|
||||
|
||||
// select old value (if one)
|
||||
m_cbValues->setCurrentIndex(m_cbValues->findData(lastSelectedKey, Qt::UserRole)); // set initial value by id WARNING: does not check for invalid index
|
||||
|
||||
DEBUG_LOG(m_logger) << "ComboBox: no initial item index found for value id" << lastSelectedKey;
|
||||
}
|
||||
|
||||
|
||||
QString ComboBox::filterText(bool typeSafe) const
|
||||
{
|
||||
QString resultFilterText;
|
||||
|
||||
bool ok = false;
|
||||
int key = m_cbValues->itemData(m_cbValues->currentIndex()).toInt(&ok);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return resultFilterText;
|
||||
}
|
||||
|
||||
if (typeSafe)
|
||||
resultFilterText = QString::number(key); // returns the selected value's ID
|
||||
else
|
||||
resultFilterText = m_avm.value(key); // returns the selected value's STRING
|
||||
|
||||
|
||||
return resultFilterText;
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select pre-defined value
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
class QComboBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class ComboBox : public AbstractAttributeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ComboBox(DetailData *detailData, const QString &attributeType,
|
||||
int eventType, const QString &initialValue, QWidget *parent = nullptr); // combobox fills itself with values, by getting informations from FilterData
|
||||
QString filterText(bool typeSafe = false) const override;
|
||||
void updateData(DetailData *detailData) override;
|
||||
|
||||
private:
|
||||
QComboBox *m_cbValues;
|
||||
int m_eventType;
|
||||
QString m_concreteAttributeType;
|
||||
AttributeValueMap m_avm;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "DefaultRangeWidget.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QSpinBox>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
DefaultRangeWidget::DefaultRangeWidget(unsigned int min, unsigned int max, const QString &prefix, const QString &suffix, const QString &initialValue, QWidget *parent)
|
||||
: AbstractAttributeWidget(parent)
|
||||
, box1(new QSpinBox())
|
||||
, box2(new QSpinBox())
|
||||
, m_logger(getLogger("EventFilter.Widgets.DefaultRangeWidget"))
|
||||
{
|
||||
connect(box1, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &DefaultRangeWidget::signalChanges);
|
||||
connect(box2, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &DefaultRangeWidget::signalChanges);
|
||||
|
||||
box1->setRange(min, max);
|
||||
box2->setRange(min, max);
|
||||
|
||||
box1->setPrefix(prefix);
|
||||
box2->setPrefix(prefix);
|
||||
|
||||
box1->setSuffix(suffix);
|
||||
box2->setSuffix(suffix);
|
||||
|
||||
box1->setValue(min);
|
||||
box2->setValue(max);
|
||||
|
||||
|
||||
QHBoxLayout* mainLayout = new QHBoxLayout();
|
||||
|
||||
mainLayout->addWidget(new QLabel(tr("between")));
|
||||
mainLayout->addWidget(box1);
|
||||
mainLayout->addWidget(new QLabel(tr("and")));
|
||||
mainLayout->addWidget(box2);
|
||||
|
||||
QWidget* mainLayoutWidget = new QWidget();
|
||||
mainLayoutWidget->setLayout(mainLayout);
|
||||
|
||||
this->addCustomWidget(mainLayoutWidget);
|
||||
|
||||
box1->setFocus(); // focus first widget
|
||||
|
||||
|
||||
// not necessary, as initialValues are already checked bz checkValue ...
|
||||
if (initialValue.length()) // is there an initial value ?
|
||||
{
|
||||
QStringList valueList = initialValue.split(QLatin1Char('-'), QString::SkipEmptyParts);
|
||||
|
||||
if (valueList.count() != 2) // must be exactly 2 (e.g. "99,999")
|
||||
{
|
||||
WARNING_LOG(m_logger) << "DefaultRangeWidget: invalid initial value '" << initialValue << "'";
|
||||
return;
|
||||
}
|
||||
|
||||
bool k1 = false;
|
||||
bool k2 = false;
|
||||
|
||||
unsigned int val1 = valueList.at(0).toUInt(&k1);
|
||||
unsigned int val2 = valueList.at(1).toUInt(&k2);
|
||||
|
||||
if (!k1 || !k2)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "DefaultRangeWidget: initial value is not numeric '" << initialValue << "'";
|
||||
return;
|
||||
}
|
||||
|
||||
box1->setValue(val1);
|
||||
box2->setValue(val2);
|
||||
}
|
||||
}
|
||||
|
||||
QString DefaultRangeWidget::filterText(bool typeSafe) const
|
||||
{
|
||||
Q_UNUSED(typeSafe);
|
||||
return QStringLiteral("%1 - %2").arg(box1->value(), box2->value());
|
||||
}
|
||||
|
||||
void DefaultRangeWidget::updateData(DetailData *detailData)
|
||||
{
|
||||
// not needed, as min / max is always static (0 - 999 bullets, etc)
|
||||
Q_UNUSED(detailData);
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
|
||||
class QHBoxLayout;
|
||||
class QSpinBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class DefaultRangeWidget : public AbstractAttributeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DefaultRangeWidget(unsigned int min,
|
||||
unsigned int max,
|
||||
const QString &prefix,
|
||||
const QString &suffix,
|
||||
const QString &initialValue = QString(),
|
||||
QWidget *parent = nullptr);
|
||||
QString filterText(bool typeSafe = false) const override;
|
||||
void updateData(DetailData *detailData) override;
|
||||
|
||||
private:
|
||||
QSpinBox* box1;
|
||||
QSpinBox* box2;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select area with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "RadiusWidget.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QSpinBox>
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
RadiusWidget::RadiusWidget(int n1, int n2, int o1, int o2, int radius, QWidget *parent)
|
||||
: AbstractAttributeWidget(parent)
|
||||
, sbN(new QSpinBox(this))
|
||||
, sbO(new QSpinBox(this))
|
||||
, sbR(new QSpinBox(this))
|
||||
{
|
||||
Q_ASSERT(false); // not ready to use!
|
||||
|
||||
QString sbNPrefix = tr("N ");
|
||||
QString sbOPrefix = tr("O ");
|
||||
QString sbRPrefix = tr("radius of ");
|
||||
|
||||
sbN->setPrefix(sbNPrefix);
|
||||
sbO->setPrefix(sbOPrefix);
|
||||
sbR->setPrefix(sbRPrefix);
|
||||
|
||||
sbN->setRange(n1, n2);
|
||||
sbO->setRange(o1, o2);
|
||||
sbR->setRange(0, 9999);
|
||||
|
||||
sbN->setValue(n1);
|
||||
sbO->setValue(o1);
|
||||
sbR->setValue(radius);
|
||||
|
||||
|
||||
|
||||
QGridLayout* mainLayout = new QGridLayout();
|
||||
|
||||
mainLayout->addWidget(sbN, 0, 0); // left
|
||||
mainLayout->addWidget(sbR, 0, 1); // middle
|
||||
mainLayout->addWidget(sbO, 0, 2); // right
|
||||
|
||||
QWidget* mainLayoutWidget = new QWidget();
|
||||
mainLayoutWidget->setLayout(mainLayout);
|
||||
|
||||
addCustomWidget(mainLayoutWidget);
|
||||
}
|
||||
|
||||
QString RadiusWidget::filterText(bool typeSafe) const
|
||||
{
|
||||
Q_UNUSED(typeSafe);
|
||||
return QStringLiteral("%1x%2x%3").arg(sbN->cleanText(), sbO->cleanText(), sbR->cleanText());
|
||||
}
|
||||
|
||||
void RadiusWidget::updateData(DetailData *)
|
||||
{
|
||||
// TODO: !
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select radius with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
|
||||
class QSpinBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class RadiusWidget : public AbstractAttributeWidget//QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RadiusWidget(int n1, int n2, int o1, int o2, int radius, QWidget *parent = nullptr);
|
||||
QString filterText(bool typeSafe = false) const override;
|
||||
void updateData(DetailData *detailData) override;
|
||||
|
||||
private:
|
||||
QSpinBox* sbN;
|
||||
QSpinBox* sbO;
|
||||
QSpinBox* sbR; // radius
|
||||
};
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between time
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "logger.h"
|
||||
#include "TimeRangeWidget.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
#include <LtsWidgets/lts_date_time_edit.h>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDateTime>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
TimeRangeWidget::TimeRangeWidget(DetailData *detailData, const QString &initialValue, QWidget *parent)
|
||||
: AbstractAttributeWidget(parent)
|
||||
, m_logger(getLogger("EventFilter.Widgets.TimeRangeWidget"))
|
||||
, m_edit1(new LtsWidgets::LtsDateTimeEdit(this))
|
||||
, m_edit2(new LtsWidgets::LtsDateTimeEdit(this))
|
||||
{
|
||||
connect(m_edit1, &LtsWidgets::LtsDateTimeEdit::dateTimeChanged, this, &TimeRangeWidget::signalChanges);
|
||||
connect(m_edit2, &LtsWidgets::LtsDateTimeEdit::dateTimeChanged, this, &TimeRangeWidget::signalChanges);
|
||||
|
||||
// m_edit1->setCalendarPopup(true);
|
||||
// m_edit2->setCalendarPopup(true);
|
||||
|
||||
// m_edit1->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
|
||||
// m_edit2->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
|
||||
|
||||
QHBoxLayout* mainLayout = new QHBoxLayout();
|
||||
|
||||
mainLayout->addWidget(new QLabel(tr("between")));
|
||||
mainLayout->addWidget(m_edit1);
|
||||
mainLayout->addWidget(new QLabel(tr("and")));
|
||||
mainLayout->addWidget(m_edit2);
|
||||
|
||||
QWidget* mainLayoutWidget = new QWidget();
|
||||
mainLayoutWidget->setLayout(mainLayout);
|
||||
|
||||
addCustomWidget(mainLayoutWidget);
|
||||
|
||||
m_edit1->setFocus(); // focus first widget
|
||||
|
||||
|
||||
updateData(detailData);
|
||||
|
||||
|
||||
if (initialValue.isEmpty())
|
||||
return;
|
||||
|
||||
const auto initialTimeRange(initialValue.splitRef(QLatin1Char('-'), QString::SkipEmptyParts));
|
||||
|
||||
if (initialTimeRange.count() != 2)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "invalid initial time range value: " << initialValue;
|
||||
return;
|
||||
}
|
||||
|
||||
bool k = false;
|
||||
qint64 time = initialTimeRange.at(0).toInt(&k);
|
||||
time *= 1000;
|
||||
|
||||
if (!k)
|
||||
WARNING_LOG(m_logger) << "invalid initial time range start value: " << initialTimeRange.at(0).toString();
|
||||
else
|
||||
m_edit1->setMsecsSinceEpoch(time);
|
||||
|
||||
|
||||
time = initialTimeRange.at(1).toInt(&k);
|
||||
time *= 1000;
|
||||
|
||||
if (!k)
|
||||
WARNING_LOG(m_logger) << "invalid initial time range start value: " << initialTimeRange.at(1).toString();
|
||||
else
|
||||
m_edit2->setMsecsSinceEpoch(time);
|
||||
}
|
||||
|
||||
|
||||
QString TimeRangeWidget::filterText(bool typeSafe) const
|
||||
{
|
||||
(void)typeSafe;
|
||||
QString filterText;
|
||||
|
||||
filterText += QString::number(m_edit1->msecsSinceEpoch() / 1000 /* otherwise would not fit into int */); // secs since epoch
|
||||
filterText += QLatin1Char('-'); // trennzeichen
|
||||
filterText += QString::number(m_edit2->msecsSinceEpoch() / 1000 /* otherwise would not fit into int */); // s.a.a.
|
||||
|
||||
return filterText;
|
||||
}
|
||||
|
||||
|
||||
void TimeRangeWidget::updateData(DetailData *detailData)
|
||||
{
|
||||
LtsSession::LtsSession *session = detailData->session();
|
||||
m_edit1->setMsecsSinceEpoch(session->partitionTime() - 60 * 1000 /* TODO: minus 1 minute offset ? */);
|
||||
m_edit2->setMsecsSinceEpoch(session->partitionTime());
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between time
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
|
||||
namespace LtsWidgets
|
||||
{
|
||||
class LtsDateTimeEdit;
|
||||
}
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class TimeRangeWidget : public AbstractAttributeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TimeRangeWidget(DetailData *detailData, const QString &initialValue, QWidget *parent = nullptr);
|
||||
QString filterText(bool typeSafe = false) const override;
|
||||
void updateData(DetailData *detailData) override;
|
||||
|
||||
private:
|
||||
NGL::INGLLogger &m_logger;
|
||||
public:
|
||||
LtsWidgets::LtsDateTimeEdit *m_edit1;
|
||||
LtsWidgets::LtsDateTimeEdit *m_edit2;
|
||||
};
|
||||
|
||||
}
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Helper classes to retrieve attribute values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Christian Ehrlicher, NLE, 2020-02-07
|
||||
*/
|
||||
|
||||
#include "attribute_value_lookup.h"
|
||||
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <OperatorManagement/opm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
|
||||
#include <OperatorManagement/opm_translation.h>
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
//
|
||||
// AvmChargeType
|
||||
//
|
||||
AttributeValueMap AvmChargeType::getAttributeValueMap(int eventType) const
|
||||
{
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
|
||||
using namespace ProjectDataManagement;
|
||||
QVector<ChargeType> charges;
|
||||
switch (eventType)
|
||||
{
|
||||
case EventType::Hit:
|
||||
case EventType::WeaponAssignment:
|
||||
case EventType::FireEvent:
|
||||
charges = m_dtc->chargesForGearClass(GearClass::DuelSim);
|
||||
break;
|
||||
case EventType::HitBuilding:
|
||||
charges = m_dtc->chargesForGearClass(GearClass::DuelSim);
|
||||
Q_FALLTHROUGH();
|
||||
case EventType::HitEffectSimulation:
|
||||
charges += m_dtc->chargesForGearClass(GearClass::Artillery);
|
||||
charges += m_dtc->chargesForGearClass(GearClass::Mortar);
|
||||
charges += m_dtc->chargesForGearClass(GearClass::Geopairing);
|
||||
charges += m_dtc->chargesForGearClass(GearClass::AirSupport);
|
||||
charges += m_dtc->chargesForGearClass(GearClass::MineArea);
|
||||
charges += m_dtc->chargesForGearClass(GearClass::Biological);
|
||||
charges += m_dtc->chargesForGearClass(GearClass::Chemical);
|
||||
break;
|
||||
case EventType::HitB:
|
||||
charges = m_dtc->chargesForGearClass(GearClass::Biological);
|
||||
break;
|
||||
case EventType::HitC:
|
||||
charges = m_dtc->chargesForGearClass(GearClass::Chemical);
|
||||
break;
|
||||
case EventType::BCContamination:
|
||||
charges = m_dtc->chargesForGearClass(GearClass::Biological);
|
||||
charges += m_dtc->chargesForGearClass(GearClass::Chemical);
|
||||
break;
|
||||
case EventType::HitMine:
|
||||
case EventType::EnterMineArea:
|
||||
case EventType::LeaveMineArea:
|
||||
case EventType::MineArea:
|
||||
charges = m_dtc->chargesForGearClass(GearClass::MineArea);
|
||||
//charges =+ dtc->chargesForGearClass(GearClass::MineSingle); // same charges
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(!charges.isEmpty());
|
||||
|
||||
AttributeValueMap ret;
|
||||
for (const ChargeType &data : qAsConst(charges))
|
||||
ret.insert(data.id(), m_dtc->trChargeTypeShortName(data.id()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AvmChargeType::getValueStringFromValueId(int attributeValueId) const
|
||||
{
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
return m_dtc->trChargeTypeShortName(attributeValueId);
|
||||
}
|
||||
|
||||
//
|
||||
// AvmGearType
|
||||
//
|
||||
AttributeValueMap AvmGearType::getAttributeValueMap(int eventType) const
|
||||
{
|
||||
using namespace ProjectDataManagement;
|
||||
if (eventType != EventType_def::WeaponAssignment &&
|
||||
eventType != EventType_def::FireEvent)
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
|
||||
const auto gearTypes = m_dtc->gearTypes();
|
||||
AttributeValueMap ret;
|
||||
for (const auto &data : gearTypes)
|
||||
{
|
||||
if (data.gearClassId() == GearClass::DuelSim &&
|
||||
data.tasCode() != 0)
|
||||
ret.insert(data.id(), m_dtc->trGearTypeName(data.id()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AvmGearType::getValueStringFromValueId(int attributeValueId) const
|
||||
{
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
return m_dtc->trGearTypeName(attributeValueId);
|
||||
}
|
||||
|
||||
//
|
||||
// AvmParty
|
||||
//
|
||||
AttributeValueMap AvmParty::getAttributeValueMap(int eventType) const
|
||||
{
|
||||
Q_UNUSED(eventType);
|
||||
|
||||
using namespace ParticipantManagement;
|
||||
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
|
||||
const auto parties = m_dtc->partys();
|
||||
AttributeValueMap ret;
|
||||
for (const auto &data : parties)
|
||||
ret.insert(data.id(), trPartyName(data.name()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AvmParty::getValueStringFromValueId(int attributeValueId) const
|
||||
{
|
||||
using namespace ParticipantManagement;
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
return trPartyName(m_dtc->party(attributeValueId).name());
|
||||
}
|
||||
|
||||
//
|
||||
// AvmEquipmentNumber
|
||||
//
|
||||
AttributeValueMap AvmEquipmentNumber::getAttributeValueMap(int eventType) const
|
||||
{
|
||||
Q_UNUSED(eventType);
|
||||
|
||||
using namespace ParticipantManagement;
|
||||
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
|
||||
AttributeValueMap ret;
|
||||
auto cb = [&ret](const ParticipantManagement::Participant & p) -> void
|
||||
{
|
||||
if (!p.equipmentNumber().is_set())
|
||||
return;
|
||||
const auto equipNo = p.equipmentNumber().get();
|
||||
ret.insert(equipNo, QString::number(equipNo));
|
||||
};
|
||||
m_dtc->participants(cb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AvmEquipmentNumber::getValueStringFromValueId(int attributeValueId) const
|
||||
{
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
auto ret = m_dtc->participant(attributeValueId).equipmentNumber();
|
||||
return ret.is_set() ? QString::number(ret.get()) : QString();
|
||||
}
|
||||
|
||||
//
|
||||
// AvmOperator
|
||||
//
|
||||
AttributeValueMap AvmOperator::getAttributeValueMap(int eventType) const
|
||||
{
|
||||
Q_UNUSED(eventType);
|
||||
|
||||
using namespace OperatorManagement;
|
||||
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
|
||||
const auto users = m_dtc->users();
|
||||
AttributeValueMap ret;
|
||||
for (const auto &data : users)
|
||||
ret.insert(data.id(), QString::fromStdString(data.name()));
|
||||
ret.insert(0, QObject::tr("EXCON"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AvmOperator::getValueStringFromValueId(int attributeValueId) const
|
||||
{
|
||||
if (attributeValueId == 0)
|
||||
return QObject::tr("EXCON");
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
return QString::fromStdString(m_dtc->user(attributeValueId).name());
|
||||
}
|
||||
|
||||
//
|
||||
// AvmBuilding
|
||||
//
|
||||
AttributeValueMap AvmBuilding::getAttributeValueMap(int eventType) const
|
||||
{
|
||||
Q_UNUSED(eventType);
|
||||
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
|
||||
AttributeValueMap ret;
|
||||
auto cb = [this, &ret](const InfrastructureManagement::MainStructureElement &mse) -> void
|
||||
{
|
||||
if (mse.structureElementTypeId() != InfrastructureManagement::StructureElementType::Building)
|
||||
return;
|
||||
ret.insert(mse.id(), m_dtc->getBuildingDisplayName(mse));
|
||||
};
|
||||
m_dtc->mainStructureElements(cb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AvmBuilding::getValueStringFromValueId(int attributeValueId) const
|
||||
{
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
return m_dtc->getBuildingDisplayName(attributeValueId);
|
||||
}
|
||||
|
||||
//
|
||||
// AvmStreamName
|
||||
//
|
||||
AvmStreamName::AvmStreamName(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc)
|
||||
: m_dtc(dtc)
|
||||
, m_snm(AudioVideoManagement::StreamNameMapping::create(m_dtc.get()))
|
||||
{}
|
||||
|
||||
AvmStreamName::~AvmStreamName() = default;
|
||||
|
||||
AttributeValueMap AvmStreamName::getAttributeValueMap(int eventType) const
|
||||
{
|
||||
AttributeValueMap ret;
|
||||
|
||||
if (!m_dtc)
|
||||
return ret;
|
||||
|
||||
switch (eventType)
|
||||
{
|
||||
case ProjectDataManagement::EventType::RadioCnr:
|
||||
{
|
||||
auto cb = [&ret](const AudioVideoManagement::CnrConfig &cnrConfig) -> void
|
||||
{
|
||||
ret.insert(cnrConfig.id(), QString::fromStdString(cnrConfig.radioCircuit()));
|
||||
};
|
||||
m_dtc->cnrConfigs(cb);
|
||||
break;
|
||||
}
|
||||
case ProjectDataManagement::EventType::RadioTvc:
|
||||
{
|
||||
auto cb = [&ret](const AudioVideoManagement::TvcConfig &tvcConfig) -> void
|
||||
{
|
||||
ret.insert(tvcConfig.id(), QString::fromStdString(tvcConfig.radioCircuit()));
|
||||
};
|
||||
m_dtc->tvcConfigs(cb);
|
||||
break;
|
||||
}
|
||||
case ProjectDataManagement::EventType::CameraVideo:
|
||||
{
|
||||
auto cb = [this, &ret](const AudioVideoManagement::Stream &stream) -> void
|
||||
{
|
||||
if (stream.mountingPointId() == 0 ||
|
||||
stream.type() != AudioVideoManagement::StreamType::Video)
|
||||
return;
|
||||
ret.insert(stream.id(), m_snm->displayName(stream.mountingPointId()));
|
||||
};
|
||||
m_dtc->streams(cb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AvmStreamName::getValueStringFromValueId(int attributeValueId) const
|
||||
{
|
||||
if (!m_dtc)
|
||||
return {};
|
||||
return QString::fromStdString(m_dtc->stream(attributeValueId).name());
|
||||
}
|
||||
|
||||
|
||||
} // namespace Timeline
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Helper classes to retrieve attribute values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Christian Ehrlicher, NLE, 2020-02-07
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class StreamNameMapping;
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
namespace OperatorManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
namespace ProjectDataManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
using AttributeValueMap = QMap<int, QString>;
|
||||
using AtributeValueLookupMap = QMap<QString, AttributeValueMap>;
|
||||
|
||||
class AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
virtual ~AttributeValueLookupProvider() = default;
|
||||
virtual AttributeValueMap getAttributeValueMap(int eventType) const = 0;
|
||||
virtual QString getValueStringFromValueId(int attributeValueId) const = 0;
|
||||
};
|
||||
|
||||
class AvmChargeType final : public AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
explicit AvmChargeType(const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
|
||||
AttributeValueMap getAttributeValueMap(int eventType) const override;
|
||||
QString getValueStringFromValueId(int attributeValueId) const override;
|
||||
private:
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_dtc;
|
||||
};
|
||||
|
||||
class AvmGearType final : public AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
explicit AvmGearType(const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
|
||||
AttributeValueMap getAttributeValueMap(int eventType) const override;
|
||||
QString getValueStringFromValueId(int attributeValueId) const override;
|
||||
private:
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_dtc;
|
||||
};
|
||||
|
||||
class AvmParty final : public AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
explicit AvmParty(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
|
||||
AttributeValueMap getAttributeValueMap(int eventType) const override;
|
||||
QString getValueStringFromValueId(int attributeValueId) const override;
|
||||
private:
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
|
||||
};
|
||||
|
||||
class AvmEquipmentNumber final : public AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
explicit AvmEquipmentNumber(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
|
||||
AttributeValueMap getAttributeValueMap(int eventType) const override;
|
||||
QString getValueStringFromValueId(int attributeValueId) const override;
|
||||
private:
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
|
||||
};
|
||||
|
||||
class AvmOperator final : public AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
explicit AvmOperator(const std::shared_ptr<OperatorManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
|
||||
AttributeValueMap getAttributeValueMap(int eventType) const override;
|
||||
QString getValueStringFromValueId(int attributeValueId) const override;
|
||||
private:
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> m_dtc;
|
||||
};
|
||||
|
||||
class AvmBuilding final : public AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
explicit AvmBuilding(const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
|
||||
AttributeValueMap getAttributeValueMap(int eventType) const override;
|
||||
QString getValueStringFromValueId(int attributeValueId) const override;
|
||||
private:
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_dtc;
|
||||
};
|
||||
|
||||
class AvmStreamName final : public AttributeValueLookupProvider
|
||||
{
|
||||
public:
|
||||
explicit AvmStreamName(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc);
|
||||
~AvmStreamName();
|
||||
AttributeValueMap getAttributeValueMap(int eventType) const override;
|
||||
QString getValueStringFromValueId(int attributeValueId) const override;
|
||||
private:
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_dtc;
|
||||
std::shared_ptr<AudioVideoManagement::StreamNameMapping> m_snm;
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
Executable
+928
@@ -0,0 +1,928 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Model to handle datail data for the different event types
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-09-04
|
||||
*/
|
||||
|
||||
#include "detail_data.h"
|
||||
#include "logger.h"
|
||||
#include "tln_legend.h"
|
||||
#include "attribute_value_lookup.h"
|
||||
|
||||
#include <LtsTimelineClassic/Event.h>
|
||||
#include <LtsWidgets/lts_date_time_edit.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
|
||||
// Dtc lookups: (data ifc libs)
|
||||
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
|
||||
#include <Plugins/MarkerManagement/mrk_data_plugin_interface.h>
|
||||
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
|
||||
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
|
||||
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
|
||||
|
||||
|
||||
// Enums only: (svc libs only)
|
||||
#include <Services/ExerciseEventManagement/eem_enums.hpp>
|
||||
#include <Services/ExerciseEventManagement/eem_translation.h>
|
||||
#include <Services/ProjectDataManagement/pdm_translation.h>
|
||||
#include <Services/AreaEffectSimulation/aes_translation.h>
|
||||
#include <Services/MarkerManagement/mrk_translation.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
static inline QString removeSpaces(const QString &str)
|
||||
{
|
||||
// no QString::erase(it) available...
|
||||
QString ret;
|
||||
ret.reserve(str.size());
|
||||
for (const QChar c : str)
|
||||
{
|
||||
if (!c.isSpace())
|
||||
ret += c;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
DetailData::DetailData(LtsSession::LtsSession *session, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_session(session)
|
||||
, __already_populated__(false)
|
||||
, m_logger(getLogger("DetailData"))
|
||||
{
|
||||
populate();
|
||||
}
|
||||
|
||||
void DetailData::addRedirectedAttributeType(const QString &newAttributeTypeId, const QString &attributeText, const QString &redirectToAttributeTypeId)
|
||||
{
|
||||
attributeTypeLookup.addAttributeText(newAttributeTypeId, attributeText);
|
||||
attributeRedirectionLookup.addRedirection(newAttributeTypeId, redirectToAttributeTypeId);
|
||||
}
|
||||
|
||||
|
||||
void DetailData::addAttributeType(const QString &attributeTypeId, const QString &attributeText, const int uiTypeId, const int interpreterTypeId)
|
||||
{
|
||||
attributeTypeLookup.addAttributeText(attributeTypeId, attributeText);
|
||||
attributeUITypeLookup.addUITypeToAttribute(attributeTypeId, uiTypeId);
|
||||
attributeInterpreterLookup.addInterpreterTypeToAttribute(attributeTypeId, interpreterTypeId);
|
||||
}
|
||||
|
||||
|
||||
void DetailData::addEventType(int eventTypeId, const QString &eventTypeString) // with default attribute types [time, etc.]
|
||||
{
|
||||
eventTypeLookup.addEventType(eventTypeId, eventTypeString);
|
||||
attributeEventLookup.addAttributesToEvent(eventTypeId, {QStringLiteral("TimeRange")});
|
||||
}
|
||||
|
||||
|
||||
void DetailData::addEventType(const ProjectDataManagement::EventType &eventType) // with default attribute types [time, etc.]
|
||||
{
|
||||
addEventType(eventType.underlying(), ProjectDataManagement::toString(eventType));
|
||||
}
|
||||
|
||||
|
||||
void DetailData::populate() // call on any retranslate
|
||||
{
|
||||
if (__already_populated__) // TODO: repopulate!!
|
||||
return;
|
||||
__already_populated__ = true;
|
||||
|
||||
|
||||
|
||||
// TODO: clear all lookups !
|
||||
|
||||
// populate Event Types - see build/Lts/Services/ExerciseEventManagement/eem_enums.hpp
|
||||
// * retrieved as of 2017-09-01
|
||||
|
||||
addEventType(0, tr("General")); // would be type 'unknown' in EventType_def DE: "Allgemein"
|
||||
|
||||
addEventType(markerTypeId, tr("Marker"));
|
||||
attributeEventLookup.addAttributesToEvent(markerTypeId, {QStringLiteral("MarkerName"),
|
||||
QStringLiteral("MarkerNote"),
|
||||
QStringLiteral("Operator"),
|
||||
QStringLiteral("MarkerOffset"),
|
||||
QStringLiteral("IsSituationType"),
|
||||
QStringLiteral("IsVideoType"),
|
||||
QStringLiteral("IsAudioType")});
|
||||
|
||||
|
||||
using namespace ProjectDataManagement;
|
||||
const auto possibleEventTypes = TimelineLegendDialog::possibleEvents();
|
||||
for (const auto eventType : possibleEventTypes)
|
||||
{
|
||||
switch (eventType.underlying())
|
||||
{
|
||||
case EventType::Hit:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("VulnerabilityState"),
|
||||
QStringLiteral("OriginatorChargeTypeId"),
|
||||
QStringLiteral("FriendlyFire"),
|
||||
//QStringLiteral("OriginatorId"), // TODO: kann ich nix mit anfangen..
|
||||
//QStringLiteral("OriginatorType"), // not really useful - see EEM HandlerDynamicParticipantData::tryCreateHitEvent()
|
||||
QStringLiteral("OriginatorEquipmentNumber")});
|
||||
break;
|
||||
case EventType::BiteMessage:
|
||||
break;
|
||||
case EventType::WeaponAssignment:
|
||||
case EventType::FireEvent:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {//<< QStringLiteral("GearId"), // is a unique serial number not known to excon operator
|
||||
QStringLiteral("GearTypeId"),
|
||||
QStringLiteral("ChargeTypeId")});
|
||||
break;
|
||||
case EventType::HitBuilding:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesType"),
|
||||
QStringLiteral("ChargeTypeId"),
|
||||
QStringLiteral("OriginatorEquipmentNumber"),
|
||||
QStringLiteral("MainStructureElementId"),
|
||||
QStringLiteral("VulnerabilityState"),
|
||||
QStringLiteral("damagePercent"), // range
|
||||
//QStringLiteral("damagePercentOld"),
|
||||
}); // range
|
||||
break;
|
||||
case EventType::Manipulation:
|
||||
break;
|
||||
case EventType::Sanitation:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("Vitality"),
|
||||
QStringLiteral("SanitationProceduresNeeded"),
|
||||
QStringLiteral("SanitationProceduresTaken")});
|
||||
break;
|
||||
case EventType::CameraVideo:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("PartyId"),
|
||||
QStringLiteral("MainStructureElementId"),
|
||||
QStringLiteral("duration"),
|
||||
QStringLiteral("streamName")});
|
||||
break;
|
||||
case EventType::RadioCnr:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("PartyId"),
|
||||
QStringLiteral("duration"),
|
||||
QStringLiteral("streamName")});
|
||||
break;
|
||||
case EventType::RadioTvc:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("duration"),
|
||||
QStringLiteral("streamName")});
|
||||
|
||||
break;
|
||||
case EventType::HitEffectSimulation:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesType"),
|
||||
QStringLiteral("AesName"),
|
||||
QStringLiteral("OriginatorChargeTypeId")});
|
||||
break;
|
||||
case EventType::HitC:
|
||||
case EventType::HitB:
|
||||
case EventType::HitMine:
|
||||
case EventType::EnterMineArea:
|
||||
case EventType::LeaveMineArea:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"),
|
||||
QStringLiteral("OriginatorChargeTypeId")});
|
||||
break;
|
||||
case EventType::HitN:
|
||||
case EventType::HitGasPipe:
|
||||
case EventType::EnterDangerArea:
|
||||
case EventType::LeaveDangerArea:
|
||||
case EventType::CrossLocalBorderline:
|
||||
case EventType::CrossGlobalBorderline:
|
||||
case EventType::EnterFunctionalArea:
|
||||
case EventType::LeaveFunctionalArea:
|
||||
case EventType::EnterNuclear:
|
||||
case EventType::LeaveNuclear:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName")});
|
||||
break;
|
||||
case EventType::Borderline:
|
||||
case EventType::NContamination:
|
||||
case EventType::DangerArea:
|
||||
case EventType::FunctionalArea:
|
||||
case EventType::MineCorridor:
|
||||
case ProjectDataManagement::EventType::GasPipe:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"),
|
||||
QStringLiteral("duration")});
|
||||
break;
|
||||
case EventType::MineArea:
|
||||
case EventType::BCContamination:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"),
|
||||
QStringLiteral("duration"),
|
||||
QStringLiteral("ChargeTypeId")});
|
||||
break;
|
||||
case EventType::Unknown:
|
||||
case EventType::FriendlyFire:
|
||||
case EventType::TechnicalArea:
|
||||
case EventType::EquipmentErrorReport:
|
||||
case EventType::EmergencyCall:
|
||||
Q_ASSERT(false);
|
||||
continue;
|
||||
}
|
||||
addEventType(eventType);
|
||||
}
|
||||
|
||||
// populate Attribute Types - see /home/ref/TDS/src/Lts/Services/ExerciseEventManagement/eem_service.xml:52
|
||||
/*
|
||||
* retrieved as of 2017-09-04
|
||||
*
|
||||
*
|
||||
* FireEvent:
|
||||
* GearId
|
||||
* GearTypeId
|
||||
* ChargeTypeId
|
||||
* Remain
|
||||
*
|
||||
* WeaponAssignment:
|
||||
* GearId
|
||||
* GearTypeId
|
||||
* DryFire
|
||||
*
|
||||
* Manipulation: => show bite window
|
||||
* DeviceType
|
||||
* BiteMessage
|
||||
* BatteryState
|
||||
* BiteState
|
||||
* ConfigState
|
||||
* JsonArray BiteErrors:
|
||||
* ErrorNo
|
||||
* CanDeviceNumber
|
||||
* SubDeviceNumber
|
||||
* UniqueId
|
||||
*
|
||||
* HitBuilding:
|
||||
* ChargetTypeId
|
||||
* damagePercent
|
||||
* damagePercentOld
|
||||
* AesId
|
||||
* VunerabilityState
|
||||
* OriginatorParticipantId
|
||||
* MainStructureElementId
|
||||
*
|
||||
*
|
||||
* >>> Ab hier bin ich mir nicht mehr Sicher, was genau im Comment gemeint ist...
|
||||
* HitIndrect:
|
||||
* HitMine:
|
||||
* HitN:
|
||||
* HitC:
|
||||
* EnterDangerArea:
|
||||
* LeaveDangerArea:
|
||||
* CES:
|
||||
* AesId
|
||||
* FriendlyFire
|
||||
*/
|
||||
|
||||
/* Jedes Attribute benoetigt einen Interpreter Typen. Ein Interpreter Typ sagt dem Interpreter, wie er den Wert eines Attributs auf den Filter anwenden kann. Hier als Beispiel:
|
||||
* "OriginatorChargeTypeId" ist ein Attribut, welches bloß eine Value ID zurueckgibt. D.h. id:9000 (wird dann später einem lesbaren Wert zugeordnet: z.B: "30mm Irgendwas")
|
||||
* SOll der Wert im Filter also verglichen werden, muessen hier die IDs verglichen werden. Id 9000 => Id 9000.
|
||||
* Hier ist also folgender Interpreter korrekt: INTERPRETER_TYPE_ID_COMPARE
|
||||
*
|
||||
* Anderes Beispiel:
|
||||
* Zeit. Wird als Filter eine Zeit zwischen X und Y angegeben, muss geschaut werden, ob die Zeit Z sich zwischen X und Y befindet. Mit "INTERPRETER_TYPE_ID_COMPARE" wuerde das
|
||||
* nicht funktionieren, da sonst nur EINE Zeit (naemlich genau Zeitpunkt Z) beim Interpreter korrekt ist. Fuer diesen Fall gibt es "INTERPRETER_TYPE_RANGE".
|
||||
* Dieser Interpreter prueft, ob etwas in der Range zwischen X und Y ist.
|
||||
*/
|
||||
|
||||
// AttributeUiTypeLookup: Wie wird das Attribut angezeigt? Bei einer Liste aus Einträgen: COmboBox, oder wenn z.B. es nur 2 Zustände gib: FriendlyFire => Yes / No => CheckBox
|
||||
|
||||
addAttributeType(QStringLiteral("TimeRange"), tr("Time range:"), ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET /* TODO: none! */, INTERPRETER_TYPE_TIME); // is added in getDetailData as dummy so that the filter has a value to filter with TimeRange
|
||||
|
||||
|
||||
// Vulnerability State:
|
||||
addAttributeType(QStringLiteral("VulnerabilityState"), tr("Vulnerability State:"));
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::CombatReady);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::LightDamage);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::MediumDamage);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::HeavyDamage);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::MobilityKill);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::VisibleMobilityKill);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::WeaponSystemDamage);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::VisibleWeaponSystemDamage);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::CatastrophicKill);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::TemporarySeverance);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::NearMiss);
|
||||
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::HitWithNoEffect);
|
||||
//addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::NotReady);
|
||||
|
||||
|
||||
// Marker Types:
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("IsSituationType"), tr("Is situation type:"));
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("IsVideoType"), tr("Is video type:"));
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("IsAudioType"), tr("Is audio type:"));
|
||||
|
||||
|
||||
// AES Types:
|
||||
// addRedirectedAttributeType(QStringLiteral("AesId"), tr("Aes Type:"), QStringLiteral("AesType")); // because the result type is Aes Type (but has to be resolved by looking at the AES behind the AesId
|
||||
addAttributeType(QStringLiteral("AesType"), tr("Aes Type:"));
|
||||
|
||||
//addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtUnknown);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtNContamination);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtBCContamination);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionArea);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionSingle);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineArea);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtDangerArea);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtFunctionalArea);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineCorridor);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtBorderline);
|
||||
//addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtTechnicalArea);
|
||||
//addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionAreaSingleExplosions);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineAreaSingleMines);
|
||||
|
||||
|
||||
// Friendly Fire
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("FriendlyFire"), tr("Friendly Fire:"));
|
||||
|
||||
// Attribute: Dry Fire
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("DryFire"), tr("Dry Fire:"));
|
||||
|
||||
|
||||
|
||||
|
||||
// non-filterables:
|
||||
addAttributeType(QStringLiteral("MarkerName"), tr("Name:"), ATTRIBUTE_UI_TYPE_CHECKBOX /* TODO: FIXME: none! */, INTERPRETER_TYPE_NONE);
|
||||
addAttributeType(QStringLiteral("MarkerNote"), tr("Note:"), ATTRIBUTE_UI_TYPE_CHECKBOX /* TODO: FIXME: none! */, INTERPRETER_TYPE_NONE);
|
||||
|
||||
|
||||
// TODO:
|
||||
//(QStringLiteral("Remain"), tr("Remain:")); was ist "remain" ?
|
||||
|
||||
|
||||
// Marker offset:
|
||||
addAttributeType(QStringLiteral("MarkerOffset"), tr("Offset [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - x */, INTERPRETER_TYPE_RANGE);
|
||||
{
|
||||
DetailData::AttributeParameterLookup::ParameterMap pm;
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue<unsigned int>(0));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue<unsigned int>(9999999));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue<QString>(QString()));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue<QString>(QString()));
|
||||
attributeParameterLookup.addParameter(QStringLiteral("MarkerOffset"), pm);
|
||||
}
|
||||
|
||||
|
||||
// Duration:
|
||||
addAttributeType(QStringLiteral("duration"), tr("Duration [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - x */, INTERPRETER_TYPE_RANGE);
|
||||
{
|
||||
DetailData::AttributeParameterLookup::ParameterMap pm;
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue<unsigned int>(0));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue<unsigned int>(99999999));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue<QString>(QString()));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue<QString>(QString()));
|
||||
attributeParameterLookup.addParameter(QStringLiteral("duration"), pm);
|
||||
}
|
||||
|
||||
|
||||
// Damage:
|
||||
addAttributeType(QStringLiteral("damagePercent"), tr("Damage [%]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - 100 */, INTERPRETER_TYPE_RANGE);
|
||||
addRedirectedAttributeType(QStringLiteral("damagePercentOld"), tr("Damage before [%]:"), QStringLiteral("damagePercent"));
|
||||
|
||||
{
|
||||
DetailData::AttributeParameterLookup::ParameterMap pm;
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue<unsigned int>(0));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue<unsigned int>(100));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue<QString>(tr(" %")));
|
||||
pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue<QString>(QString()));
|
||||
attributeParameterLookup.addParameter(QStringLiteral("damagePercent"), pm); // only for filters (event filter), so only filtereable attributes like MUNITION_LEFT_BETWEEN (not MUNITION_LEFT!)
|
||||
}
|
||||
|
||||
// Equipment Numbers: (Achtung! Uebersetzt nur direkt eqid zu eqid !)
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> dtcPpm;
|
||||
m_session->getDtc<ParticipantManagement::DataInterface>(dtcPpm);
|
||||
addAttributeType(QStringLiteral("EquipmentNumber"), tr("Equip. No.:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("EquipmentNumber"), new AvmEquipmentNumber(dtcPpm));
|
||||
addRedirectedAttributeType(QStringLiteral("OriginatorEquipmentNumber"), tr("Equip. No. of Originator:"), QStringLiteral("EquipmentNumber"));
|
||||
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> dtcPdm;
|
||||
m_session->getDtc<ProjectDataManagement::DataInterface>(dtcPdm);
|
||||
// Charge Types:
|
||||
addAttributeType(QStringLiteral("ChargeTypeId"), tr("Charge Type:")); // Achtung: OriginatorChargeTypeId wird auf den Generellen Typ "ChargeTypeId" weitergeleitet, daher muss nur der Interpreter Type des Haupt-Typen gesetzt werden!
|
||||
addRedirectedAttributeType(QStringLiteral("OriginatorChargeTypeId"), tr("Originator Charge Type:"), QStringLiteral("ChargeTypeId"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("ChargeTypeId"), new AvmChargeType(dtcPdm));
|
||||
|
||||
// Gear Types:
|
||||
addAttributeType(QStringLiteral("GearTypeId"), tr("Gear Type:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("GearTypeId"), new AvmGearType(dtcPdm));
|
||||
|
||||
// Originator Types:
|
||||
addAttributeType(QStringLiteral("OriginatorType"), tr("Originator Type:"));
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Unknown);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Participant);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ObserverController);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ExerciseControl);
|
||||
//addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::WoundTreatmentDevice);
|
||||
//addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::MaintainanceDevice);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::FunctionalArea);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Initialization);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice);
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::DusMine);
|
||||
const bool showPvSan = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("ParticipantInformation"),
|
||||
QStringLiteral("HasPvSan"));
|
||||
if (showPvSan)
|
||||
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Sanitation);
|
||||
|
||||
|
||||
// (ISM) Structure Elements:
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> dtcIsm;
|
||||
m_session->getDtc<InfrastructureManagement::DataInterface>(dtcIsm);
|
||||
addAttributeType(QStringLiteral("MainStructureElementId"), tr("Building:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("MainStructureElementId"), new AvmBuilding(dtcIsm));
|
||||
|
||||
// (PPM) Parties
|
||||
addAttributeType(QStringLiteral("PartyId"), tr("Party:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("PartyId"), new AvmParty(dtcPpm));
|
||||
|
||||
// (OPM) Operator Management:
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> dtcOpm;
|
||||
m_session->getDtc<OperatorManagement::DataInterface>(dtcOpm);
|
||||
addAttributeType(QStringLiteral("Operator"), tr("Operator:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("Operator"), new AvmOperator(dtcOpm));
|
||||
|
||||
|
||||
// (AVM) Streams
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> dtcAvm;
|
||||
m_session->getDtc<AudioVideoManagement::DataInterface>(dtcAvm);
|
||||
addAttributeType(QStringLiteral("streamName"), tr("Stream Name:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("streamName"), new AvmStreamName(dtcAvm));
|
||||
}
|
||||
|
||||
DetailData::GetDetailDataResultList DetailData::getDetailData(const LtsTimelineClassic::Event *event)
|
||||
{
|
||||
GetDetailDataResultList result;
|
||||
|
||||
if (event->detailData().isEmpty()) // no detail data so search in
|
||||
return result;
|
||||
|
||||
const QJsonObject &root = event->detailData();
|
||||
for (auto i = root.constBegin(); i != root.constEnd(); ++i)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Adding Detail Data for: " << i.key();
|
||||
result.append(getDetailDataForAttribute(i.key(), *i));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DetailData::GetDetailDataForAttributeResult DetailData::getDetailDataForAttribute(const LtsTimelineClassic::Event *event, const QString &attributeType)
|
||||
{
|
||||
GetDetailDataForAttributeResult result;
|
||||
|
||||
const QJsonObject &root = event->detailData();
|
||||
root[QStringLiteral("TimeRange")] = event->startTime() / 1000 /* as value would be too big for int => see getDetailDataForAttribute(..) */; // event time as temporary detail data
|
||||
root[QStringLiteral("PartyId")] = event->partyId();
|
||||
|
||||
const QJsonValue attribute = root[attributeType];
|
||||
|
||||
if (attribute.isNull() || attribute.isUndefined())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "DetailData::getDetailDataForAttribute: no attribute type " << attributeType
|
||||
<< " in " << QJsonDocument(root).toJson();
|
||||
|
||||
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
|
||||
return result;
|
||||
}
|
||||
|
||||
return getDetailDataForAttribute(attributeType, attribute);
|
||||
}
|
||||
|
||||
|
||||
DetailData::GetDetailDataForAttributeResult DetailData::getDetailDataForAttribute(const QString &attributeType, const QJsonValue &attributeValueJson)
|
||||
{
|
||||
GetDetailDataForAttributeResult result;
|
||||
result.attributeTypeId = attributeType;
|
||||
result.attributeValueId = -1;
|
||||
result.requestResult = DetailData::RequestResult::Error;
|
||||
QString attributeTypeTranslated = attributeTypeLookup.getAttributeText(attributeType);
|
||||
|
||||
if (attributeTypeTranslated.isEmpty())
|
||||
{
|
||||
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
|
||||
//ERROR_LOG(m_logger) << "getDetailDataForAttribute: Invalid Attribute Type for " << attributeType;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.attributeType = attributeTypeTranslated;
|
||||
|
||||
int attributeValueId = -1;
|
||||
|
||||
/*
|
||||
enum Type
|
||||
{
|
||||
Null = 0x0,
|
||||
Bool = 0x1,
|
||||
Double = 0x2,
|
||||
String = 0x3,
|
||||
Array = 0x4,
|
||||
Object = 0x5,
|
||||
Undefined = 0x80
|
||||
};
|
||||
*/
|
||||
|
||||
switch (attributeValueJson.type())
|
||||
{
|
||||
// sorted by frequency of occurrence
|
||||
case QJsonValue::Double:
|
||||
{
|
||||
attributeValueId = attributeValueJson.toInt(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
case QJsonValue::Null:
|
||||
case QJsonValue::Undefined:
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Timeline: DetailData::getDetailDataForAttribute: attribute value is null or undefined! " << attributeValueJson.toString();
|
||||
result.requestResult = DetailData::RequestResult::InvalidAttributeTypeJson;
|
||||
return result;
|
||||
}
|
||||
|
||||
case QJsonValue::Bool:
|
||||
{
|
||||
attributeValueId = attributeValueJson.toBool() ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case QJsonValue::String:
|
||||
{
|
||||
bool k = false;
|
||||
QString attributeValueString = attributeValueJson.toString();
|
||||
|
||||
if (attributeValueString.isEmpty())
|
||||
{
|
||||
attributeValueId = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
attributeValueId = attributeValueString.toInt(&k);
|
||||
|
||||
if (!k) // not a number but treat as text... NOTE: has no id
|
||||
{
|
||||
result.attributeValue = attributeValueString;
|
||||
result.requestResult = DetailData::RequestResult::Okay;
|
||||
return result;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Timeline: DetailData::getDetailDataForAttribute: attribute value cannot be handled. Type " << attributeValueJson.type() << attributeValueJson.toString();
|
||||
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (attributeValueId == -1)
|
||||
{
|
||||
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.attributeValueId = attributeValueId;
|
||||
|
||||
|
||||
// there are values that do not have to be translated:
|
||||
int attributeUiType = attributeUITypeLookup.getUIType(attributeType);
|
||||
switch (attributeUiType)
|
||||
{
|
||||
// do not translate
|
||||
case ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET:
|
||||
case ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET:
|
||||
case ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET:
|
||||
case ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET:
|
||||
{
|
||||
result.attributeValue = QString::number(attributeValueId); // use "id" as "translated" string
|
||||
result.requestResult = DetailData::RequestResult::Okay;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// translate
|
||||
case ATTRIBUTE_UI_TYPE_COMBO_BOX:
|
||||
case ATTRIBUTE_UI_TYPE_CHECKBOX:
|
||||
{
|
||||
result.attributeValue = attributeValueLookup.getValueStringFromValueId(attributeType, attributeValueId);
|
||||
if (result.attributeValue.isEmpty())
|
||||
result.attributeValue = m_attributeValueLookupDtc.getValueStringFromValueId(attributeType, attributeValueId);
|
||||
result.requestResult = DetailData::RequestResult::Okay;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default: // -1
|
||||
{
|
||||
// maybe the type was redirected?
|
||||
QString concreteAttributeType = attributeRedirectionLookup.getRedirection(attributeType);
|
||||
|
||||
if (concreteAttributeType == attributeType) // it was not redirected - give up!
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getDetailDataForAttribute: attribute type " << attributeType << " does not have an UiType !!!";
|
||||
result.requestResult = DetailData::RequestResult::NoUiTypeForAttribute;
|
||||
}
|
||||
else // there is a redirection, try this method with the redirection
|
||||
{
|
||||
//qWarning() << "trying redirection for attribute type" << attributeType;
|
||||
|
||||
// save some results, as getDetailDataForAttribute will set ALL the results for the redirection, instead of ONLY the value..
|
||||
QString attributeType = result.attributeType;
|
||||
QString attributeTypeId = result.attributeTypeId;
|
||||
|
||||
result = getDetailDataForAttribute(concreteAttributeType, attributeValueJson);
|
||||
|
||||
result.attributeType = attributeType;
|
||||
result.attributeTypeId = attributeTypeId;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void DetailData::createRetrieveCurrentTimeCallback(LtsWidgets::LtsDateTimeEdit *dateTimeEdit)
|
||||
{
|
||||
dateTimeEdit->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); });
|
||||
}
|
||||
|
||||
|
||||
// LOOKUP BASE
|
||||
DetailData::LookupBase::LookupBase(const QString &lookupClassName)
|
||||
: m_lookupClassName(lookupClassName)
|
||||
, m_logger(getLogger(QStringLiteral("DetailData.") + lookupClassName))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// EVENT TYPE LOOKUP
|
||||
DetailData::EventTypeLookup::EventTypeLookup()
|
||||
: LookupBase(QStringLiteral("EventTypeLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::EventTypeLookup::addEventType(const int key, const QString &value)
|
||||
{
|
||||
m_eventTypeMap.insert(key, value);
|
||||
}
|
||||
|
||||
int DetailData::EventTypeLookup::getEventType(const QString &eventText) const
|
||||
{
|
||||
// as eventText is simplified, method 'key' would not work
|
||||
|
||||
const QString paramText = removeSpaces(eventText);
|
||||
for (auto i = m_eventTypeMap.constBegin(); i != m_eventTypeMap.constEnd(); ++i)
|
||||
{
|
||||
const QString mapText = removeSpaces(i.value());
|
||||
if (mapText == paramText)
|
||||
return i.key();
|
||||
}
|
||||
|
||||
return -1; // -1 = invalid !
|
||||
}
|
||||
|
||||
QString DetailData::EventTypeLookup::getEventText(const int eventType) const
|
||||
{
|
||||
return m_eventTypeMap.value(eventType);
|
||||
}
|
||||
|
||||
bool DetailData::EventTypeLookup::isEventExists(const int eventType) const
|
||||
{
|
||||
return m_eventTypeMap.contains(eventType);
|
||||
}
|
||||
|
||||
QStringList DetailData::EventTypeLookup::getEventTexts() const
|
||||
{
|
||||
return m_eventTypeMap.values();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE EVENT LOOKUP
|
||||
DetailData::AttributeEventLookup::AttributeEventLookup()
|
||||
: LookupBase(QStringLiteral("AttributeEventLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::AttributeEventLookup::addAttributesToEvent(const int eventType, const AttributeList &attributeTypeList)
|
||||
{
|
||||
AttributeList &al = m_attributeEventLookupMap[eventType];
|
||||
al += attributeTypeList;
|
||||
}
|
||||
|
||||
void DetailData::AttributeEventLookup::addAttributesToEvent(const ProjectDataManagement::EventType &eventType, const AttributeList &attributeTypeList)
|
||||
{
|
||||
addAttributesToEvent(eventType.underlying(), attributeTypeList);
|
||||
}
|
||||
|
||||
bool DetailData::AttributeEventLookup::isAttributeInEvent(const int eventType, const QString &attributeType)
|
||||
{
|
||||
auto eventTypeIt = m_attributeEventLookupMap.constFind(eventType);
|
||||
|
||||
if (eventTypeIt == m_attributeEventLookupMap.constEnd())
|
||||
return false; // event does not even exist
|
||||
|
||||
const AttributeList &attributeList = *eventTypeIt;
|
||||
|
||||
if (attributeList.contains(attributeType))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DetailData::AttributeEventLookup::AttributeList DetailData::AttributeEventLookup::getEventsAttributeList(const int eventType) const // get all attribute types from the event
|
||||
{
|
||||
return m_attributeEventLookupMap.value(eventType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE TEXT LOOKUP
|
||||
DetailData::AttributeTypeLookup::AttributeTypeLookup()
|
||||
: LookupBase(QStringLiteral("AttributeTypeLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::AttributeTypeLookup::addAttributeText(const QString &attributeType, const QString &attributeText)
|
||||
{
|
||||
m_attributeTypeLookupMap.insert(attributeType, attributeText);
|
||||
}
|
||||
|
||||
QString DetailData::AttributeTypeLookup::getAttributeType(const QString &attributeText) const
|
||||
{
|
||||
const QString paramText = removeSpaces(attributeText);
|
||||
// as eventText is simplified, method 'key' would not work
|
||||
for (auto i = m_attributeTypeLookupMap.constBegin(); i != m_attributeTypeLookupMap.constEnd(); ++i)
|
||||
{
|
||||
const QString mapText = removeSpaces(i.value());
|
||||
if (mapText == paramText)
|
||||
return i.key();
|
||||
}
|
||||
|
||||
WARNING_LOG(m_logger) << "getAttributeType: attribute type not found by text '" << attributeText << "'";
|
||||
return QString(); // invalid
|
||||
}
|
||||
|
||||
DetailData::AttributeTypeLookup::AttributeTypeList DetailData::AttributeTypeLookup::getAttributeTypes() const
|
||||
{
|
||||
return m_attributeTypeLookupMap.keys();
|
||||
}
|
||||
|
||||
QString DetailData::AttributeTypeLookup::getAttributeText(const QString &attributeType, const QString &defaultReturnValue) const
|
||||
{
|
||||
return m_attributeTypeLookupMap.value(attributeType, defaultReturnValue);
|
||||
}
|
||||
|
||||
DetailData::AttributeTypeLookup::AttributeTextList DetailData::AttributeTypeLookup::getAttributeTexts() const
|
||||
{
|
||||
return m_attributeTypeLookupMap.values();
|
||||
}
|
||||
|
||||
|
||||
// ATTRIBUTE PARAMETER LOOKUP
|
||||
DetailData::AttributeParameterLookup::AttributeParameterLookup()
|
||||
: LookupBase(QStringLiteral("AttributeParameterLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::AttributeParameterLookup::addParameter(const QString &attributeType, const ParameterMap ¶meterMap)
|
||||
{
|
||||
if (!parameterMap.count())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "addParameter: parameter map is empty!";
|
||||
return;
|
||||
}
|
||||
|
||||
m_attributeParameterMap.insert(attributeType, parameterMap);
|
||||
}
|
||||
|
||||
DetailData::AttributeParameterLookup::ParameterMap DetailData::AttributeParameterLookup::getParameterMap(const QString &attributeType) const
|
||||
{
|
||||
return m_attributeParameterMap.value(attributeType);
|
||||
}
|
||||
|
||||
QVariant DetailData::AttributeParameterLookup::getParameterValue(const QString &attributeType, const int parameterType) const
|
||||
{
|
||||
const ParameterMap &pm = getParameterMap(attributeType);
|
||||
|
||||
auto pmci = pm.constFind(parameterType);
|
||||
|
||||
if (pmci == pm.constEnd()) // exists? FIXME: in NGLDAO Timeline: "!=" !!
|
||||
return QVariant();
|
||||
|
||||
return *pmci;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE UI TYPE
|
||||
DetailData::AttributeUITypeLookup::AttributeUITypeLookup()
|
||||
: LookupBase(QStringLiteral("AttributeUITypeLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::AttributeUITypeLookup::addUITypeToAttribute(const QString &attributeType, const int uiType)
|
||||
{
|
||||
m_attributeUITypeLookupMap.insert(attributeType, uiType);
|
||||
}
|
||||
|
||||
int DetailData::AttributeUITypeLookup::getUIType(const QString &attributeType) const
|
||||
{
|
||||
return m_attributeUITypeLookupMap.value(attributeType, -1); // -1 = invalid
|
||||
}
|
||||
|
||||
|
||||
// INTERPRETER LOOKUP
|
||||
DetailData::AttributeInterpreterLookup::AttributeInterpreterLookup()
|
||||
: LookupBase(QStringLiteral("AttributeInterpreterLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::AttributeInterpreterLookup::addInterpreterTypeToAttribute(const QString &attributeType, const int interpreterType)
|
||||
{
|
||||
m_attributeInterpreterLookupMap.insert(attributeType, interpreterType);
|
||||
}
|
||||
|
||||
int DetailData::AttributeInterpreterLookup::getInterpreterType(const QString &attributeType) const
|
||||
{
|
||||
return m_attributeInterpreterLookupMap.value(attributeType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE VALUE LOOKUP
|
||||
DetailData::AttributeValueLookup::AttributeValueLookup()
|
||||
: LookupBase(QStringLiteral("AttributeValueLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void DetailData::AttributeValueLookup::removeValueFromAttributeValueMap(const QString &attributeType, const int valueKey)
|
||||
{
|
||||
auto attributeTypeValueMapIt = m_attributeTypeValueMap.find(attributeType);
|
||||
|
||||
if (attributeTypeValueMapIt == m_attributeTypeValueMap.end()) // there are currently no values for this attribute type, insert all new values
|
||||
return; // attribute type not even found!
|
||||
|
||||
AttributeValueMap ¤tAttributeValueMap = *attributeTypeValueMapIt;
|
||||
currentAttributeValueMap.remove(valueKey);
|
||||
}
|
||||
|
||||
|
||||
void DetailData::AttributeValueLookup::addValueToAttributeValueMap(const QString &attributeType, const int valueKey, const QString &valueValue)
|
||||
{
|
||||
AttributeValueMap &avm = m_attributeTypeValueMap[attributeType];
|
||||
avm.insert(valueKey, valueValue);
|
||||
}
|
||||
|
||||
|
||||
void DetailData::AttributeValueLookup::addValuesToAttributeValueMap(const QString &attributeType, const AttributeValueMap &avm) // add a VALUE (consisting of id & string) to the map coresponding to the attribute type
|
||||
{
|
||||
AttributeValueMap &thisAvm = m_attributeTypeValueMap[attributeType];
|
||||
for (auto i = avm.constBegin(); i != avm.constEnd(); ++i)
|
||||
{
|
||||
thisAvm.insert(i.key(), i.value());
|
||||
}
|
||||
}
|
||||
|
||||
AttributeValueMap DetailData::AttributeValueLookup::getAttributeValueMap(const QString &attributeType) const
|
||||
{
|
||||
return m_attributeTypeValueMap.value(attributeType);
|
||||
}
|
||||
|
||||
QString DetailData::AttributeValueLookup::getValueStringFromValueId(const QString &attributeType, const int attributeValueId, const QString& defaultValue) const
|
||||
{
|
||||
return getAttributeValueMap(attributeType).value(attributeValueId, defaultValue);
|
||||
}
|
||||
|
||||
void DetailData::AttributeValueLookup::clear()
|
||||
{
|
||||
m_attributeTypeValueMap.clear();
|
||||
}
|
||||
|
||||
|
||||
// ATTRIBUTE REDIRECTION LOOKUP
|
||||
DetailData::AttributeRedirectionLookup::AttributeRedirectionLookup()
|
||||
: LookupBase(QStringLiteral("AttributeRedirectionLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::AttributeRedirectionLookup::addRedirection(const QString &attributeType, const QString &redirectTo)
|
||||
{
|
||||
m_attributeRedirectionMap.insert(attributeType, redirectTo);
|
||||
}
|
||||
|
||||
QString DetailData::AttributeRedirectionLookup::getRedirection(const QString &attributeType) const
|
||||
{
|
||||
auto it = m_attributeRedirectionMap.find(attributeType);
|
||||
if (it == m_attributeRedirectionMap.end())
|
||||
return attributeType;
|
||||
return it.value();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Timeline
|
||||
Executable
+343
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Model to handle datail data for the different event types
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-09-04
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
#include <Services/ProjectDataManagement/pdm_enums.hpp> // needed for this header
|
||||
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
|
||||
#include "attribute_value_lookup.h"
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
namespace LtsTimelineClassic
|
||||
{
|
||||
class Event;
|
||||
}
|
||||
namespace LtsWidgets
|
||||
{
|
||||
class LtsDateTimeEdit;
|
||||
}
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
constexpr int markerTypeId = 999999; // HACK: there is no marker type
|
||||
|
||||
class DetailData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class RequestResult
|
||||
{
|
||||
Error = 0,
|
||||
Okay = 1,
|
||||
InvalidAttributeType,
|
||||
NoValueTranslationForAttribute,
|
||||
NoUiTypeForAttribute,
|
||||
InvalidAttributeTypeJson,
|
||||
JsonCorrupted
|
||||
};
|
||||
|
||||
struct GetDetailDataForAttributeResult
|
||||
{
|
||||
QString attributeType; // translated! "Friendly Fire" instead of the key "FriendlyFire"
|
||||
QString attributeValue; // also translated! "No" instead of the key "0"
|
||||
|
||||
QString attributeTypeId; // "FriendlyFire" instead of the translated version "Friendly Fire"
|
||||
int attributeValueId = 0;
|
||||
RequestResult requestResult = RequestResult::Error;
|
||||
};
|
||||
|
||||
using GetDetailDataResultList = QVector<GetDetailDataForAttributeResult>;
|
||||
|
||||
enum AttributeUITypes // attribute ui types
|
||||
{
|
||||
ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET = 0,
|
||||
ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET,
|
||||
ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET,
|
||||
ATTRIBUTE_UI_TYPE_COMBO_BOX, // most attributes use this
|
||||
ATTRIBUTE_UI_TYPE_CHECKBOX,
|
||||
ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET
|
||||
};
|
||||
|
||||
enum UIParameterType
|
||||
{
|
||||
UI_PARAM_TYPE_N1,
|
||||
UI_PARAM_TYPE_N2,
|
||||
UI_PARAM_TYPE_O1,
|
||||
UI_PARAM_TYPE_O2,
|
||||
UI_PARAM_TYPE_RAD,
|
||||
|
||||
UI_PARAM_TYPE_MIN,
|
||||
UI_PARAM_TYPE_MAX,
|
||||
UI_PARAM_TYPE_PREFIX,
|
||||
UI_PARAM_TYPE_SUFFIX
|
||||
};
|
||||
|
||||
enum InterpreterTypes
|
||||
{
|
||||
INTERPRETER_TYPE_NONE = 0, // ERROR VALUE
|
||||
//INTERPRETER_TYPE_TOINT,
|
||||
INTERPRETER_TYPE_RANGE,
|
||||
INTERPRETER_TYPE_AREA, // for filter interpreter
|
||||
INTERPRETER_TYPE_ID_COMPARE, // or key compare
|
||||
INTERPRETER_TYPE_STR_COMPARE, // or value compare [deprecated - do not use]
|
||||
INTERPRETER_TYPE_POSITION, // for event info windows line edits !
|
||||
INTERPRETER_TYPE_TIME, // for event info windows line edits !
|
||||
INTERPRETER_TYPE_DURATION, // for event info windows line edits !
|
||||
INTERPRETER_TYPE_RAD
|
||||
};
|
||||
|
||||
|
||||
explicit DetailData(LtsSession::LtsSession *session, QObject *parent = nullptr);
|
||||
|
||||
void populate();
|
||||
GetDetailDataResultList getDetailData(const LtsTimelineClassic::Event *event);
|
||||
GetDetailDataForAttributeResult getDetailDataForAttribute(const LtsTimelineClassic::Event *event, const QString &attributeType);
|
||||
void createRetrieveCurrentTimeCallback(LtsWidgets::LtsDateTimeEdit *dateTimeEdit);
|
||||
LtsSession::LtsSession *session() { return m_session; }
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief addRedirectedAttributeType just like "addAttributeType", but automatically redirects to "redirectionAttributeTypeId" (note that redirected attributes do not need to have ui types or interpreter types)
|
||||
* @param attributeTypeId
|
||||
* @param attributeText
|
||||
* @param redirectionAttributeTypeId
|
||||
*/
|
||||
void addRedirectedAttributeType(const QString &newAttributeTypeId, const QString &attributeText, const QString &redirectToAttributeTypeId);
|
||||
void addAttributeType(const QString &attributeTypeId, const QString &attributeText, const int uiTypeId = ATTRIBUTE_UI_TYPE_COMBO_BOX, const int interpreterTypeId = INTERPRETER_TYPE_ID_COMPARE);
|
||||
|
||||
void addAttributeTypeWithYesAndNo(const QString &attributeTypeId, const QString &attributeText)
|
||||
{
|
||||
addAttributeType(attributeTypeId, attributeText, ATTRIBUTE_UI_TYPE_CHECKBOX);
|
||||
attributeValueLookup.addValueToAttributeValueMap(attributeTypeId, 0, tr("No"));
|
||||
attributeValueLookup.addValueToAttributeValueMap(attributeTypeId, 1, tr("Yes"));
|
||||
}
|
||||
|
||||
template <typename AttributeEnumType>
|
||||
void addAttributeValue(const QString &attributeTypeId, const AttributeEnumType &attributeEnum)
|
||||
{
|
||||
//qWarning() << "<<<" << attributeTypeId << ":" << (int)attributeEnum << "=>" << toString(attributeEnum);
|
||||
attributeValueLookup.addValueToAttributeValueMap(attributeTypeId, (int)attributeEnum, toString(attributeEnum));
|
||||
}
|
||||
|
||||
void addEventType(int eventTypeId, const QString &eventTypeString);
|
||||
void addEventType(const ProjectDataManagement::EventType &eventType);
|
||||
|
||||
GetDetailDataForAttributeResult getDetailDataForAttribute(const QString &attributeType, const QJsonValue &attributeValueJson);
|
||||
|
||||
LtsSession::LtsSession *m_session;
|
||||
bool __already_populated__; // do not allow secondary population, this would take to much time to develop atm
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
public:
|
||||
|
||||
class LookupBase
|
||||
{
|
||||
public:
|
||||
explicit LookupBase(const QString &lookupClassName);
|
||||
|
||||
protected:
|
||||
QString m_lookupClassName;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
|
||||
class EventTypeLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
using EventTypeMap = QMap<int /* eventTypeId */, QString /* Event Name */>; // example: 3, 'Hit'
|
||||
|
||||
EventTypeLookup();
|
||||
|
||||
void addEventType(const int key, const QString &value);
|
||||
int getEventType(const QString &eventText) const;
|
||||
QString getEventText(const int eventType) const;
|
||||
QStringList getEventTexts() const; // all texts
|
||||
bool isEventExists(const int eventType) const;
|
||||
|
||||
private:
|
||||
EventTypeMap m_eventTypeMap;
|
||||
};
|
||||
EventTypeLookup eventTypeLookup;
|
||||
|
||||
|
||||
class AttributeTypeLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
using AttributeTypeLookupMap = QMap<QString /* attributeTypeId */, QString /* name */>;
|
||||
using AttributeTypeList = QList<QString>;
|
||||
using AttributeTextList = QStringList;
|
||||
|
||||
AttributeTypeLookup();
|
||||
|
||||
void addAttributeText(const QString &attributeType, const QString &attributeText);
|
||||
QString getAttributeType(const QString &attributeText) const;
|
||||
AttributeTypeList getAttributeTypes() const;
|
||||
QString getAttributeText(const QString &attributeType, const QString &defaultReturnValue = QString()) const;
|
||||
AttributeTextList getAttributeTexts() const;
|
||||
|
||||
private:
|
||||
AttributeTypeLookupMap m_attributeTypeLookupMap;
|
||||
};
|
||||
AttributeTypeLookup attributeTypeLookup;
|
||||
|
||||
|
||||
class AttributeEventLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
using AttributeEventLookupMap = QMap<int /* eventTypeId */, QList<QString> /* attributeTypeId List */>;
|
||||
using AttributeList = QList<QString>;
|
||||
|
||||
AttributeEventLookup();
|
||||
|
||||
void addAttributesToEvent(const int eventType, const AttributeList &attributeTypeList);
|
||||
void addAttributesToEvent(const ProjectDataManagement::EventType &eventType, const AttributeList &attributeTypeList);
|
||||
bool isAttributeInEvent(const int eventType, const QString &attributeType);
|
||||
AttributeList getEventsAttributeList(const int eventType) const; // get all attribute types from the event
|
||||
|
||||
private:
|
||||
AttributeEventLookupMap m_attributeEventLookupMap;
|
||||
};
|
||||
AttributeEventLookup attributeEventLookup;
|
||||
|
||||
|
||||
class AttributeParameterLookup : public LookupBase // as ui type is fixed for attribute type, it is perfectly okay to request parameters (min, max, etc.) by attribute type
|
||||
{
|
||||
public:
|
||||
using ParameterMap = QMap<int, QVariant>; // Parameter Type => Parameter String
|
||||
using AttributeParameterMap = QHash<QString, ParameterMap>;
|
||||
|
||||
AttributeParameterLookup();
|
||||
|
||||
void addParameter(const QString &attributeType, const ParameterMap ¶meterMap); // add a parameter map to the lookup
|
||||
ParameterMap getParameterMap(const QString &attributeType) const;
|
||||
QVariant getParameterValue(const QString &attributeType, const int parameterType) const;
|
||||
|
||||
private:
|
||||
AttributeParameterMap m_attributeParameterMap;
|
||||
};
|
||||
AttributeParameterLookup attributeParameterLookup;
|
||||
|
||||
|
||||
class AttributeUITypeLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
using AttributeUITypeLookupMap = QHash<QString, int>;
|
||||
|
||||
AttributeUITypeLookup();
|
||||
|
||||
void addUITypeToAttribute(const QString &attributeType, const int uiType);
|
||||
int getUIType(const QString &attributeType) const;
|
||||
|
||||
private:
|
||||
AttributeUITypeLookupMap m_attributeUITypeLookupMap;
|
||||
};
|
||||
AttributeUITypeLookup attributeUITypeLookup;
|
||||
|
||||
|
||||
class AttributeInterpreterLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
using AttributeInterpreterLookupMap = QHash<QString, int>;
|
||||
|
||||
AttributeInterpreterLookup();
|
||||
|
||||
void addInterpreterTypeToAttribute(const QString &attributeType, const int interpreterType);
|
||||
int getInterpreterType(const QString &attributeType) const;
|
||||
|
||||
private:
|
||||
AttributeInterpreterLookupMap m_attributeInterpreterLookupMap;
|
||||
};
|
||||
AttributeInterpreterLookup attributeInterpreterLookup;
|
||||
|
||||
|
||||
class AttributeValueLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
AttributeValueLookup();
|
||||
|
||||
void addValueToAttributeValueMap(const QString &attributeType, const int valueKey, const QString &valueValue /* ^^ */);
|
||||
void removeValueFromAttributeValueMap(const QString &attributeType, const int valueKey);
|
||||
void addValuesToAttributeValueMap(const QString &attributeType, const AttributeValueMap &avm); // add a VALUE (consisting of id & string) to the map coresponding to the attribute type
|
||||
void clear(); // clears map for updating map and sets to uninitialized
|
||||
|
||||
AttributeValueMap getAttributeValueMap(const QString &attributeType) const;
|
||||
QString getValueStringFromValueId(const QString &attributeType, const int attributeValueId, const QString &defaultValue = QString()) const;
|
||||
|
||||
private:
|
||||
AtributeValueLookupMap m_attributeTypeValueMap; // contains a map for each attribute type, that contain a map for their keys & values
|
||||
};
|
||||
AttributeValueLookup attributeValueLookup;
|
||||
|
||||
class AttributeValueLookupDtc : public LookupBase
|
||||
{
|
||||
public:
|
||||
AttributeValueLookupDtc() : LookupBase(QStringLiteral("AttributeValueLookupDtc")) {}
|
||||
~AttributeValueLookupDtc() { qDeleteAll(m_provider); }
|
||||
|
||||
// takes ownership on provider
|
||||
void addHandlerForDtc(const QString &attributeType, AttributeValueLookupProvider *provider)
|
||||
{
|
||||
auto &p = m_provider[attributeType];
|
||||
delete p;
|
||||
p = provider;
|
||||
}
|
||||
AttributeValueMap getAttributeValueMap(int eventType, const QString &attributeType) const
|
||||
{
|
||||
const auto provider = m_provider.value(attributeType);
|
||||
if (!provider)
|
||||
return {};
|
||||
return provider->getAttributeValueMap(eventType);
|
||||
}
|
||||
QString getValueStringFromValueId(const QString &attributeType, int attributeValueId) const
|
||||
{
|
||||
const auto provider = m_provider.value(attributeType);
|
||||
if (!provider)
|
||||
return {};
|
||||
return provider->getValueStringFromValueId(attributeValueId);
|
||||
}
|
||||
private:
|
||||
QHash<QString, AttributeValueLookupProvider*> m_provider;
|
||||
};
|
||||
AttributeValueLookupDtc m_attributeValueLookupDtc;
|
||||
AttributeValueMap operatorsForEventType(int eventType) const;
|
||||
QString operatorNameFromId(int id) const;
|
||||
|
||||
class AttributeRedirectionLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
using AttributeRedirectionMap = QHash<QString, QString>;
|
||||
|
||||
explicit AttributeRedirectionLookup();
|
||||
|
||||
void addRedirection(const QString &attributeType, const QString &redirectTo);
|
||||
QString getRedirection(const QString &attributeType) const; // returns redirection, or if no redirection for attribute type, then returns original attribute type
|
||||
|
||||
private:
|
||||
AttributeRedirectionMap m_attributeRedirectionMap;
|
||||
};
|
||||
AttributeRedirectionLookup attributeRedirectionLookup;
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
Executable
+218
@@ -0,0 +1,218 @@
|
||||
#include "excon_filter.h"
|
||||
#include "detail_data.h"
|
||||
#include "EventFilter/interpreter/FilterWorker.h"
|
||||
#include "EventFilter/interpreter/FilterEquationFunctions.h"
|
||||
|
||||
#include <LtsTimelineClassic/EventList.h>
|
||||
#include <LtsTimelineClassic/Event.h>
|
||||
#include <ProjectDataManagement/pdm_enums.hpp>
|
||||
#include "logger.h"
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
//m_rootItem->getFullEventList(true, true);
|
||||
static LtsTimelineClassic::EventList applyFilter(DetailData *detailData,
|
||||
const LtsTimelineClassic::EventList &eventList,
|
||||
const ModelFilterList &modelFilterList,
|
||||
bool simulation) // returns remaining/visible events
|
||||
{
|
||||
NGL::INGLLogger &logger(getLogger("ExconFilter"));
|
||||
/*
|
||||
*
|
||||
* general event can be filtered by event's default base data (time, duration, etc.)
|
||||
* .. and can be filtered by e.g. position (if the inherit event contains a position - if not, ignore error)
|
||||
*
|
||||
*/
|
||||
|
||||
//const QSet<int> eventOnlyEventList = getEventOnlyEventList(modelFilterList);
|
||||
//EventList eventList = eventListToFilter; //m_rootItem->getFullEventList(true, true); // get all events from model's root item, recursive and all (even hidden, logically) events
|
||||
LtsTimelineClassic::EventList visibleEvents;
|
||||
|
||||
bool resetFilterOnly = false;
|
||||
|
||||
if (!modelFilterList.count()) // no filters set = no events to filter => show all events
|
||||
{
|
||||
DEBUG_LOG(logger) << "applyFilter: Model Filter List is EMPTY";
|
||||
|
||||
if (simulation) // do not return any visible event if there is NO filter (or every event will be shown which is NOT a nice feature)
|
||||
return visibleEvents;
|
||||
|
||||
resetFilterOnly = true;
|
||||
}
|
||||
|
||||
visibleEvents = eventList; // copy list of pointers (!)
|
||||
|
||||
|
||||
QSet<int> mentionedEventTypes;
|
||||
mentionedEventTypes.insert(markerTypeId); // markers are always visible!
|
||||
|
||||
for (const FilterWorker::ModelFilter &mf : modelFilterList)
|
||||
{
|
||||
if (mf.active)
|
||||
mentionedEventTypes.insert(mf.eventType);
|
||||
}
|
||||
|
||||
/* the filter must consider one of these 2 cases
|
||||
*
|
||||
* case 1: filter all events - if there is "General Event" only
|
||||
* case 2: case 1 + hide all events that are not mentioned - if there are other events than "General Event" AND the "General Event"
|
||||
*/
|
||||
|
||||
bool showAllEvents = false;
|
||||
|
||||
if (mentionedEventTypes.count() == 1 && mentionedEventTypes.contains(0 /* GENERAL_EVENT */))
|
||||
showAllEvents = true;
|
||||
|
||||
|
||||
// PER ATTRIBUTE THERE MUST BE AT LEAST ONE FITTING VALUE ! (or)
|
||||
for (LtsTimelineClassic::Event *event : eventList) // go through all events in model
|
||||
{
|
||||
if (!event)
|
||||
{
|
||||
WARNING_LOG(logger) << "applyFilter: Erroneous event!";
|
||||
continue; // next event, we can't handle this event
|
||||
}
|
||||
|
||||
int eventType = event->typeId();
|
||||
//int eventID = event->getID();
|
||||
|
||||
if (resetFilterOnly /*|| eventOnlyEventList.contains(eventType)*/) // reset filter or show entire event type when event type is event-type-filter (& search eoe list for current events event type)
|
||||
{
|
||||
if (!simulation)
|
||||
event->show();
|
||||
|
||||
// no inc / dec needed for vec here !
|
||||
|
||||
continue; // do not filter further - done!
|
||||
}
|
||||
|
||||
bool eventVisible = true;
|
||||
|
||||
// check if event must be filtered (mentioned in model filter list)
|
||||
if (!showAllEvents && !mentionedEventTypes.contains(eventType))
|
||||
eventVisible = false;
|
||||
|
||||
if (!eventVisible /*&& m_showOnlyThese*/) // TODO: settings for "SHOW ALL BUT FILTER ONLY THESE" and "SHOW ONLY THESE"
|
||||
{
|
||||
if (!simulation)
|
||||
event->hide();
|
||||
|
||||
visibleEvents.removeAll(event);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto eventsAttributeList = detailData->attributeEventLookup.getEventsAttributeList(eventType); // get attribute types from event
|
||||
|
||||
// at least one value has to fit per attribute !! (or)
|
||||
for (const QString &attributeType : eventsAttributeList) // attribute of event [[ATTR]]
|
||||
{
|
||||
QString concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType); // why did I not "get the concrete type in any case" back then?
|
||||
bool visibleByAttribute = false; // false from the beginning, because at least one value HAS TO FIT to an attribute
|
||||
bool attributeTypeMentioned = false; // if not filtered by an attribute, then do not filter by this attribute
|
||||
|
||||
|
||||
// no fitting value? then hide event
|
||||
for (const FilterWorker::ModelFilter &mf : modelFilterList) // values from filter list [[VAL]]
|
||||
{
|
||||
if (mf.eventType == eventType || mf.eventType == 0 /* GENERAL_EVENT */) // if true, there are only ModelFilters for General Event (which filters all events) [General Event's attributes get applied on all other Events]
|
||||
{
|
||||
if (mf.attributeType == concreteAttributeType && mf.active) // the attribute from the event looking for?
|
||||
{
|
||||
attributeTypeMentioned = true; // actually filtering by this attribute !
|
||||
|
||||
DetailData::GetDetailDataForAttributeResult result = detailData->getDetailDataForAttribute(event, attributeType); // get attribute from event detail data (zwmsdd)
|
||||
if (result.requestResult != DetailData::RequestResult::Okay) // detail data not found for attr type? must be a redirection
|
||||
result = detailData->getDetailDataForAttribute(event, concreteAttributeType); // TRY REDIRECTION
|
||||
|
||||
/* filter says: look for detail data with attr type "area_pos" => must be redirected before doing this to "position"
|
||||
* filter says: look for "attribute verursacher" => do NOT redirect as this is an existing detail data! */
|
||||
|
||||
/* attribute types with ui type for combobox can redirect unproblematically (same as in filter equation functions)
|
||||
* => attribute types with special ui type(s) should not be redirected
|
||||
* so if the attempt to lookup a attribute interpreter type fails, try another lookup with redirection
|
||||
* side effects: when new attribute types are not completly integrated
|
||||
* guess: ????
|
||||
*/
|
||||
|
||||
if (result.requestResult != DetailData::RequestResult::Okay) // detail data not found for attr type? must be a redirection
|
||||
{
|
||||
WARNING_LOG(logger) << "applyFilter: result.requestResult != DetailData::OKAY -" << (int)result.requestResult;
|
||||
continue; // // TODO: show error and continue
|
||||
}
|
||||
|
||||
//qWarning() << "checkValue: type" << concreteAttributeType << "value id" << result.attributeValueId << "filter value" << mf.attributeValue << "(value as string:"<<result.attributeValue<<")";
|
||||
visibleByAttribute = FilterEquationFunctions::checkValue(detailData, concreteAttributeType, result.attributeValueId, mf.attributeValue);
|
||||
|
||||
if (visibleByAttribute) // the event is visible if minimum ONE attribute fits
|
||||
break;
|
||||
|
||||
#ifdef DEBUG // as it is time consuming
|
||||
DEBUG_LOG(logger)
|
||||
<< "\r\napplyFilter:\r\n"
|
||||
<< "Evnt Type (" << eventType << ")\r\n"
|
||||
<< "Attr Type (" << attributeType << ")\r\n"
|
||||
<< "Evnt Val (" << result.resultValue << ")\r\n"
|
||||
<< "Fltr Val (" << mf.attributeValue << ")\r\n"
|
||||
<< "Evnt SHOW (" << eventVisible << ")\r\n"
|
||||
<< "Attr SHOW (" << visibleByAttribute << ")\r\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at the end, after looping through all values - no value fitting: hide | at least one value fitting: show
|
||||
if (attributeTypeMentioned && !visibleByAttribute) // if attribute is mentioned, but NOT marked as visible, then hide event - because one WHOLE attribute does not fit !
|
||||
{
|
||||
eventVisible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!simulation)
|
||||
event->setVisible(eventVisible);
|
||||
|
||||
if (!eventVisible)
|
||||
visibleEvents.removeAll(event);
|
||||
}
|
||||
|
||||
DEBUG_LOG(logger) << "applyFilter: Visible Events after applying filter:" << visibleEvents.count();
|
||||
|
||||
return visibleEvents;
|
||||
}
|
||||
|
||||
|
||||
LtsTimelineClassic::EventList setFilter(DetailData *detailData,
|
||||
const LtsTimelineClassic::EventList &eventListToFilter,
|
||||
const QJsonArray &filter,
|
||||
QWidget *parentWidget,
|
||||
bool simulation,
|
||||
bool handleResult)
|
||||
{
|
||||
/*/
|
||||
*
|
||||
* Filter Text:
|
||||
*
|
||||
* Syntax : [Filter];[Filter]; ...
|
||||
* Filter : [Event Type]:[Attribute]+[Attribute]+ ...
|
||||
* Attribute : [Attr Type]{[Attr Value],[Attr Value], ...}
|
||||
*
|
||||
/*/
|
||||
|
||||
LtsTimelineClassic::EventList visibleEvents;
|
||||
|
||||
FilterWorker::GetModelFilterListResult result = FilterWorker::getModelFilterList(detailData, filter, true /* type safe !! */); // get model filter list by the filter text
|
||||
ModelFilterList modelFilterList = result.result;
|
||||
if (handleResult)
|
||||
FilterWorker::getInstance()->handleResultValues(result.resultValueList, parentWidget);
|
||||
|
||||
visibleEvents = applyFilter(detailData, eventListToFilter, modelFilterList, simulation); // apply the model filter list to the timeline
|
||||
|
||||
|
||||
return visibleEvents;
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
Loaded 100 of 154 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user