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

@@ -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>