Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
Executable
+212
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* DbReader for RecordingManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
#include "db_reader.h"
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
#include <LtsPluginManager/lts_plugin_loader.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlError>
|
||||
#include <QSqlField>
|
||||
#include <QSqlIndex>
|
||||
#include <QSqlRecord>
|
||||
#include <QVariant>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
|
||||
DbReader::DbReader(int exerciseId)
|
||||
: m_exerciseId(exerciseId)
|
||||
, m_queryFrom(nullptr)
|
||||
, m_queryTo(nullptr)
|
||||
, m_bSupportsSchemasFrom(false)
|
||||
, m_bSupportsSchemasTo(false)
|
||||
, m_logger(PresentationManagement::getLogger("DbReader"))
|
||||
{}
|
||||
|
||||
DbReader::~DbReader()
|
||||
{
|
||||
delete m_queryFrom;
|
||||
delete m_queryTo;
|
||||
// Todo: crashes OperatorApplication. Required to unload?
|
||||
// LtsPluginManager::LtsPluginLoader::getInstance()->unloadAllPlugins();
|
||||
m_plugins.clear();
|
||||
}
|
||||
|
||||
bool DbReader::loadPlugin(const LtsPluginManager::PluginInstance &pi)
|
||||
{
|
||||
RecordReplay::RecordReplayPlugin *recPlugin = qobject_cast<RecordReplay::RecordReplayPlugin*>(pi.plugin);
|
||||
if (!recPlugin)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot load RecordReplayPlugin " << pi.fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!recPlugin->initCopy(m_exerciseId, m_bSupportsSchemasFrom, m_bSupportsSchemasTo))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Initialisation for RecordReplayPlugin " << pi.fileName << " failed ";
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Loaded record replay plugin " << recPlugin->pluginName();
|
||||
m_plugins += recPlugin;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbReader::init(const QSqlDatabase &dbFrom, const QSqlDatabase &dbTo)
|
||||
{
|
||||
m_dbFrom = dbFrom;
|
||||
delete m_queryFrom;
|
||||
m_queryFrom = new NSqlQuery(dbFrom);
|
||||
m_bSupportsSchemasFrom = dbFrom.driverName() != QStringLiteral("QSQLITE");
|
||||
|
||||
m_dbTo = dbTo;
|
||||
delete m_queryTo;
|
||||
m_queryTo = new NSqlQuery(dbTo);
|
||||
m_bSupportsSchemasTo = dbTo.driverName() != QStringLiteral("QSQLITE");
|
||||
|
||||
auto cb = [this](const LtsPluginManager::PluginInstance &pi) { return loadPlugin(pi);};
|
||||
LtsPluginManager::LtsPluginLoader::getInstance()->loadPlugins(LtsPluginManager::PluginType::SPECIAL,
|
||||
cb,
|
||||
QStringList(),
|
||||
QStringLiteral("recordreplay"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbReader::createTables()
|
||||
{
|
||||
for(RecordReplay::RecordReplayPlugin *recPlugin : qAsConst(m_plugins))
|
||||
{
|
||||
const QVector<QString> tableNames = recPlugin->getRecordTableNames();
|
||||
for (const QString &name : tableNames)
|
||||
{
|
||||
const QString fqTableName = DBCommon::getExerciseTableName(name, m_exerciseId);
|
||||
const QSqlRecord record = m_dbFrom.record(fqTableName);
|
||||
|
||||
if (record.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Empty record for " << fqTableName;
|
||||
return false;
|
||||
}
|
||||
|
||||
const QSqlIndex pk = m_dbFrom.primaryIndex(fqTableName);
|
||||
createTable(*m_queryTo, name, record, pk, m_logger);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbReader::copyData(qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
INFO_LOG(m_logger) << "IN readData";
|
||||
if (!m_queryFrom || !m_queryTo)
|
||||
return false;
|
||||
// for each plugin
|
||||
for(RecordReplay::RecordReplayPlugin *recPlugin : qAsConst(m_plugins))
|
||||
{
|
||||
if (!recPlugin->copyData(*m_queryFrom, *m_queryTo, fromTime, toTime))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString sqliteTypeFromVariant(QVariant::Type t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case QVariant::Bool:
|
||||
return QStringLiteral("boolean");
|
||||
case QVariant::Int:
|
||||
return QStringLiteral("integer");
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
case QVariant::ULongLong: // mhhh
|
||||
return QStringLiteral("bigint");
|
||||
case QVariant::Double:
|
||||
return QStringLiteral("double precision");
|
||||
case QVariant::String:
|
||||
return QStringLiteral("text");
|
||||
case QVariant::ByteArray:
|
||||
return QStringLiteral("blob");
|
||||
case QVariant::Date:
|
||||
case QVariant::Time:
|
||||
case QVariant::DateTime:
|
||||
return QStringLiteral("text");
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool DbReader::createTable(NSqlQuery &q, const QString &tableName, const QSqlRecord &record, const QSqlIndex &pk, NGL::INGLLogger &logger)
|
||||
{
|
||||
QStringList createTableColumns;
|
||||
createTableColumns.reserve(record.count());
|
||||
|
||||
QStringList pks;
|
||||
pks.reserve(pk.count());
|
||||
for (int i = 0; i < pk.count(); ++i)
|
||||
pks += pk.field(i).name();
|
||||
|
||||
bool bCreateIdxOnId = false;
|
||||
bool bCreateIdxOnSampleTime = false;
|
||||
for (int i = 0; i < record.count(); ++i)
|
||||
{
|
||||
const QSqlField f = record.field(i);
|
||||
if (!bCreateIdxOnId && f.name() == QLatin1String("id"))
|
||||
bCreateIdxOnId = true;
|
||||
if (!bCreateIdxOnSampleTime && f.name() == QLatin1String("sample_time"))
|
||||
bCreateIdxOnSampleTime = true;
|
||||
|
||||
QString type = sqliteTypeFromVariant(f.type());
|
||||
const int idx = pks.indexOf(f.name());
|
||||
if (idx >= 0)
|
||||
{
|
||||
pks.removeAt(i);
|
||||
type = QStringLiteral("INTEGER PRIMARY KEY");
|
||||
}
|
||||
|
||||
createTableColumns += f.name() + QLatin1Char(' ') + type;
|
||||
}
|
||||
if (bCreateIdxOnSampleTime)
|
||||
bCreateIdxOnId = false;
|
||||
|
||||
const QString createTableCommand(QStringLiteral("CREATE TABLE %1 (%2)").arg(tableName, createTableColumns.join(QStringLiteral(",\n"))));
|
||||
const QString indexIdTableCommand(QStringLiteral("CREATE INDEX IDX_%1_id ON %1 (id)").arg(tableName));
|
||||
const QString indexStTableCommand(QStringLiteral("CREATE INDEX IDX_%1_sampleTime ON %1 (sample_time)").arg(tableName));
|
||||
DEBUG_LOG(logger) << createTableCommand;
|
||||
DEBUG_LOG(logger) << indexIdTableCommand;
|
||||
DEBUG_LOG(logger) << indexStTableCommand;
|
||||
|
||||
q.exec(QStringLiteral("DROP TABLE IF EXISTS %1").arg(tableName));
|
||||
|
||||
if (!q.exec(createTableCommand))
|
||||
{
|
||||
ERROR_LOG(logger) << "qOut create table failed... " << q.lastError().text();
|
||||
return false;
|
||||
}
|
||||
if (bCreateIdxOnId && !q.exec(indexIdTableCommand))
|
||||
{
|
||||
ERROR_LOG(logger) << "qOut create index on table... " << q.lastError().text();
|
||||
return false;
|
||||
}
|
||||
if (bCreateIdxOnSampleTime && !q.exec(indexStTableCommand))
|
||||
{
|
||||
ERROR_LOG(logger) << "qOut create index on table... " << q.lastError().text();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // TakeHomePackageGenerator
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* DbReader for SituationReplay
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QVector>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include <PluginInterfaces/record_replay_plugin.h>
|
||||
#include <PresentationManagement/logger.h>
|
||||
|
||||
class NSqlQuery;
|
||||
namespace LtsPluginManager
|
||||
{
|
||||
struct PluginInstance;
|
||||
}
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
|
||||
class DbReader final
|
||||
{
|
||||
public:
|
||||
explicit DbReader(int exerciseId);
|
||||
~DbReader();
|
||||
|
||||
bool init(const QSqlDatabase &dbFrom, const QSqlDatabase &dbTo);
|
||||
|
||||
bool createTables();
|
||||
bool copyData(qint64 fromTime, qint64 toTime);
|
||||
|
||||
|
||||
static bool createTable(NSqlQuery &q, const QString &tableName, const QSqlRecord &record, const QSqlIndex &pk, NGL::INGLLogger &logger);
|
||||
private:
|
||||
bool loadPlugin(const LtsPluginManager::PluginInstance &pi);
|
||||
private:
|
||||
int m_exerciseId;
|
||||
QSqlDatabase m_dbFrom;
|
||||
QSqlDatabase m_dbTo;
|
||||
NSqlQuery *m_queryFrom;
|
||||
NSqlQuery *m_queryTo;
|
||||
bool m_bSupportsSchemasFrom;
|
||||
bool m_bSupportsSchemasTo;
|
||||
|
||||
QVector<RecordReplay::RecordReplayPlugin*> m_plugins;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace TakeHomePackageGenerator
|
||||
Executable
+254
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Burn data to dvd
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "dvd_writer.h"
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
DVDWriter::DVDWriter(const QString &packageDir, QObject *pParent)
|
||||
: QObject(pParent)
|
||||
, m_pProgressDlg(new QProgressDialog(tr("Burning files..."), tr("Abort"), 0, 100, nullptr))
|
||||
, m_packageDir(packageDir)
|
||||
, m_logger(PresentationManagement::getLogger("DbReader"))
|
||||
{
|
||||
connect(m_pProgressDlg, &QProgressDialog::canceled, this, &DVDWriter::slotCancel);
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::slotCancel()
|
||||
{
|
||||
cleanupProcess();
|
||||
m_pProgressDlg->setLabelText(tr("Cancelling burning process..."));
|
||||
m_pProgressDlg->setCancelButton(nullptr);
|
||||
m_pProgressDlg->setMaximum(0);
|
||||
}
|
||||
|
||||
|
||||
DVDWriter::~DVDWriter()
|
||||
{
|
||||
if (m_pProgressDlg)
|
||||
m_pProgressDlg->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::slotWriteDVD()
|
||||
{
|
||||
cleanupProcess();
|
||||
|
||||
m_dvdBurnProcess = new QProcess(this);
|
||||
|
||||
m_pProgressDlg->setMinimumDuration(0);
|
||||
m_pProgressDlg->setWindowTitle(tr("Burning..."));
|
||||
m_pProgressDlg->setWindowModality(Qt::WindowModal);
|
||||
|
||||
QStringList args;
|
||||
args << QStringLiteral("-Z") << dvdDevice() << QStringLiteral("-R") << QStringLiteral("-J") << QStringLiteral("-udf") << m_packageDir;
|
||||
|
||||
connect(m_dvdBurnProcess.data(), &QProcess::readyRead,
|
||||
this, &DVDWriter::incomingDataAvailable);
|
||||
connect(m_dvdBurnProcess.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DVDWriter::dvdFinished);
|
||||
|
||||
m_dvdBurnProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
m_dvdBurnProcess->start(dvdProgram(), args);
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::incomingDataAvailable()
|
||||
{
|
||||
while (m_dvdBurnProcess && m_dvdBurnProcess->canReadLine())
|
||||
{
|
||||
const QByteArray qB = m_dvdBurnProcess->readLine().trimmed();
|
||||
INFO_LOG(m_logger) << "qb = " << qB.data()
|
||||
<< " m_packageDir=" << m_packageDir;
|
||||
|
||||
if (qB.contains(":-["))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
QString errString = QString::fromUtf8(qB.mid(3));
|
||||
|
||||
if (LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("No DVD in drive / error burning dvd. Try again?"),
|
||||
errString,
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes | LtsWidgets::Button::No) == LtsWidgets::Button::Yes)
|
||||
slotWriteDVD();
|
||||
else
|
||||
{
|
||||
cleanup(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Example Text:
|
||||
if (qB.contains("estimate finish")) // " 6.31% done, estimate finish Thu Sep 1 12:09:05 2011"
|
||||
m_pProgressDlg->setValue((int) qB.left(qB.indexOf("%")).toDouble() * 0.9); // 90% for processes %age, 10% for lead out & Co.
|
||||
else if (qB.contains("Total translation table size")) // "Total translation table size: 0"
|
||||
m_pProgressDlg->setValue(91);
|
||||
else if (qB.contains("Total rockridge attributes bytes")) // "Total rockridge attributes bytes: 92758"
|
||||
m_pProgressDlg->setValue(92);
|
||||
else if (qB.contains("Total directory bytes")) // "Total directory bytes: 165888"
|
||||
m_pProgressDlg->setValue(93);
|
||||
else if (qB.contains("Path table size(bytes)")) // "Path table size(bytes): 244"
|
||||
m_pProgressDlg->setValue(94);
|
||||
else if (qB.contains("Max brk space used")) // "Max brk space used ea000"
|
||||
m_pProgressDlg->setValue(95);
|
||||
else if (qB.contains("extents written")) // "79377 extents written (155 MB)"
|
||||
m_pProgressDlg->setValue(96);
|
||||
else if (qB.contains("builtin_dd")) // "builtin_dd: 79392*2KB out @ average 5.6x1352KBps"
|
||||
m_pProgressDlg->setValue(97);
|
||||
else if (qB.contains("flushing cache")) // "/dev/dvd: flushing cache"
|
||||
m_pProgressDlg->setValue(98);
|
||||
else if (qB.contains("updating RMA")) // "/dev/dvd: updating RMA"
|
||||
m_pProgressDlg->setValue(99);
|
||||
else if (qB.contains("closing session")) // "/dev/dvd: closing session"
|
||||
m_pProgressDlg->setValue(100);
|
||||
else if (qB.contains("media is not recognized"))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
if (LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("No DVD in drive. Try again?"),
|
||||
tr("Media is not recognized"),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes | LtsWidgets::Button::No) == LtsWidgets::Button::Yes)
|
||||
slotWriteDVD();
|
||||
else
|
||||
cleanup(false);
|
||||
return;
|
||||
}
|
||||
else if (qB.contains(":-( unable to open"))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
if (LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Unable to open DVD device. Try again?"),
|
||||
tr("Unable to open DVD device"),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes | LtsWidgets::Button::No) == LtsWidgets::Button::Yes)
|
||||
slotWriteDVD();
|
||||
else
|
||||
cleanup(false);
|
||||
return;
|
||||
}
|
||||
else if (qB.contains(":-("))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
QString strError(tr("Unable to open DVD device"));
|
||||
|
||||
QString strErrorReason(QString::fromUtf8(qB));
|
||||
int index = strErrorReason.indexOf(QLatin1Char(':'), 1); // Skip eyes of the sad smiley (':-(')
|
||||
if (index > 0)
|
||||
{
|
||||
strError += QStringLiteral("<br>Error:");
|
||||
strError += strErrorReason.remove(0, index + 1);
|
||||
}
|
||||
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), strError);
|
||||
cleanup(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::dvdFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
// TODO: exitCode und exitStatus korrekt auswerten
|
||||
INFO_LOG(m_logger) << "growisofs ends with extitCode : '" << exitCode << " and ExitStatus '" << exitStatus;
|
||||
|
||||
//Closing Down DVD Process
|
||||
if (!m_dvdBurnProcess)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "dvdFinished with error code: " << exitCode << ", status: " << exitStatus
|
||||
<< " process is already cleaned up";
|
||||
return;
|
||||
}
|
||||
|
||||
m_dvdBurnProcess->close();
|
||||
m_dvdBurnProcess->deleteLater();
|
||||
m_dvdBurnProcess = nullptr;
|
||||
if (exitCode == 0 && exitStatus == QProcess::NormalExit)
|
||||
{
|
||||
m_pProgressDlg->setValue(100);
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Burning complete"));
|
||||
cleanup(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "dvdFinished with error code: " << exitCode << ", status: " << exitStatus;
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Burning aborted with an unkown error %1").arg(exitCode));
|
||||
cleanup(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::cleanup(bool success)
|
||||
{
|
||||
if (m_pProgressDlg)
|
||||
{
|
||||
m_pProgressDlg->deleteLater();
|
||||
m_pProgressDlg = nullptr;
|
||||
}
|
||||
emit signalBurningFinished(success);
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::cleanupProcess()
|
||||
{
|
||||
if (m_dvdBurnProcess)
|
||||
{
|
||||
m_dvdBurnProcess->disconnect();
|
||||
m_dvdBurnProcess->terminate();
|
||||
if (!m_dvdBurnProcess->waitForFinished(1000))
|
||||
m_dvdBurnProcess->kill();
|
||||
m_dvdBurnProcess->deleteLater();
|
||||
m_dvdBurnProcess = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DVDWriter::checkBuringCapabilities()
|
||||
{
|
||||
QFileInfo fi1(dvdProgram());
|
||||
if (!fi1.exists() || !fi1.isFile() || !fi1.isExecutable())
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Unable to locate burning executable (%1)").arg(dvdProgram()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi2(dvdDevice());
|
||||
if (!fi2.exists() || !fi2.isReadable() || !fi2.isWritable())
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Unable to find DVD device (%1)").arg(dvdDevice()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString DVDWriter::dvdProgram() const
|
||||
{
|
||||
return QStringLiteral("/usr/bin/growisofs");
|
||||
}
|
||||
|
||||
QString DVDWriter::dvdDevice() const
|
||||
{
|
||||
#ifdef LTS_DEBUG
|
||||
return QStringLiteral("/dev/sr0");
|
||||
#else
|
||||
return QStringLiteral("/dev/rde/dvd");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Burn data to dvd
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include "export.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QProcess>
|
||||
#include <QPointer>
|
||||
#include <QProgressDialog>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class PREGUISCRIPTCOMMON_EXPORT DVDWriter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DVDWriter(const QString &packageDir, QObject *pParent = nullptr);
|
||||
~DVDWriter();
|
||||
|
||||
signals:
|
||||
void signalBurningFinished(bool success);
|
||||
|
||||
public slots:
|
||||
void slotWriteDVD();
|
||||
|
||||
private slots:
|
||||
void slotCancel();
|
||||
void incomingDataAvailable();
|
||||
void dvdFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
private:
|
||||
void cleanup(bool success);
|
||||
void cleanupProcess();
|
||||
bool checkBuringCapabilities();
|
||||
QString dvdProgram() const;
|
||||
QString dvdDevice() const;
|
||||
|
||||
QProgressDialog *m_pProgressDlg;
|
||||
|
||||
QString m_packageDir;
|
||||
QPointer<QProcess> m_dvdBurnProcess;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "export.h"
|
||||
#include "situation_exporter.h"
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
bool exportSituationMapData(int exerciseId, const QString& strPathToFile, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
SituationExporter se(exerciseId);
|
||||
if (!se.exportStaticData(strPathToFile))
|
||||
return false;
|
||||
if (!se.exportDynamicData(fromTime, toTime))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace TakeHomePackageGenerator
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
PREGUISCRIPTCOMMON_EXPORT bool exportSituationMapData(int exerciseId, const QString& strPathToFile, qint64 fromTime = 0, qint64 toTime = 1822159491 * 1000LL);
|
||||
}
|
||||
|
||||
Executable
+637
@@ -0,0 +1,637 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "export_process.h"
|
||||
#include "export_step.h"
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
#include <QProgressDialog>
|
||||
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
|
||||
#include <Plugins/AssetManagement/asm_data_plugin_interface.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
//
|
||||
// ExportedScriptInformation
|
||||
//
|
||||
QJsonValue ExportedScriptInformation::toJson() const
|
||||
{
|
||||
// THP-Export: In der Übersichts-Website 'Take Home Package werden einige
|
||||
// Übungsparameter angezeigt, aber auch die Präsenmtationen mit ihrem
|
||||
// Namen aufgelistet. Dort gab es wohl in Hin und Her zw.
|
||||
// 'presentations.name' und 'presentations.displayName'.
|
||||
// Daher schreiben wir nun den ScriptName doppelt, damit es für beiden
|
||||
// Varianten funktioniert:
|
||||
return QJsonObject({{QStringLiteral("name"), scriptName},
|
||||
{QStringLiteral("displayName"), scriptName}, // write {name and displayName} with identical value (not clear which will be used at index_de_DE.html @ thp_viewer)
|
||||
{QStringLiteral("path"), jsonPath},
|
||||
{QStringLiteral("scriptId"), scriptId},
|
||||
{QStringLiteral("exportTime"), exportTime},
|
||||
{QStringLiteral("exerciseName"), exerciseName}
|
||||
});
|
||||
}
|
||||
|
||||
ExportProcess::ExportProcess(LtsSession::LtsSession *pSession,
|
||||
const std::shared_ptr<SituationReplay::ForeignGuiInterface> &replayGuiIfc,
|
||||
QProgressDialog *pProgressDlg,
|
||||
const QString &strScriptName,
|
||||
const QString &strExerciseName,
|
||||
int scriptId,
|
||||
const std::vector<PresentationManagement::PresentationContent> &contentList,
|
||||
const QMap<QString, PresentationManagement::TopicAssignment> &trackEntryAssignments,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_contentList(contentList)
|
||||
, m_trackEntryAssignments(trackEntryAssignments)
|
||||
, m_strScriptName(strScriptName)
|
||||
, m_strExerciseName(strExerciseName)
|
||||
, m_scriptId(scriptId)
|
||||
, m_pSession(pSession)
|
||||
, m_replayGuiIfc(replayGuiIfc)
|
||||
, m_pProgressDlg(pProgressDlg)
|
||||
, m_cntTopicsToExport(0)
|
||||
, m_logger(PresentationManagement::getLogger("ExportProcess"))
|
||||
{
|
||||
QDir().mkpath(contentPath());
|
||||
}
|
||||
|
||||
|
||||
ExportProcess::~ExportProcess()
|
||||
{
|
||||
for (auto e : qAsConst(m_vecExportSteps))
|
||||
e->deleteLater();
|
||||
|
||||
for (auto e : qAsConst(m_vecExportStepsExecuted))
|
||||
e->deleteLater();
|
||||
}
|
||||
|
||||
QString ExportProcess::exportPath(const int exerciseId)
|
||||
{
|
||||
return exportRootPath() + QStringLiteral("Exercise_%1/").arg(exerciseId);
|
||||
}
|
||||
|
||||
QString ExportProcess::exportRootPath()
|
||||
{
|
||||
return QDir::tempPath() + QLatin1String("/THP-Export/");
|
||||
}
|
||||
|
||||
static QVector<TopicReplay::Interface::SituationReplayTime> extractUsedSitReplayTimes(
|
||||
const TopicEditorBase::TopicData &data, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
)
|
||||
{
|
||||
// Add replay information (not necessarily available) to attributes
|
||||
QVector<TopicReplay::Interface::SituationReplayTime> ret;
|
||||
ret.reserve(5);
|
||||
for (const TopicReplay::Interface::SituationReplayTime &sitReplayTime : allSitReplayTimes)
|
||||
{
|
||||
bool collides = LtsScriptTimeline::isCollision(data.startTime, data.startTime + data.duration, sitReplayTime.topicStart_s, sitReplayTime.topicEnd_s);
|
||||
if (collides)
|
||||
ret.push_back(sitReplayTime);
|
||||
}
|
||||
// Order chronologically
|
||||
std::sort(ret.begin(), ret.end(),
|
||||
[](const TopicReplay::Interface::SituationReplayTime &a, const TopicReplay::Interface::SituationReplayTime &b)
|
||||
{
|
||||
return a.topicStart_s < b.topicStart_s;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ExportProcess::slotStartExport()
|
||||
{
|
||||
/*
|
||||
* Identify all replay topics, save their start and end times (topic start/end and actual replay start/end time).
|
||||
* Replay topics are used when exporting, e.g. Building Topics since they may be placed parallel to one or more ReplayTopics
|
||||
*/
|
||||
QVector<TopicReplay::Interface::SituationReplayTime> allSitReplayTimes;
|
||||
|
||||
for (const PresentationManagement::PresentationContent &content : qAsConst(m_contentList))
|
||||
{
|
||||
auto it = m_trackEntryAssignments.constFind(QString::fromStdString(content.presentationTopicType()));
|
||||
if (it == m_trackEntryAssignments.constEnd())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Invalid content for type (" << content.presentationTopicType() << "): " << QString::fromStdString(content.presentationTopicType());
|
||||
continue;
|
||||
}
|
||||
|
||||
const PresentationManagement::TopicAssignment &ta = it.value();
|
||||
if (ta.topicType == TopicEditorBase::TopicType::SituationReplay ||
|
||||
ta.topicType == TopicEditorBase::TopicType::Situation)
|
||||
{
|
||||
// Verify content
|
||||
if (content.attributes().size() == 0)
|
||||
continue;
|
||||
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(QByteArray(content.attributes().c_str(), content.attributes().size()), &parseError));
|
||||
if (parseError.error != QJsonParseError::NoError)
|
||||
continue;
|
||||
const QJsonObject detailData = doc.object();
|
||||
|
||||
TopicReplay::Interface::SituationReplayTime sitReplayTime;
|
||||
sitReplayTime.id = content.id();
|
||||
sitReplayTime.topicStart_s = content.startTime();
|
||||
sitReplayTime.topicEnd_s = content.startTime() + content.duration();
|
||||
sitReplayTime.replaySpeedFactor = qRound64(detailData.value(QStringLiteral("speed")).toDouble(1.0));
|
||||
sitReplayTime.replayStart_ms = qRound64(detailData.value(QStringLiteral("start")).toDouble());
|
||||
sitReplayTime.replayEnd_ms = sitReplayTime.replayStart_ms + (content.duration() * sitReplayTime.replaySpeedFactor * 1000); // do not use 'end' json object
|
||||
allSitReplayTimes.push_back(std::move(sitReplayTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (const PresentationManagement::PresentationContent &content : m_contentList)
|
||||
{
|
||||
auto it = m_trackEntryAssignments.constFind(QString::fromStdString(content.presentationTopicType()));
|
||||
|
||||
if (it == m_trackEntryAssignments.constEnd())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Invalid content for presentation type " << content.presentationTopicType();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify content
|
||||
if (content.attributes().size() == 0)
|
||||
continue;
|
||||
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(QByteArray(content.attributes().c_str(), content.attributes().size()), &parseError));
|
||||
if (parseError.error != QJsonParseError::NoError)
|
||||
continue;
|
||||
QJsonObject detailData = doc.object();
|
||||
|
||||
const PresentationManagement::TopicAssignment &ta = *it;
|
||||
|
||||
// Get export interface
|
||||
TopicReplay::Interface *topicExportIfc = ta.topicExportFactory->createInterface(ta.topicType);
|
||||
|
||||
if (!topicExportIfc)
|
||||
{
|
||||
//WARNING_LOG(m_logger) << "Warning: Export for topic id " << te->m_topicId << " failed";
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the filter steps
|
||||
m_vecExportSteps += parseFilterSteps(content.id(), detailData, allSitReplayTimes);
|
||||
|
||||
// TrackEntry is used when all topics have been exported and the html table is created (start time, duration)
|
||||
// after filter steps to make sure we use the updated detailData
|
||||
TopicEditorBase::TopicData data(
|
||||
content.id(), ta.topicType, content.startTime(), content.duration(), QString::fromStdString(content.description()),
|
||||
QString::fromStdString(content.channel()), detailData
|
||||
);
|
||||
QJsonArray unused;
|
||||
bool keepOriginalTopic = false;
|
||||
m_vecExportSteps += checkAdditionalExportEntries(content.id(), data, unused, topicExportIfc, allSitReplayTimes, keepOriginalTopic);
|
||||
if (keepOriginalTopic)
|
||||
m_vecExportSteps += createExportStep(content.id(), data, topicExportIfc, allSitReplayTimes);
|
||||
}
|
||||
|
||||
connect(m_pProgressDlg, &QProgressDialog::canceled, this, &ExportProcess::slotCancel);
|
||||
m_cntTopicsToExport = m_vecExportSteps.size();
|
||||
m_pProgressDlg->setMaximum(m_cntTopicsToExport);
|
||||
slotRunExportStep();
|
||||
}
|
||||
|
||||
QVector<ExportStep *> ExportProcess::parseFilterSteps(
|
||||
int parentTopicId, QJsonObject &detailData, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
)
|
||||
{
|
||||
QVector<ExportStep *> ret;
|
||||
const QJsonArray filters = detailData.value(QStringLiteral("Filters")).toArray();
|
||||
QJsonArray newFilterLines;
|
||||
for (const QJsonValue &filterLineValue : qAsConst(filters))
|
||||
{
|
||||
TopicEditorBase::TopicData data;
|
||||
auto temp = filterLineValue.toObject();
|
||||
data.fromJson(temp);
|
||||
|
||||
if (data.topicType != TopicEditorBase::TopicType::TacticalPlan &&
|
||||
data.topicType != TopicEditorBase::TopicType::SituationMapFilter &&
|
||||
data.topicType != TopicEditorBase::TopicType::Pdf &&
|
||||
data.topicType != TopicEditorBase::TopicType::Image &&
|
||||
data.topicType != TopicEditorBase::TopicType::Text)
|
||||
continue;
|
||||
|
||||
auto topicExportIfc = topicIfcFromType(data.topicType, ExportOrReplay::Export);
|
||||
if (!topicExportIfc)
|
||||
continue;
|
||||
auto topicReplayIfc = topicIfcFromType(data.topicType, ExportOrReplay::Replay);
|
||||
if (!topicReplayIfc)
|
||||
{
|
||||
delete topicExportIfc;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool keepOriginalTopic = true;
|
||||
ret += checkAdditionalExportEntries(parentTopicId, data, newFilterLines, topicReplayIfc, allSitReplayTimes, keepOriginalTopic);
|
||||
if (keepOriginalTopic)
|
||||
ret += createExportStep(parentTopicId, data, topicExportIfc, allSitReplayTimes);
|
||||
|
||||
// delete topicExportIfc; // ownership is transfered to TakeHomePackageGenerator::ExportStep within createExportStep
|
||||
delete topicReplayIfc;
|
||||
newFilterLines += temp;
|
||||
}
|
||||
detailData[QStringLiteral("Filters")] = newFilterLines;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<ExportStep *> ExportProcess::checkAdditionalExportEntries(
|
||||
int realParentId, const TopicEditorBase::TopicData &parentData, QJsonArray &filterLines,
|
||||
TopicReplay::Interface *parentTopicReplayIfc, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes,
|
||||
bool &keepOriginalTopic
|
||||
)
|
||||
{
|
||||
QVector<TakeHomePackageGenerator::ExportStep *> ret;
|
||||
// add possible additional export entries
|
||||
const auto addTrackEntries = parentTopicReplayIfc->additionalTrackEntries(parentData.properties, keepOriginalTopic);
|
||||
for (const TopicEditorBase::TopicData &data : addTrackEntries)
|
||||
{
|
||||
TopicEditorBase::TopicData addData(data);
|
||||
addData.description = parentData.description;
|
||||
addData.startTime = parentData.startTime;
|
||||
addData.duration = parentData.duration;
|
||||
addData.id = parentData.id;
|
||||
|
||||
auto topicExportIfc = topicIfcFromType(addData.topicType, ExportOrReplay::Export);
|
||||
DEBUG_LOG(m_logger) << "addEntry type: " << addData.topicType << ", ifc: " << topicExportIfc;
|
||||
if (!topicExportIfc)
|
||||
continue;
|
||||
|
||||
filterLines += addData.toJson();
|
||||
ret += createExportStep(realParentId, addData, topicExportIfc, allSitReplayTimes);
|
||||
m_cntTopicsToExport++;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "topic count: " << m_cntTopicsToExport;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ExportStep *ExportProcess::createExportStep(
|
||||
int parentTopicId, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicExportIfc,
|
||||
const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
)
|
||||
{
|
||||
TakeHomePackageGenerator::ExportStep *pExportStep = new TakeHomePackageGenerator::ExportStep(this, data, topicExportIfc);
|
||||
|
||||
pExportStep->setSituationReplayTimes(extractUsedSitReplayTimes(data, allSitReplayTimes));
|
||||
pExportStep->setParentTopicId(parentTopicId);
|
||||
pExportStep->setBasePath(exportPath(m_pSession->exerciseId()));
|
||||
|
||||
connect(pExportStep, &TakeHomePackageGenerator::ExportStep::signalExportSuccessful,
|
||||
this, &ExportProcess::slotRunExportStep, Qt::QueuedConnection);
|
||||
|
||||
connect(pExportStep, &TakeHomePackageGenerator::ExportStep::signalExportFailed,
|
||||
this, &ExportProcess::slotRunExportStep, Qt::QueuedConnection);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Adding filter step " << data.topicType;
|
||||
return pExportStep;
|
||||
}
|
||||
|
||||
TopicReplay::Interface *ExportProcess::topicIfcFromType(TopicEditorBase::TopicType type, ExportOrReplay exportOrReplay) const
|
||||
{
|
||||
auto it = m_trackEntryAssignments.constFind(TopicEditorBase::topicTypeString(type));
|
||||
if (it == m_trackEntryAssignments.constEnd())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Invalid content for presentation type " << type;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PresentationManagement::TopicAssignment &ta = *it;
|
||||
TopicReplay::Interface *topicIfc = exportOrReplay == ExportOrReplay::Export ? ta.topicExportFactory->createInterface(ta.topicType)
|
||||
: ta.topicReplayFactory->createInterface(ta.topicType);
|
||||
if (!topicIfc)
|
||||
WARNING_LOG(m_logger) << "Could not find replay interface for " << type;
|
||||
return topicIfc;
|
||||
}
|
||||
|
||||
void ExportProcess::slotCancel()
|
||||
{
|
||||
m_pProgressDlg->setLabelText(tr("Export cancelled, waiting for current\ntopic export to finish..."));
|
||||
m_pProgressDlg->setCancelButton(nullptr);
|
||||
m_pProgressDlg->setMaximum(0);
|
||||
m_pProgressDlg->show();
|
||||
}
|
||||
|
||||
|
||||
void ExportProcess::slotRunExportStep()
|
||||
{
|
||||
if (m_logger.isDebugEnabled())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "ExportProcess::slotRunExportStep() CALLED, m_vecExportSteps.size(): " << m_vecExportSteps.size()
|
||||
<< ", m_vecExportStepsExecuted.size(): " << m_vecExportStepsExecuted.size();
|
||||
|
||||
for (const auto &s : qAsConst(m_vecExportSteps))
|
||||
DEBUG_LOG(m_logger) << "m_vecExportSteps: " << s << " compare: " << (s == sender());
|
||||
for (const auto &s : qAsConst(m_vecExportStepsExecuted))
|
||||
DEBUG_LOG(m_logger) << "m_vecExportStepsExecuted: " << s << " compare: " << (s == sender());
|
||||
}
|
||||
|
||||
if (m_pProgressDlg->wasCanceled())
|
||||
{
|
||||
m_pProgressDlg->hide();
|
||||
m_pProgressDlg->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
m_pProgressDlg->setValue(m_vecExportStepsExecuted.size());
|
||||
|
||||
if (m_vecExportSteps.size())
|
||||
{
|
||||
TakeHomePackageGenerator::ExportStep *pExportStep = m_vecExportSteps.takeFirst();
|
||||
m_vecExportStepsExecuted.push_back(pExportStep);
|
||||
|
||||
QString strExportLabel(tr("Exporting topic of type \"%1\" (Topic %2 / %3)")
|
||||
.arg(TopicEditorBase::topicTypeString(pExportStep->m_topicData.topicType))
|
||||
.arg(m_vecExportStepsExecuted.size())
|
||||
.arg(m_cntTopicsToExport));
|
||||
DEBUG_LOG(m_logger) << strExportLabel;
|
||||
m_pProgressDlg->setLabelText(strExportLabel);
|
||||
|
||||
QString strExportPath(contentPath() + QString::number(pExportStep->topicId()) + QLatin1Char('/'));
|
||||
QDir dir(strExportPath);
|
||||
dir.mkdir(strExportPath);
|
||||
pExportStep->startExport(strExportPath);
|
||||
}
|
||||
else
|
||||
exportDone();
|
||||
}
|
||||
|
||||
|
||||
void ExportProcess::exportDone()
|
||||
{
|
||||
createJsonFiles();
|
||||
createPresentationTable();
|
||||
copyStaticContent();
|
||||
|
||||
QStringList sl;
|
||||
for (const auto &step : qAsConst(m_vecExportStepsExecuted))
|
||||
{
|
||||
if (step->exportFailed())
|
||||
sl << QStringLiteral("%1 (%2)").arg(step->m_topicData.description, TopicEditorBase::topicTypeTranslation(step->m_topicData.topicType));
|
||||
}
|
||||
|
||||
|
||||
emit exportSuccessful(exportPath(m_pSession->exerciseId()), sl.join(QStringLiteral(",<br />")));
|
||||
|
||||
m_pProgressDlg->deleteLater();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
static inline QJsonArray descVecToArray(const std::vector<AssetManagement::MapDescription> &descriptions,
|
||||
const QString &layerBaseName)
|
||||
{
|
||||
QJsonArray arr;
|
||||
QJsonObject obj;
|
||||
for (size_t i = 0; i < descriptions.size(); ++i)
|
||||
{
|
||||
// must be in sync with SituationMap::BaseUrl
|
||||
const AssetManagement::MapDescription &desc = descriptions.at(i);
|
||||
const bool isElevation = desc.mapDescriptionTypeId() == AssetManagement::MapDescriptionType::Elevation;
|
||||
obj[QStringLiteral("name")] = QString::fromStdString(desc.name());
|
||||
obj[QStringLiteral("description")] = QString::fromStdString(desc.description());
|
||||
obj[QStringLiteral("url")] = QString(layerBaseName + QLatin1Char('_') + QString::number(i) + (isElevation ? QStringLiteral(".tiff") : QStringLiteral(".tpk")));
|
||||
obj[QStringLiteral("minScale")] = desc.minScale();
|
||||
obj[QStringLiteral("maxScale")] = desc.maxScale();
|
||||
|
||||
arr.append(obj);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
void ExportProcess::createJsonFiles()
|
||||
{
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc = nullptr;
|
||||
std::shared_ptr<AssetManagement::Interface::Dtc> asmDtc = nullptr;
|
||||
if (!m_pSession->getDtc<AssetManagement::DataInterface>(asmDtc) ||
|
||||
!m_pSession->getDtc<ExerciseManagement::DataInterface>(exmDtc))
|
||||
return;
|
||||
createLayerMappings(exmDtc, asmDtc);
|
||||
createDataJson(exmDtc, asmDtc);
|
||||
}
|
||||
|
||||
void ExportProcess::createLayerMappings(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const
|
||||
{
|
||||
QFile file(exportPath(m_pSession->exerciseId()) + QStringLiteral("layerMapping.json"));
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
return;
|
||||
|
||||
const ExerciseManagement::Exercise exercise = exmDtc->exercise(m_pSession->exerciseId());
|
||||
const AssetManagement::TrainingArea ta = asmDtc->trainingArea(exercise.trainingAreaId());
|
||||
|
||||
// must be in sync with MapSettingsJson::fromJsonObject
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("mapUrls")] = descVecToArray(ta.map2D(), QStringLiteral("map2D"));
|
||||
obj[QStringLiteral("sceneUrls")] = descVecToArray(ta.scene3D(), QStringLiteral("scene3D"));
|
||||
obj[QStringLiteral("elevationUrls")] = descVecToArray(ta.elevation(), QStringLiteral("elevation"));
|
||||
obj[QStringLiteral("sceneObjectUrls")] = descVecToArray(ta.sceneObjects(), QStringLiteral("sceneObjects"));
|
||||
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
void ExportProcess::createDataJson(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const
|
||||
{
|
||||
// Add exercise to ExportRootPath
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Add exercise to ExportRootPath";
|
||||
QFile file(exportRootPath() + QStringLiteral("exercises.json"));
|
||||
if (!file.open(QFile::ReadWrite))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open " << file.fileName() << " for read/write: " << file.errorString();
|
||||
return;
|
||||
}
|
||||
QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
QJsonArray arr = obj[QStringLiteral("Exercises")].toArray();
|
||||
if (!arr.contains(m_pSession->exerciseId()) )
|
||||
arr.append(m_pSession->exerciseId());
|
||||
obj[QStringLiteral("Exercises")] = arr;
|
||||
file.resize(0);
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
INFO_LOG(m_logger) << " file.write " << QJsonDocument(obj).toJson(QJsonDocument::Indented);
|
||||
file.close();
|
||||
}
|
||||
//
|
||||
QFile file(exportPath(m_pSession->exerciseId()) + QStringLiteral("data.json"));
|
||||
INFO_LOG(m_logger) << "ExportProcess::createDataJson " << exportPath(m_pSession->exerciseId()) + QStringLiteral("data.json");
|
||||
if (!file.open(QFile::ReadWrite))
|
||||
return;
|
||||
|
||||
QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
|
||||
const ExerciseManagement::Exercise exercise = exmDtc->exercise(m_pSession->exerciseId());
|
||||
const AssetManagement::TrainingArea ta = asmDtc->trainingArea(exercise.trainingAreaId());
|
||||
|
||||
obj[QStringLiteral("title")] = QString::fromStdString(exercise.name());
|
||||
obj[QStringLiteral("exerciseName")] = QString::fromStdString(exercise.name());
|
||||
obj[QStringLiteral("exerciseId")] = exercise.id();
|
||||
obj[QStringLiteral("exerciseArea")] = QString::fromStdString(ta.name());
|
||||
obj[QStringLiteral("cycleTime")] = QString(QDateTime::fromMSecsSinceEpoch(exercise.startTime()).toString() +
|
||||
QStringLiteral(" - ") + QDateTime::fromMSecsSinceEpoch(exercise.stopTime()).toString());
|
||||
obj[QStringLiteral("exerciseStart")] = exercise.startTime();
|
||||
obj[QStringLiteral("exerciseEnd")] = exercise.stopTime();
|
||||
obj[QStringLiteral("exercisingForces")] = QString::fromStdString(exercise.forces());
|
||||
obj[QStringLiteral("exercisingPurpose")] = QString::fromStdString(exercise.description());
|
||||
|
||||
// TODO: administrativeInstructions, exerciseIncidents
|
||||
|
||||
QJsonArray presentations = obj[QStringLiteral("presentations")].toArray();
|
||||
const QString presPath = QString(QString::number(m_scriptId) + QStringLiteral("/presentation.json"));
|
||||
bool bPresFound = false;
|
||||
for (const QJsonValue &val : qAsConst(presentations))
|
||||
{
|
||||
const QJsonObject arrObj = val.toObject();
|
||||
if (arrObj[QStringLiteral("path")].toString() == presPath)
|
||||
{
|
||||
bPresFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bPresFound)
|
||||
{
|
||||
ExportedScriptInformation esi;
|
||||
esi.scriptId = m_scriptId;
|
||||
esi.scriptName = m_strScriptName;
|
||||
esi.exerciseName = m_strExerciseName;
|
||||
esi.jsonPath = presPath;
|
||||
esi.exportTime = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
|
||||
|
||||
presentations += esi.toJson();
|
||||
obj[QStringLiteral("presentations")] = presentations;
|
||||
}
|
||||
file.resize(0);
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
INFO_LOG(m_logger) << " file.write " << QJsonDocument(obj).toJson(QJsonDocument::Indented);
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ExportProcess::createPresentationTable()
|
||||
{
|
||||
// Order chronologically
|
||||
std::sort(m_vecExportStepsExecuted.begin(), m_vecExportStepsExecuted.end(),
|
||||
[](const TakeHomePackageGenerator::ExportStep * a, const TakeHomePackageGenerator::ExportStep * b) -> bool
|
||||
{
|
||||
return a->m_topicData.startTime < b->m_topicData.startTime;
|
||||
});
|
||||
QString presentationTableDirName = contentPath();
|
||||
presentationTableDirName.truncate(presentationTableDirName.size() - 1);
|
||||
QDir presentationDir(presentationTableDirName);
|
||||
if (!presentationDir.exists())
|
||||
{
|
||||
bool succ = presentationDir.mkdir(presentationTableDirName);
|
||||
if (!succ)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QFile file(contentPath() + QStringLiteral("presentation.json"));
|
||||
if (!file.open(QFile::WriteOnly | QFile::Truncate))
|
||||
return;
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("title")] = m_strScriptName;
|
||||
obj[QStringLiteral("exerciseName")] = m_strExerciseName;
|
||||
|
||||
QJsonArray topicArray;
|
||||
int topicId = 1;
|
||||
for (const TakeHomePackageGenerator::ExportStep *s : qAsConst(m_vecExportStepsExecuted))
|
||||
{
|
||||
if (s->exportFailed())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Export failed for " << s->topicId();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->m_topicData.topicType == TopicEditorBase::TopicType::SituationReplay ||
|
||||
s->m_topicData.topicType == TopicEditorBase::TopicType::TacticalPlan ||
|
||||
s->m_topicData.topicType == TopicEditorBase::TopicType::Situation ||
|
||||
s->filename().isEmpty())
|
||||
{
|
||||
/* these topics exported their data into an existing topic - e.g.:
|
||||
* Replay is put into a SituationMap topic, because a Replay topic
|
||||
* alone doesn't make sense in the THP, as to play a topic, all topic
|
||||
* information (Map, Replay, Filters, etc.) need to be inside ONE topic */
|
||||
continue;
|
||||
}
|
||||
|
||||
QJsonObject topicObj;
|
||||
topicObj[QStringLiteral("topicId")] = topicId++;
|
||||
topicObj[QStringLiteral("topicStart")] = QTime::fromMSecsSinceStartOfDay(s->m_topicData.startTime * 1000).toString();
|
||||
topicObj[QStringLiteral("duration")] = QTime::fromMSecsSinceStartOfDay(s->m_topicData.duration * 1000).toString();
|
||||
topicObj[QStringLiteral("type")] = TopicEditorBase::topicTypeString(s->m_topicData.topicType);
|
||||
|
||||
#ifndef EXPORT_BDV_TOPIC_AS_JSON
|
||||
if (s->m_topicData.topicType == TopicEditorBase::TopicType::Building)
|
||||
{
|
||||
QDir dir(s->filename());
|
||||
const auto listVideos = dir.entryList({QStringLiteral("*.mpg")}, QDir::Files, QDir::Name);
|
||||
for (const QString &strVideo : listVideos)
|
||||
{
|
||||
const QString relPath = QString::number(m_scriptId) + QLatin1Char('/') + dir.dirName() + QLatin1Char('/') + strVideo;
|
||||
topicObj[QStringLiteral("description")] = QJsonObject({{QStringLiteral("displayName"), strVideo},
|
||||
{QStringLiteral("href"), relPath}});
|
||||
topicArray += topicObj;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
QString dispName(s->m_topicData.description.isEmpty() ?
|
||||
TopicEditorBase::topicTypeString(s->m_topicData.topicType) :
|
||||
s->m_topicData.description);
|
||||
|
||||
if (s->m_topicData.topicType == TopicEditorBase::TopicType::Audio || s->m_topicData.topicType == TopicEditorBase::TopicType::Video)
|
||||
dispName = s->filename().splitRef(QLatin1Char('/')).last().toString();
|
||||
|
||||
if (!s->filename().isEmpty())
|
||||
{
|
||||
const QString stRelativeLinkToExportedFile(QString::number(m_scriptId) + QLatin1Char('/') +
|
||||
QString::number(s->topicId()) + QLatin1Char('/') +
|
||||
s->filename());
|
||||
|
||||
const QString stRelativeLinkToLocalExportedFile(QString::number(s->topicId()) + QLatin1Char('/') + s->filename());
|
||||
topicObj[QStringLiteral("description")] = QJsonObject({{QStringLiteral("displayName"), dispName},
|
||||
{QStringLiteral("href"), stRelativeLinkToExportedFile},
|
||||
{QStringLiteral("href_local"), stRelativeLinkToLocalExportedFile}
|
||||
});
|
||||
// topicObj[QStringLiteral("href")] = stRelativeLinkToExportedFile;
|
||||
// topicObj[QStringLiteral("href_local")] = stRelativeLinkToLocalExportedFile;
|
||||
}else
|
||||
{
|
||||
topicObj[QStringLiteral("description")] = QJsonObject({{ QStringLiteral("displayName"), dispName }});
|
||||
}
|
||||
|
||||
|
||||
topicArray += topicObj;
|
||||
}
|
||||
|
||||
obj[QStringLiteral("content")] = topicArray;
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ExportProcess::copyStaticContent() const
|
||||
{
|
||||
QString exportPathStr = exportPath(m_pSession->exerciseId());
|
||||
exportPathStr.truncate(exportPathStr.size() - 1);
|
||||
if (!NGL::copyDirContentsToDir(QStringLiteral("thp"), exportPathStr, true))
|
||||
WARNING_LOG(m_logger) << "Could not find thp static content directory exportPath=" << exportPathStr;
|
||||
if (!NGL::copyDirContentsToDir(QStringLiteral("thp_standalone"), exportPathStr + QDir::separator() + QString::number(m_scriptId), true))
|
||||
WARNING_LOG(m_logger) << "Could not find thp_standalone static content directory exportPath=" << exportPathStr + QDir::separator() + QString::number(m_scriptId);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <PresentationManagement/pre_dtc.h>
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include <AssetManagement/asm_dtc.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsScriptTimeline/track_content_widget.h>
|
||||
|
||||
|
||||
class QProgressDialog;
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
|
||||
class ExportStep;
|
||||
|
||||
struct ExportedScriptInformation
|
||||
{
|
||||
QString scriptName;
|
||||
QString exerciseName;
|
||||
QString jsonPath;
|
||||
qint64 exportTime = 0;
|
||||
int scriptId = 0;
|
||||
|
||||
int id() const { return scriptId; }
|
||||
|
||||
QJsonValue toJson() const;
|
||||
};
|
||||
|
||||
|
||||
class PREGUISCRIPTCOMMON_EXPORT ExportProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportProcess(LtsSession::LtsSession *pSession,
|
||||
const std::shared_ptr<SituationReplay::ForeignGuiInterface> &replayGuiIfc,
|
||||
QProgressDialog *pProgressDlg,
|
||||
const QString &strScriptName,
|
||||
const QString &strExerciseName,
|
||||
int scriptId,
|
||||
const std::vector<PresentationManagement::PresentationContent> &contentList,
|
||||
const QMap<QString, PresentationManagement::TopicAssignment> &trackEntryAssignments,
|
||||
QObject *parent);
|
||||
~ExportProcess();
|
||||
|
||||
static QString exportPath(const int exerciseId);
|
||||
static QString exportRootPath();
|
||||
|
||||
signals:
|
||||
void exportSuccessful(const QString &m_strExportPath, const QString &failedTopicsDescription);
|
||||
|
||||
public slots:
|
||||
void slotStartExport();
|
||||
|
||||
private slots:
|
||||
void slotCancel();
|
||||
void slotRunExportStep();
|
||||
|
||||
private:
|
||||
QVector<ExportStep *> parseFilterSteps(
|
||||
int parentTopicId, QJsonObject &detailData, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
);
|
||||
QVector<ExportStep *> checkAdditionalExportEntries(
|
||||
int realParentId, const TopicEditorBase::TopicData &parentData, QJsonArray &filterLines,
|
||||
TopicReplay::Interface *parentTopicReplayIfc, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes,
|
||||
bool &keepOriginalTopic
|
||||
);
|
||||
ExportStep *createExportStep(
|
||||
int parentTopicId, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicExportIfc,
|
||||
const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
);
|
||||
|
||||
enum class ExportOrReplay
|
||||
{
|
||||
Export,
|
||||
Replay
|
||||
};
|
||||
|
||||
TopicReplay::Interface *topicIfcFromType(TopicEditorBase::TopicType type, ExportOrReplay exportOrReplay) const;
|
||||
QString contentPath() const { return exportPath(m_pSession->exerciseId()) + QString::number(m_scriptId) + QLatin1Char('/'); }
|
||||
void exportDone();
|
||||
void createJsonFiles();
|
||||
void createLayerMappings(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const;
|
||||
void createDataJson(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const;
|
||||
void createPresentationTable();
|
||||
void copyStaticContent() const;
|
||||
|
||||
private:
|
||||
QVector<ExportStep *> m_vecExportSteps;
|
||||
QVector<ExportStep *> m_vecExportStepsExecuted;
|
||||
|
||||
std::vector<PresentationManagement::PresentationContent> m_contentList;
|
||||
QMap<QString, PresentationManagement::TopicAssignment> m_trackEntryAssignments;
|
||||
QString m_strScriptName;
|
||||
QString m_strExerciseName;
|
||||
int m_scriptId;
|
||||
|
||||
LtsSession::LtsSession *m_pSession;
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> m_replayGuiIfc;
|
||||
QProgressDialog *m_pProgressDlg;
|
||||
int m_cntTopicsToExport;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
}
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "export_step.h"
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
ExportStep::ExportStep(QObject *parent, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicReplayIfc)
|
||||
: QObject(parent)
|
||||
, m_topicData(data)
|
||||
, m_notifier(this)
|
||||
, m_topicReplayIfc(topicReplayIfc)
|
||||
, m_timer(new QTimer(this))
|
||||
, m_parentTopicId(-1)
|
||||
, m_exportFailed(false)
|
||||
{
|
||||
m_timer->setSingleShot(true);
|
||||
m_timer->setInterval(30 * 1000); // 30s timeout
|
||||
connect(m_timer, &QTimer::timeout, this, &ExportStep::slotExportFailed);
|
||||
|
||||
connect(&m_notifier, &TopicEditorBase::ExportNotifier::stillAlive, this, &ExportStep::slotResetTimer);
|
||||
connect(&m_notifier, &TopicEditorBase::ExportNotifier::exportSuccessful, this, &ExportStep::slotExportSuccessful);
|
||||
connect(&m_notifier, &TopicEditorBase::ExportNotifier::exportFailed, this, &ExportStep::slotExportFailed);
|
||||
}
|
||||
|
||||
|
||||
ExportStep::~ExportStep()
|
||||
{
|
||||
m_timer->stop();
|
||||
delete m_topicReplayIfc;
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::startExport(const QString &strExportPath)
|
||||
{
|
||||
m_timer->start();
|
||||
m_topicReplayIfc->setExportPlaybackTimes(m_topicData.startTime, m_topicData.duration, m_sitReplayTimes);
|
||||
m_topicReplayIfc->setBasePath(m_basePath);
|
||||
m_topicReplayIfc->exportTopic(m_topicData.properties, strExportPath, &m_notifier);
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::slotResetTimer()
|
||||
{
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::slotExportFailed()
|
||||
{
|
||||
m_timer->stop();
|
||||
m_exportFailed = true;
|
||||
m_notifier.disconnect(); // Export failed e.g. due to timeout. We do not want to get a "success signal" seconds later. Timeout is timeout, fail is fail, later success does not matter
|
||||
emit signalExportFailed();
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::slotExportSuccessful(const QString &strFilename)
|
||||
{
|
||||
m_timer->stop();
|
||||
m_strFileName = strFilename;
|
||||
m_notifier.disconnect();
|
||||
emit signalExportSuccessful();
|
||||
}
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <Common/TopicEditorBase/topic_editor_base.h>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class PREGUISCRIPTCOMMON_EXPORT ExportStep : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportStep(QObject *parent, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicReplayIfc);
|
||||
~ExportStep();
|
||||
|
||||
void startExport(const QString &strExportPath);
|
||||
void setSituationReplayTimes(const QVector<TopicReplay::Interface::SituationReplayTime> ×) { m_sitReplayTimes = times; }
|
||||
void setParentTopicId(int parentId) { m_parentTopicId = parentId; }
|
||||
void setBasePath(const QString &basePath) { m_basePath = basePath; }
|
||||
int topicId() const { return m_parentTopicId < 0 ? m_topicData.id : m_parentTopicId; }
|
||||
bool exportFailed() const { return m_exportFailed; }
|
||||
QString filename() const { return m_strFileName; }
|
||||
|
||||
// wtf?
|
||||
TopicEditorBase::TopicData m_topicData;
|
||||
|
||||
signals:
|
||||
void signalExportSuccessful();
|
||||
void signalExportFailed();
|
||||
|
||||
private slots:
|
||||
void slotResetTimer();
|
||||
void slotExportSuccessful(const QString &strFilename);
|
||||
void slotExportFailed();
|
||||
|
||||
private:
|
||||
QVector<TopicReplay::Interface::SituationReplayTime> m_sitReplayTimes;
|
||||
QString m_strFileName;
|
||||
QString m_basePath;
|
||||
TopicEditorBase::ExportNotifier m_notifier;
|
||||
TopicReplay::Interface *m_topicReplayIfc;
|
||||
|
||||
QTimer *m_timer;
|
||||
int m_parentTopicId;
|
||||
bool m_exportFailed;
|
||||
};
|
||||
}
|
||||
Lts/Plugins/PresentationManagement/Gui/Script/Common/TakeHomePackageGenerator/situation_exporter.cpp
Executable
+234
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Export data from postgresql database to sqlite
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
|
||||
|
||||
#include "situation_exporter.h"
|
||||
#include "db_reader.h"
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QSqlRecord>
|
||||
#include <QSqlError>
|
||||
#include <QSqlField>
|
||||
#include <QSqlIndex>
|
||||
#include <QSqlDatabase>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
SituationExporter::SituationExporter(int exerciseId)
|
||||
: m_exerciseId(exerciseId)
|
||||
, m_logger(PresentationManagement::getLogger("SituationExporter"))
|
||||
{}
|
||||
|
||||
SituationExporter::~SituationExporter()
|
||||
{
|
||||
const QString dbConInName = m_dbIn.connectionName();
|
||||
const QString dbConOutName = m_dbOut.connectionName();
|
||||
m_dbIn.close();
|
||||
m_dbOut.close();
|
||||
m_dbIn = QSqlDatabase();
|
||||
m_dbOut = QSqlDatabase();
|
||||
if (!dbConInName.isEmpty())
|
||||
QSqlDatabase::removeDatabase(dbConInName);
|
||||
if (!dbConOutName.isEmpty())
|
||||
QSqlDatabase::removeDatabase(dbConOutName);
|
||||
}
|
||||
|
||||
bool SituationExporter::exportStaticData(const QString &strPathToFile)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Exporting static data to " << strPathToFile;
|
||||
m_dbIn.close();
|
||||
m_dbOut.close();
|
||||
|
||||
QString str;
|
||||
NGL::Settings s(str); // FIXME
|
||||
// open postgres db, read table structure, read static data
|
||||
const QString dbUser(QStringLiteral("postgres"));
|
||||
const QString dbPasswd(QStringLiteral("postgres"));
|
||||
m_dbIn = DBConnection::open(m_logger,
|
||||
dbUser,
|
||||
dbPasswd,
|
||||
s.databaseDriver(),
|
||||
s.databaseHostname(),
|
||||
s.databaseName());
|
||||
if (!m_dbIn.isOpen())
|
||||
return false;
|
||||
|
||||
// open sqlite db, create tables, write static data
|
||||
QFile::remove(strPathToFile);
|
||||
m_dbOut = DBConnection::open(m_logger,
|
||||
QString(),
|
||||
QString(),
|
||||
QStringLiteral("QSQLITE"),
|
||||
QString(),
|
||||
strPathToFile);
|
||||
if (!m_dbOut.isOpen())
|
||||
return false;
|
||||
|
||||
DBTransaction transOut(m_dbOut);
|
||||
|
||||
//const int fileTypeId = FileManagement::FileType::TacticalPlan;
|
||||
constexpr int fileTypeTacticalPlan = 6;
|
||||
constexpr int fileTypeOperatorDefinedSymbol = 8;
|
||||
const QVector<StaticTableToCopy> staticTables =
|
||||
{{QStringLiteral("asm"), QStringLiteral("asm_training_area"), QString()},
|
||||
|
||||
{QStringLiteral("exm"), QStringLiteral("exercise"), QStringLiteral("id = %1").arg(m_exerciseId)},
|
||||
{QStringLiteral("exm"), QStringLiteral("exercise_phase"), QStringLiteral("exercise_id = %1").arg(m_exerciseId)},
|
||||
|
||||
{QStringLiteral("flm"), QStringLiteral("flm_file_content"), QStringLiteral("(file_type_id = %1 OR file_type_id = %2) AND file_status_id = 0").arg(fileTypeTacticalPlan).arg(fileTypeOperatorDefinedSymbol)},
|
||||
{QStringLiteral("flm"), QStringLiteral("flm_file_type_info"), QString()},
|
||||
{QStringLiteral("flm"), QStringLiteral("flm_folder"), QString()},
|
||||
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_main_structure_element"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_structure_element"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_structure_element_type"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_mounting_point_type"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_structure_element_footprint"), QString()},
|
||||
|
||||
{QStringLiteral("ppm"), QStringLiteral("ppm_type"), QString()},
|
||||
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_can_component_string"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_charge_type"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_fire_purpose"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_gear_type"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_gear_type_charge_type"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_language_hmi"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_translation"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_vulnerability_kind"), QString()}
|
||||
};
|
||||
for (const auto &t : staticTables)
|
||||
{
|
||||
if (!copyTable(t, false))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Copying table " << t.schema << "." << t.table << " failed... ";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const QString exerciseSchema = DBCommon::getExerciseSchemaName(m_exerciseId);
|
||||
const QVector<StaticTableToCopy> srpTables =
|
||||
{{exerciseSchema, QStringLiteral("flt_aes_filter"), QString()},
|
||||
{exerciseSchema, QStringLiteral("flt_symbol_appearance"), QString()},
|
||||
{exerciseSchema, QStringLiteral("srp_situation_replay"), QString()},
|
||||
{exerciseSchema, QStringLiteral("srp_replay_journal"), QString()},
|
||||
{exerciseSchema, QStringLiteral("rec_snapshot"), QString()}
|
||||
};
|
||||
for (const auto &t : srpTables)
|
||||
{
|
||||
if (!copyTable(t, true))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Copying table " << t.schema << "." << t.table << " failed... ";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
transOut.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationExporter::exportDynamicData(qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
DbReader dbReader(m_exerciseId);
|
||||
if (!dbReader.init(m_dbIn, m_dbOut))
|
||||
return false;
|
||||
|
||||
DBTransaction trans(m_dbOut);
|
||||
if (!dbReader.createTables() || !dbReader.copyData(fromTime, toTime)) // todo: !
|
||||
return false;
|
||||
QString stmtUpdateExercise = QStringLiteral("UPDATE exercise SET begin_time = :begin_time, end_time = :end_time");
|
||||
NSqlQuery q(m_dbOut);
|
||||
if (!q.prepare(stmtUpdateExercise))
|
||||
return false;
|
||||
q.bindValue(QStringLiteral("begin_time"), fromTime);
|
||||
q.bindValue(QStringLiteral("end_time"), toTime);
|
||||
if (!q.exec())
|
||||
return false;
|
||||
trans.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationExporter::copyTable(const StaticTableToCopy &t, bool bOnlyCreateSchema)
|
||||
{
|
||||
NSqlQuery qIn(m_dbIn);
|
||||
NSqlQuery qOut(m_dbOut);
|
||||
|
||||
const QString fqTableName(t.schema.isEmpty() ? t.table : (t.schema + QLatin1Char('.') + t.table));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Copying " << fqTableName << " started";
|
||||
const QSqlRecord record = m_dbIn.record(fqTableName);
|
||||
if (record.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Empty record for " << fqTableName;
|
||||
return false;
|
||||
}
|
||||
QStringList selectTableColumns;
|
||||
QStringList insertTablePlaceholder;
|
||||
selectTableColumns.reserve(record.count());
|
||||
insertTablePlaceholder.reserve(record.count());
|
||||
for (int i = 0; i < record.count(); ++i)
|
||||
{
|
||||
const QSqlField &f = record.field(i);
|
||||
selectTableColumns += f.name();
|
||||
insertTablePlaceholder += QLatin1Char(':') + f.name();
|
||||
}
|
||||
|
||||
const QSqlIndex pk = m_dbIn.primaryIndex(fqTableName);
|
||||
if (!DbReader::createTable(qOut, t.table, record, pk, m_logger))
|
||||
return false;
|
||||
|
||||
if (bOnlyCreateSchema)
|
||||
return true;
|
||||
|
||||
// do not copy tables without schemaName
|
||||
if (t.schema.isEmpty())
|
||||
return true;
|
||||
|
||||
const QString whereStmt(t.where.isEmpty() ? QString() : QStringLiteral(" WHERE %1").arg(t.where));
|
||||
const QString selectTableCommand(QStringLiteral("SELECT %1 FROM %2%3")
|
||||
.arg(selectTableColumns.join(QStringLiteral(", ")), fqTableName, whereStmt));
|
||||
const QString insertTableCommand(QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)")
|
||||
.arg(t.table,
|
||||
selectTableColumns.join(QStringLiteral(", ")),
|
||||
insertTablePlaceholder.join(QStringLiteral(", "))));
|
||||
|
||||
DEBUG_LOG(m_logger) << selectTableCommand;
|
||||
DEBUG_LOG(m_logger) << insertTableCommand;
|
||||
|
||||
if (!qOut.prepare(insertTableCommand))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "qOut prepare failed... " << qOut.lastError().text();
|
||||
return false;
|
||||
}
|
||||
if (!qIn.exec(selectTableCommand))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "qIn select failed... " << qIn.lastError().text();
|
||||
return false;
|
||||
}
|
||||
while (qIn.next())
|
||||
{
|
||||
for (int i = 0; i < insertTablePlaceholder.size(); ++i)
|
||||
qOut.bindValue(insertTablePlaceholder.at(i), qIn.value(i));
|
||||
if (!qOut.exec())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "qOut insert failed.. " << qOut.lastError().text();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Copying " << fqTableName << " finished";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageGenerator
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Export data from postgresql database to sqlite
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include <QString>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class SituationExporter
|
||||
{
|
||||
public:
|
||||
explicit SituationExporter(int exerciseId);
|
||||
~SituationExporter();
|
||||
|
||||
bool exportStaticData(const QString& strPathToFile);
|
||||
bool exportDynamicData(qint64 fromTime, qint64 toTime);
|
||||
|
||||
private:
|
||||
struct StaticTableToCopy
|
||||
{
|
||||
QString schema;
|
||||
QString table;
|
||||
QString where;
|
||||
};
|
||||
|
||||
bool copyTable(const StaticTableToCopy &t, bool bOnlyCreateSchema);
|
||||
private:
|
||||
int m_exerciseId;
|
||||
QSqlDatabase m_dbIn;
|
||||
QSqlDatabase m_dbOut;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace TakeHomePackageGenerator
|
||||
Reference in new issue
Block a user