Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+17
View File
@@ -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
)
@@ -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
Qt5::Core
Qt5::Concurrent
NGLLogger
LtsSession
AsmDataPluginInterface
ExmDataPluginInterface
#nglcompression
#nglsettings
#ngltools
#LtsSessionData
#httq
)
NGL_INSTALL_TARGET(ThpCommon)
@@ -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
View File
@@ -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
@@ -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
@@ -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;
};
}
@@ -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
@@ -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
@@ -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>
@@ -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
Qt5::Widgets
Qt5::Network
Qt5::WebSockets
NGLLogger
LtsWidgets
LtsSession
LtsDataView
nglcompression
nglsettings
ngltools
AsmDataPluginInterface
ExmDataPluginInterface
LtsSessionData
httq
)
NGL_INSTALL_TARGET(ThpManagementGuiPlugin)
@@ -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
@@ -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
File diff suppressed because it is too large. Load diff
@@ -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
@@ -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>
@@ -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
@@ -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
@@ -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
Qt5::Widgets
Qt5::Network
Qt5::WebSockets
NGLLogger
LtsWidgets
LtsSession
LtsDataView
nglcompression
nglsettings
ngltools
LtsSessionData
# for creating data.json
AsmDataPluginInterface
ExmDataPluginInterface
)
NGL_INSTALL_TARGET(ThpUsbManagementGuiPlugin)
@@ -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
@@ -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
File diff suppressed because it is too large. Load diff
@@ -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
@@ -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>
@@ -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
//
@@ -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
@@ -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