Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# $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, 2024-01-11
|
||||
#
|
||||
|
||||
SET(src
|
||||
#logger.cpp
|
||||
#logger.h
|
||||
tpm_js_parser.cpp
|
||||
tpm_js_parser.h
|
||||
tpm_tools.cpp
|
||||
tpm_tools.h
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY2(WS SV Thp2CommonCore SHARED ${src}) # SV because FLM Service (httq server) uses Thp2CommonCore, too
|
||||
NGL_TARGET_COMPILE_DEFINITIONS(Thp2CommonCore PRIVATE L=QStringLiteral)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(Thp2CommonCore
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../ # export file
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(Thp2CommonCore
|
||||
PRIVATE
|
||||
Qt5::Core
|
||||
#NGLLogger
|
||||
LtsUtilsCoreHeaderOnly
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(Thp2CommonCore)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @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 $
|
||||
*
|
||||
* Created by Mike Wille, SLTE, 2024-01-11
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "TPM2.CommonCore.";
|
||||
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,24 @@
|
||||
/**
|
||||
* @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 $
|
||||
*
|
||||
* Created by Mike Wille, SLTE, 2024-01-11
|
||||
*/
|
||||
|
||||
#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,544 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* topics.js parser
|
||||
* $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 Mike Wille, EZSZ, 2024-02-12
|
||||
*/
|
||||
|
||||
#include "tpm_js_parser.h"
|
||||
|
||||
//#include <logger.h>
|
||||
#include <tpm_tools.h>
|
||||
|
||||
#include <LtsUtilsCore/json.h>
|
||||
|
||||
#include <QMapIterator>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::string error(const QString &msg) { return msg.toStdString(); }
|
||||
using namespace std;
|
||||
#ifndef DLOG
|
||||
#define DLOG DEBUG_LOG(m_logger)
|
||||
#endif
|
||||
using namespace LtsUtils;
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
/// JsObjectParser
|
||||
template<>
|
||||
/*static*/ JsonObject JsParser<JsonObject, QJsonObject>::parse(const QByteArray &data) noexcept(false)
|
||||
{
|
||||
return JsonObject::fromJsonSafe(_parse(data, true).toUtf8());
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
JsParser<JsonObject, QJsonObject>::JsParser(const QString &globalThisName, const QString &filePath, bool mustExist) noexcept(false)
|
||||
: m_globalThisName(globalThisName)
|
||||
, m_filePath(filePath)
|
||||
, m_json(load(mustExist))
|
||||
//, m_logger(getLogger("JsObjectParser"))
|
||||
{
|
||||
qWarning() << "OBJECT - m_globalThisName" << m_globalThisName << "m_filePath" << m_filePath << "m_json" << m_json.object().count();
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
QJsonDocument JsParser<JsonObject, QJsonObject>::document() const
|
||||
{
|
||||
return QJsonDocument(static_cast<const QJsonObject &>(m_json));
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
/*static*/ const QJsonObject &JsParser<JsonObject, QJsonObject>::get() const
|
||||
{
|
||||
return m_json;
|
||||
}
|
||||
|
||||
|
||||
///// JsArrayParser
|
||||
template<>
|
||||
/*static*/ JsonArray JsParser<JsonArray, QJsonArray>::parse(const QByteArray &data) noexcept(false)
|
||||
{
|
||||
return JsonArray::fromJsonSafe(_parse(data, false).toUtf8());
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
JsParser<JsonArray, QJsonArray>::JsParser(const QString &globalThisName, const QString &filePath, bool mustExist) noexcept(false)
|
||||
: m_globalThisName(globalThisName)
|
||||
, m_filePath(filePath)
|
||||
, m_json(load(mustExist))
|
||||
//, m_logger(getLogger("JsArrayParser"))
|
||||
{
|
||||
qWarning() << "ARRAY - m_globalThisName" << m_globalThisName << "m_filePath" << m_filePath << "m_json" << m_json.size();
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
QJsonDocument JsParser<JsonArray, QJsonArray>::document() const
|
||||
{
|
||||
return QJsonDocument(m_json());
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
/*static*/ const QJsonArray &JsParser<JsonArray, QJsonArray>::get() const
|
||||
{
|
||||
return m_json();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// JsParser
|
||||
template<typename LtsJsonType, typename QJsonType>
|
||||
void JsParser<LtsJsonType, QJsonType>::save() noexcept(false)
|
||||
{
|
||||
if (!m_dataChanged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto file(openSaveFile(m_filePath)); // throws (incl. dtor)
|
||||
file->write(L("globalThis.%1 = \n").arg(m_globalThisName).toUtf8());
|
||||
file->write(document().toJson(QJsonDocument::JsonFormat::Indented /* adds \n to the end */));
|
||||
file->write(";");
|
||||
}
|
||||
|
||||
|
||||
template<typename LtsJsonType, typename QJsonType>
|
||||
/*static*/ QByteArray JsParser<LtsJsonType, QJsonType>:: _load(bool mustExist) const noexcept(false)
|
||||
{
|
||||
const auto data(readFile(m_filePath, mustExist));
|
||||
|
||||
qWarning() << "JsParser: file" << m_filePath << "######################## content:" << data;
|
||||
|
||||
if (data.isEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
template<typename LtsJsonType, typename QJsonType>
|
||||
/*static*/ QString JsParser<LtsJsonType, QJsonType>::_parse(const QByteArray &data, bool isObject) noexcept(false)
|
||||
{
|
||||
const QString opener((isObject) ? L("{") : L("["));
|
||||
const QString closer((isObject) ? L("}") : L("]"));
|
||||
|
||||
const QRegExp regexp(L(R"RRR(\%1[\S\s]*\%2)RRR").arg(opener, closer));
|
||||
const QString topicsJsText(QString::fromUtf8(data));
|
||||
//DLOG << "topicsJsText: " << topicsJsText;
|
||||
|
||||
if (regexp.indexIn(topicsJsText) < 0)
|
||||
{
|
||||
//throw runtime_error(L("no %1 with name '%2' in js-file '%3' found").arg(isObject ? L("object") : L("array").arg(globalThisName, filePath).toStdString());
|
||||
throw runtime_error(L("no %1 in js-file found").arg(isObject ? L("object") : L("array")).toStdString());
|
||||
}
|
||||
|
||||
// js file, not a json file, so get the first '[' and the last ']' to get the pure json compatible data structure from the incompatible javascript (see regexp pattern above)
|
||||
const QString jsonString(regexp.cap());
|
||||
//DLOG << "jsonString: " << jsonString;
|
||||
|
||||
qWarning() << "jsonString" << jsonString;
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
|
||||
template<typename LtsJsonType, typename QJsonType>
|
||||
/*static*/ LtsJsonType JsParser<LtsJsonType, QJsonType>::load(bool mustExist) const noexcept(false)
|
||||
{
|
||||
auto data = _load(mustExist);
|
||||
|
||||
if (data.isEmpty())
|
||||
{
|
||||
if (mustExist)
|
||||
{
|
||||
throw runtime_error("js-file is missing content");
|
||||
}
|
||||
|
||||
qWarning() << ":(";
|
||||
return {};
|
||||
}
|
||||
|
||||
return parse(data);
|
||||
}
|
||||
|
||||
|
||||
template<typename LtsJsonType, typename QJsonType>
|
||||
/*static*/ void JsParser<LtsJsonType, QJsonType>::write(const QString &globalThisName, const QJsonType &json, const QString &filePath, bool mustExist) noexcept(false)
|
||||
{
|
||||
auto parser = JsParser<LtsJsonType, QJsonType>(globalThisName, filePath, mustExist);
|
||||
parser.set(json);
|
||||
parser.save();
|
||||
}
|
||||
template void JsParser<JsonObject, QJsonObject>::write(const QString &globalThisName, const QJsonObject &json, const QString &filePath, bool mustExist) noexcept(false);
|
||||
template void JsParser<JsonArray, QJsonArray>::write(const QString &globalThisName, const QJsonArray &json, const QString &filePath, bool mustExist) noexcept(false);
|
||||
|
||||
|
||||
template<typename LtsJsonType, typename QJsonType>
|
||||
void JsParser<LtsJsonType, QJsonType>::set(const QJsonType &json)
|
||||
{
|
||||
m_json = LtsJsonType(json);
|
||||
m_dataChanged = true;
|
||||
}
|
||||
template void JsParser<JsonObject, QJsonObject>::set(const QJsonObject &json);
|
||||
template void JsParser<JsonArray, QJsonArray>::set(const QJsonArray &json);
|
||||
|
||||
|
||||
template<typename LtsJsonType, typename QJsonType>
|
||||
/*static*/ QJsonType JsParser<LtsJsonType, QJsonType>::read(const QString &globalThisName, const QString &filePath, bool mustExist) noexcept(false)
|
||||
{
|
||||
return JsParser(globalThisName, filePath, mustExist).get();
|
||||
}
|
||||
template QJsonObject JsParser<JsonObject, QJsonObject>::read(const QString &globalThisName, const QString &filePath, bool mustExist) noexcept(false);
|
||||
template QJsonArray JsParser<JsonArray, QJsonArray>::read(const QString &globalThisName, const QString &filePath, bool mustExist) noexcept(false);
|
||||
|
||||
|
||||
|
||||
/// ScriptsJsParser
|
||||
ScriptsJsParser::ScriptsJsParser(const QString &root, bool mustExist) noexcept(false)
|
||||
: JsObjectParser(L("scriptsJs"), scriptsJsLocation(root), mustExist)
|
||||
{
|
||||
const QJsonObject obj(get());
|
||||
qWarning() << "ScriptsJsParser" << obj;
|
||||
|
||||
for (auto it = obj.constBegin(); it != obj.constEnd(); ++it)
|
||||
{
|
||||
const auto esi(ExportedScriptInformation::fromJson(it.value(), true /* local */, ExportedScriptInformation::UploadState::ThpUnknownUploadState));
|
||||
qWarning() << "adding" << esi.id();
|
||||
//DEBUG_LOG(m_logger) << "obj=" << QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
|
||||
//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_esis.insert(esi.id(), esi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//ScriptsJsParser::~ScriptsJsParser() noexcept(false)
|
||||
void ScriptsJsParser::save() noexcept(false)
|
||||
{
|
||||
QJsonObject obj;
|
||||
|
||||
QMapIterator<QString, ExportedScriptInformation> it(m_esis);
|
||||
while (it.hasNext())
|
||||
{
|
||||
auto &esi = it.next().value();
|
||||
obj.insert(esi.id(), esi.toJson());
|
||||
}
|
||||
|
||||
set(obj);
|
||||
JsParser::save();
|
||||
}
|
||||
|
||||
|
||||
const QMap<QString, ExportedScriptInformation> &ScriptsJsParser::getExportedScriptInformations() const
|
||||
{
|
||||
return m_esis;
|
||||
}
|
||||
|
||||
|
||||
const ExportedScriptInformation &ScriptsJsParser::getExportedScriptInformation(const QString &scriptId) const noexcept(false)
|
||||
{
|
||||
auto it = m_esis.constFind(scriptId);
|
||||
|
||||
if (it == m_esis.constEnd())
|
||||
{
|
||||
throw L("getExportedScriptInformation: script with id '%1' not found").arg(scriptId);
|
||||
}
|
||||
|
||||
return it.value();
|
||||
}
|
||||
|
||||
|
||||
bool ScriptsJsParser::hasExportedScriptInformation(const QString &scriptId) const
|
||||
{
|
||||
return m_esis.contains(scriptId);
|
||||
}
|
||||
|
||||
|
||||
void ScriptsJsParser::setExportedScriptInformations(const QVector<ExportedScriptInformation> &esis) noexcept(false)
|
||||
{
|
||||
m_esis.clear();
|
||||
addExportedScriptInformations(esis);
|
||||
}
|
||||
|
||||
|
||||
void ScriptsJsParser::addExportedScriptInformations(const QVector<ExportedScriptInformation> &esis) noexcept(false)
|
||||
{
|
||||
for (const ExportedScriptInformation &esi : esis)
|
||||
addExportedScriptInformation(esi);
|
||||
}
|
||||
|
||||
|
||||
void ScriptsJsParser::addExportedScriptInformation(const ExportedScriptInformation &esi) noexcept(false)
|
||||
{
|
||||
m_esis.insert(esi.id(), esi);
|
||||
m_dataChanged = true;
|
||||
}
|
||||
|
||||
|
||||
void ScriptsJsParser::removeExportedScriptInformation(const QString &scriptId) noexcept(false)
|
||||
{
|
||||
if (m_esis.remove(scriptId) != 1)
|
||||
{
|
||||
throw L("removeExportedScriptInformation: unable to remove script with id '%1' because it was not found").arg(scriptId);
|
||||
}
|
||||
|
||||
m_dataChanged = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///// TopicsJsParser
|
||||
//TopicsJsParser::TopicsJsParser(const QString &root, bool mustExist) noexcept(false)
|
||||
// : JsArrayParser(L("topicsJs"), scriptsJsLocation(root), mustExist)
|
||||
//{
|
||||
// const auto topics = Topic::topicsFromJson(get());
|
||||
// qWarning() << "TopicsJsParser: topics " << topics.count();
|
||||
|
||||
// for (const auto &topic : topics)
|
||||
// {
|
||||
// qWarning() << "adding" << topic.id;
|
||||
// m_topics.insert(topic.id, topic);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
//void TopicsJsParser::save() noexcept(false)
|
||||
//{
|
||||
// QJsonArray arr;
|
||||
|
||||
// QMapIterator<int, Topic> it(m_topics);
|
||||
// while (it.hasNext())
|
||||
// {
|
||||
// auto &topic = it.next().value();
|
||||
// arr += topic.toJson();
|
||||
// }
|
||||
|
||||
// set(arr);
|
||||
// JsParser::save();
|
||||
//}
|
||||
|
||||
|
||||
//const QMap<int, Topic> &TopicsJsParser::getTopics() const
|
||||
//{
|
||||
// return m_topics;
|
||||
//}
|
||||
|
||||
|
||||
//const Topic &TopicsJsParser::getTopic(const int topicId) const noexcept(false)
|
||||
//{
|
||||
// auto it = m_topics.constFind(topicId);
|
||||
|
||||
// if (it == m_topics.constEnd())
|
||||
// {
|
||||
// throw L("getTopic: topic with id '%1' not found").arg(topicId);
|
||||
// }
|
||||
|
||||
// return it.value();
|
||||
//}
|
||||
|
||||
|
||||
//bool TopicsJsParser::hasTopic(const int topicId) const
|
||||
//{
|
||||
// return m_topics.contains(topicId);
|
||||
//}
|
||||
|
||||
|
||||
//void TopicsJsParser::setTopics(const QVector<Topic> &topics) noexcept(false)
|
||||
//{
|
||||
// m_topics.clear();
|
||||
// addTopics(topics);
|
||||
//}
|
||||
|
||||
|
||||
//void TopicsJsParser::addTopics(const QVector<Topic> &topics) noexcept(false)
|
||||
//{
|
||||
// for (const Topic &topic : topics)
|
||||
// addTopic(topic);
|
||||
//}
|
||||
|
||||
|
||||
//void TopicsJsParser::addTopic(const Topic &topic) noexcept(false)
|
||||
//{
|
||||
// m_topics.insert(topic.id, topic);
|
||||
// m_dataChanged = true;
|
||||
//}
|
||||
|
||||
|
||||
//void TopicsJsParser::removeTopic(const int topicId) noexcept(false)
|
||||
//{
|
||||
// if (m_topics.remove(topicId) != 1)
|
||||
// {
|
||||
// throw L("removeTopic: unable to remove topic with id '%1' because it was not found").arg(topicId);
|
||||
// }
|
||||
|
||||
// m_dataChanged = true;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
/// ExportedScriptInformation
|
||||
QJsonObject dateTimeToJson(const QDateTime &dt)
|
||||
{
|
||||
return { { L("iso"), dt.toUTC().toString(Qt::DateFormat::ISODate) }, { L("secsSinceEpoch"), dt.toSecsSinceEpoch() } };
|
||||
}
|
||||
|
||||
|
||||
QDateTime jsonToDateTime(const QJsonValue &val) noexcept(false)
|
||||
{
|
||||
bool k = false;
|
||||
auto ret = QDateTime::fromSecsSinceEpoch(val.toObject()[L("secsSinceEpoch")].toVariant().toULongLong(&k));
|
||||
|
||||
if (!k)
|
||||
{
|
||||
throw std::runtime_error("jsonToDateTime: !k");
|
||||
}
|
||||
|
||||
if (!ret.isValid())
|
||||
{
|
||||
throw std::runtime_error("jsonToDateTime: !ret.isValid()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QString ExportedScriptInformation::id() const
|
||||
{
|
||||
return L("%1.%2%3").arg(exercise.id).arg(script.id).arg(script.customName.isEmpty() ? QString() : L("-%1").arg(script.customName));
|
||||
}
|
||||
|
||||
|
||||
QJsonValue ExportedScriptInformation::toJson() const
|
||||
{
|
||||
QJsonObject ret({
|
||||
{ L("createdAt"), dateTimeToJson(createdAt) },
|
||||
{ L("exerciseId"), exercise.id },
|
||||
{ L("exerciseName"), exercise.name },
|
||||
{ L("scriptId"), script.id },
|
||||
{ L("scriptName"), script.name }
|
||||
});
|
||||
|
||||
if (!script.customName.isEmpty()) // js's '...' operator would be very handy here
|
||||
{
|
||||
ret[L("scriptCustomName")] = script.customName; // optional, needed for usb exports where some topics were unselected by the user
|
||||
}
|
||||
|
||||
// if (uploadedAt.isValid())
|
||||
// ret[L("uploadedAt")] = dateTimeToJson(uploadedAt);
|
||||
// if (downloadedAt.isValid())
|
||||
// ret[L("downloadedAt")] = dateTimeToJson(downloadedAt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ExportedScriptInformation ExportedScriptInformation::fromJson(const QJsonValue &val,
|
||||
const bool local,
|
||||
const UploadState uploadState) noexcept(false)
|
||||
{
|
||||
const QJsonObject obj(val.toObject());
|
||||
|
||||
ExportedScriptInformation esi;
|
||||
|
||||
const auto createdAt = jsonToDateTime(obj[L("createdAt")]);
|
||||
|
||||
if (local)
|
||||
{
|
||||
esi.createdAt = createdAt;
|
||||
}
|
||||
|
||||
if (uploadState == UploadState::ThpAlreadyUploaded)
|
||||
{
|
||||
esi.createdAtServer = createdAt;
|
||||
}
|
||||
|
||||
esi.script.id = obj[L("scriptId")].toInt();
|
||||
esi.script.name = obj[L("scriptName")].toString();
|
||||
|
||||
auto scriptCustomNameValIt = obj.constFind(L("scriptCustomName")); // optional
|
||||
if (scriptCustomNameValIt != obj.constEnd())
|
||||
{
|
||||
esi.script.customName = scriptCustomNameValIt->toString();
|
||||
}
|
||||
|
||||
esi.exercise.id = obj[L("exerciseId")].toInt();
|
||||
esi.exercise.name = obj[L("exerciseName")].toString();
|
||||
|
||||
if (esi.script.id < 1 || esi.script.name.isEmpty() || esi.exercise.id < 1 || esi.exercise.name.isEmpty())
|
||||
{
|
||||
throw std::runtime_error("one or more of (script id / script name / exc id / exc name) missing");
|
||||
}
|
||||
|
||||
esi.local = local;
|
||||
esi.uploaded = uploadState;
|
||||
|
||||
return esi;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Topic
|
||||
//QJsonObject Topic::toJson() const
|
||||
//{
|
||||
// every topic type is different.....
|
||||
//}
|
||||
|
||||
|
||||
/*static*/ Topic Topic::topicFromJson(const QJsonObject &obj) noexcept(false)
|
||||
{
|
||||
const JsonObject o(obj);
|
||||
|
||||
// no optional :(
|
||||
const auto filterKey = JsonObject::Key(L("filter"));
|
||||
|
||||
Topic t; // initializer list too nice for 42.3 :'(
|
||||
|
||||
t.id = o.value<int>(L("id"));
|
||||
t.channel = o.value<int>(L("channel"));
|
||||
t.description = o.value<QString>(L("description"));
|
||||
t.type = o.value<int>(L("type"));
|
||||
t.start = o.value<int>(L("start"));
|
||||
t.duration = o.value<int>(L("duration"));
|
||||
t.filename = o.valueOr<QString>(L("filename"), o.valueOr<QString>(L("src"), {}));
|
||||
t.filter = (o.isNull(filterKey) ? -1 : o.value<int>(filterKey));
|
||||
t.filterSet = o.contains<int>(filterKey);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ QVector<Topic> Topic::topicsFromJson(const QJsonArray &arr) noexcept(false)
|
||||
{
|
||||
QVector<Topic> ret;
|
||||
for (const auto &val : arr)
|
||||
{
|
||||
const QJsonObject obj(val.toObject());
|
||||
ret += topicFromJson(obj);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} // namespace TakeHomePackageManager
|
||||
@@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* js-file parsers & specific script.js & topics.js parsers
|
||||
* $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 Mike Wille, EZSZ, 2024-02-12
|
||||
*/
|
||||
|
||||
#include <Common2Core/thp2commoncore_export.h>
|
||||
|
||||
//#include <NGLLogger/INGLLogger.h>
|
||||
#include <LtsUtilsCore/json.h>
|
||||
#include <Common2Core/tpm_tools.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QFile>
|
||||
#include <QMap>
|
||||
|
||||
|
||||
using namespace LtsUtils;
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
/// JsParser
|
||||
template <typename LtsJsonType, typename QJsonType>
|
||||
class THP2COMMONCORE_EXPORT JsParser
|
||||
{
|
||||
public:
|
||||
explicit JsParser(const QString &globalThisName, const QString &filePath, bool mustExist = false) noexcept(false);
|
||||
|
||||
void save() noexcept(false);
|
||||
static QJsonType read(const QString &globalThisName, const QString &filePath, bool mustExist = false) noexcept(false);
|
||||
static void write(const QString &globalThisName, const QJsonType &json, const QString &filePath, bool mustExist = false) noexcept(false);
|
||||
static LtsJsonType parse(const QByteArray &data) noexcept(false);
|
||||
QJsonDocument document() const;
|
||||
const QJsonType &get() const;
|
||||
void set(const QJsonType &json);
|
||||
|
||||
protected:
|
||||
LtsJsonType load(bool mustExist) const noexcept(false);
|
||||
static QString _parse(const QByteArray &data, bool isObject) noexcept(false);
|
||||
QByteArray _load(bool mustExist) const noexcept(false);
|
||||
|
||||
const QString m_globalThisName;
|
||||
const QString m_filePath;
|
||||
LtsJsonType m_json;
|
||||
bool m_dataChanged { false };
|
||||
};
|
||||
|
||||
template class THP2COMMONCORE_EXPORT JsParser<JsonObject, QJsonObject>;
|
||||
using JsObjectParser = JsParser<JsonObject, QJsonObject>;
|
||||
|
||||
template class THP2COMMONCORE_EXPORT JsParser<JsonArray, QJsonArray>;
|
||||
using JsArrayParser = JsParser<JsonArray, QJsonArray>;
|
||||
|
||||
|
||||
|
||||
/// ExportedScriptInformation
|
||||
struct THP2COMMONCORE_EXPORT ExportedScriptInformation
|
||||
{
|
||||
enum class UploadState
|
||||
{
|
||||
ThpUnknownUploadState,
|
||||
ThpNotUploaded,
|
||||
ThpAlreadyUploaded,
|
||||
};
|
||||
|
||||
|
||||
struct Exercise
|
||||
{
|
||||
int id;
|
||||
QString name;
|
||||
};
|
||||
|
||||
|
||||
struct Script
|
||||
{
|
||||
int id;
|
||||
QString name;
|
||||
QString customName;
|
||||
};
|
||||
|
||||
bool operator==(const ExportedScriptInformation &other) const
|
||||
{
|
||||
return (id() == other.id());
|
||||
}
|
||||
|
||||
QString id() const;
|
||||
|
||||
|
||||
QDateTime createdAt; // NOTE: invalid if script only on server
|
||||
Exercise exercise;
|
||||
Script script;
|
||||
|
||||
|
||||
// things not saved to json - only informational
|
||||
QDateTime createdAtServer = {};
|
||||
bool local = true; // only set to false if it's from setServerContent and NOT locally available!
|
||||
UploadState uploaded = UploadState::ThpUnknownUploadState;
|
||||
|
||||
|
||||
void setLocal(const QDateTime &_createdAt) { local = true; createdAt = _createdAt; }
|
||||
void unsetLocal() { local = false; createdAt = {}; }
|
||||
bool isUploaded() const { return (uploaded == UploadState::ThpAlreadyUploaded); }
|
||||
void setUploaded(const QDateTime &_createdAtServer) { uploaded = UploadState::ThpAlreadyUploaded; createdAtServer = _createdAtServer; }
|
||||
void unsetUploaded() { uploaded = UploadState::ThpNotUploaded; createdAtServer= {}; }
|
||||
QJsonValue toJson() const;
|
||||
static ExportedScriptInformation fromJson(const QJsonValue &val,
|
||||
const bool local = true,
|
||||
const UploadState uploadState = UploadState::ThpUnknownUploadState);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// ScriptsJsParser
|
||||
class THP2COMMONCORE_EXPORT ScriptsJsParser : /*protected*/ public JsObjectParser
|
||||
{
|
||||
public:
|
||||
ScriptsJsParser(const QString &root, bool mustExist = false) noexcept(false);
|
||||
|
||||
void save() noexcept(false);
|
||||
const QMap<QString, ExportedScriptInformation> &getExportedScriptInformations() const;
|
||||
const ExportedScriptInformation &getExportedScriptInformation(const QString &scriptId) const noexcept(false);
|
||||
bool hasExportedScriptInformation(const QString &scriptId) const;
|
||||
void setExportedScriptInformations(const QVector<ExportedScriptInformation> &esis) noexcept(false);
|
||||
void addExportedScriptInformation(const ExportedScriptInformation &esi) noexcept(false);
|
||||
void addExportedScriptInformations(const QVector<ExportedScriptInformation> &esis) noexcept(false);
|
||||
void removeExportedScriptInformation(const QString &scriptId) noexcept(false);
|
||||
|
||||
private:
|
||||
QMap<QString /*scriptId*/, ExportedScriptInformation> m_esis;
|
||||
bool m_dataChanged { false };
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Topic
|
||||
struct THP2COMMONCORE_EXPORT Topic
|
||||
{
|
||||
int id;
|
||||
int channel;
|
||||
QString description; // user given description
|
||||
int type;
|
||||
int start;
|
||||
int duration;
|
||||
QString filename;
|
||||
|
||||
// bool getFilter(int &_filter) // TODO: optional Ò_ó
|
||||
// {
|
||||
// if (filterSet)
|
||||
// _filter = filter;
|
||||
// return filterSet;
|
||||
// }
|
||||
|
||||
//private:
|
||||
|
||||
int filter;
|
||||
bool filterSet = false;
|
||||
|
||||
static Topic topicFromJson(const QJsonObject &obj) noexcept(false);
|
||||
static QVector<Topic> topicsFromJson(const QJsonArray &arr) noexcept(false);
|
||||
//QJsonObject toJson() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
///// TopicsJsParser
|
||||
//class THP2COMMONCORE_EXPORT TopicsJsParser : /*protected*/ public JsArrayParser
|
||||
//{
|
||||
//public:
|
||||
// TopicsJsParser(const QString &root, bool mustExist = false) noexcept(false);
|
||||
|
||||
// void save() noexcept(false);
|
||||
// const QMap<int, Topic> &getTopics() const;
|
||||
// const Topic &getTopic(const int topicId) const noexcept(false);
|
||||
// bool hasTopic(const int topicId) const;
|
||||
// void setTopics(const QVector<Topic> &topics) noexcept(false);
|
||||
// void addTopic(const Topic &topic) noexcept(false);
|
||||
// void addTopics(const QVector<Topic> &topics) noexcept(false);
|
||||
// void removeTopic(const int topicId) noexcept(false);
|
||||
|
||||
//private:
|
||||
// QMap<int /*topicId*/, Topic> m_topics;
|
||||
// bool m_dataChanged { false };
|
||||
//};
|
||||
} // namespace TakeHomePackageManager
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Some useful tools to be shared
|
||||
* $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 Mike Wille, EZSZ, 2024-02-12
|
||||
*/
|
||||
|
||||
#include "tpm_tools.h"
|
||||
#include "tpm_js_parser.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QDir>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
using namespace std;
|
||||
//std::string error(const QString &msg) { return msg.toStdString(); }
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
/// SaveFile
|
||||
SaveFile::SaveFile(SaveFile &&other)
|
||||
{
|
||||
m_saveFile.swap(other.m_saveFile);
|
||||
}
|
||||
|
||||
|
||||
SaveFile::SaveFile(const QString &filePath) noexcept(false)
|
||||
: m_saveFile(new QSaveFile(filePath))
|
||||
{}
|
||||
|
||||
|
||||
SaveFile::~SaveFile() noexcept(false)
|
||||
{
|
||||
if (!m_saveFile->isOpen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_saveFile->commit())
|
||||
{
|
||||
throw std::runtime_error("Commit on temporary save file '" + m_saveFile->fileName().toStdString() + "' failed: " + m_saveFile->errorString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SaveFile SaveFile::open(const QString &filePath) noexcept(false)
|
||||
{
|
||||
SaveFile f(filePath);
|
||||
if (!f->open(QIODevice::OpenModeFlag::WriteOnly /* implies truncate */))
|
||||
{
|
||||
throw runtime_error("Failed to create temporary save file '" + filePath.toStdString() + "': " + f->errorString().toStdString());
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// etc.
|
||||
QString localThpDir() { return (QDir::homePath() + QDir::separator() + L("THP2")); } // e.g. /shd/CTC/WS/THP2
|
||||
QString serverThpDir() { return (QDir::homePath() + QDir::separator() + L("THP2-Uploads")); } // e.g. /shd/CTC/SV/THP2-Uploads
|
||||
QString thpOverviewLocation() { return L("/shd/CTC/WS/share/Lts/THP-overview"); }
|
||||
QString scriptsLocation(const QString &root) { return root + QDir::separator() + L("scripts"); } // e.g. /shd/CTC/WS/THP2/scripts
|
||||
QString scriptsJsLocation(const QString &root) { return scriptsLocation(root) + QDir::separator() + L("scripts.js"); } // e.g. /shd/CTC/WS/THP2/scripts/scripts.js
|
||||
QString scriptLocation(const QString &root, const QString &scriptId) { return scriptsLocation(root) + QDir::separator() + scriptId; } // NOTE: counterpart of scriptArchiveLocation
|
||||
QString scriptHtmlLocation(const QString &root, const QString &scriptId) { return scriptLocation(root, scriptId) + QDir::separator() + L("index.html"); }
|
||||
QString scriptArchiveLocation(const QString &root, const QString &scriptId) { return scriptLocation(root, scriptId) + L(".tar.bz2"); } // NOTE: FLM only! client uploads as archive - server stores as archive (use instead of scriptLocation)
|
||||
QString topicsLocation(const QString &root, const QString &scriptId) { return scriptLocation(root, scriptId) + QDir::separator() + L("topics"); }
|
||||
QString topicsJsLocation(const QString &root, const QString &scriptId) { return topicsLocation(root, scriptId) + QDir::separator() + L("topics.js"); }
|
||||
QString topicLocation(const QString &root, const QString &scriptId, const QString &topicFilename) { return topicsLocation(root, scriptId) + QDir::separator() + topicFilename; }
|
||||
|
||||
|
||||
//QVector<ExportedScriptInformation> esisFromScriptsJs(const QString &thpRoot) noexcept(false)
|
||||
//{
|
||||
// const QJsonObject obj(JsObjectParser::read(L("scriptsJs"), scriptsJsLocation(thpRoot), false));
|
||||
// QVector<ExportedScriptInformation> esis;
|
||||
// esis.reserve(obj.count());
|
||||
|
||||
// for (auto it = obj.constBegin(); it != obj.constEnd(); ++it)
|
||||
// {
|
||||
// const auto esi(ExportedScriptInformation::fromJson(it.value(), true /* local */, ExportedScriptInformation::UploadState::ThpUnknownUploadState));
|
||||
// //DEBUG_LOG(m_logger) << "obj=" << QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
|
||||
// //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)
|
||||
|
||||
// esis.push_back(esi);
|
||||
// }
|
||||
|
||||
// return esis;
|
||||
//}
|
||||
|
||||
|
||||
SaveFile openSaveFile(const QString &filePath) noexcept(false)
|
||||
{
|
||||
return SaveFile::open(filePath);
|
||||
}
|
||||
|
||||
|
||||
void writeSaveFile(const QString &filePath, const QByteArray &content) noexcept(false)
|
||||
{
|
||||
SaveFile f(openSaveFile(filePath));
|
||||
f->write(content);
|
||||
}
|
||||
|
||||
|
||||
QByteArray readFile(const QString &filename, bool mustExist) noexcept(false)
|
||||
{
|
||||
QFile f(filename);
|
||||
|
||||
if (!f.exists())
|
||||
{
|
||||
if (mustExist)
|
||||
{
|
||||
throw runtime_error("File '" + filename.toStdString() + "' doesn't exist");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
throw runtime_error("Unable to read file at " + filename.toStdString() + ": " + f.errorString().toStdString());
|
||||
}
|
||||
|
||||
return f.readAll();
|
||||
}
|
||||
|
||||
|
||||
void openFile(QFile &file, bool readOnly, bool existingOnly) noexcept(false)
|
||||
{
|
||||
QFlags<QIODevice::OpenModeFlag> flags(QIODevice::ReadWrite);
|
||||
if (readOnly)
|
||||
{
|
||||
flags.setFlag(QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
// if (existingOnly)
|
||||
// {
|
||||
// flags.setFlag(QIODevice::ExistingOnly); 42.3 is missing this flag -.-
|
||||
// }
|
||||
// polyfill for above ^
|
||||
if (!file.exists() && existingOnly)
|
||||
{
|
||||
throw runtime_error("Unable to open file '" + file.fileName().toStdString() + "' for " + (readOnly ? "reading" : "r/w") + ": <file does not exist!>");
|
||||
}
|
||||
|
||||
if (!file.open(flags))
|
||||
{
|
||||
throw runtime_error("Unable to open file '" + file.fileName().toStdString() + "' for " + (readOnly ? "reading" : "r/w") + ": " + file.errorString().toStdString());
|
||||
}
|
||||
}
|
||||
} // namespace TakeHomePackageManager
|
||||
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Some useful tools to be shared
|
||||
* $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 Mike Wille, EZSZ, 2024-02-12
|
||||
*/
|
||||
|
||||
//#include <logger.h>
|
||||
#include <Common2Core/thp2commoncore_export.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QSaveFile>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#define _compiler_warning(x) _Pragma(#x)
|
||||
#define compiler_warning(x) _compiler_warning(GCC warning x)
|
||||
#else
|
||||
#define compiler_warning(x)
|
||||
#endif
|
||||
|
||||
|
||||
class QFile;
|
||||
|
||||
|
||||
namespace TakeHomePackageManager
|
||||
{
|
||||
/// SaveFile
|
||||
class THP2COMMONCORE_EXPORT SaveFile // NOTE: auto-commits - call `->cancelWriting()` to not commit the file
|
||||
{
|
||||
public:
|
||||
SaveFile() = delete;
|
||||
SaveFile(SaveFile &&other);
|
||||
~SaveFile() noexcept(false);
|
||||
|
||||
static SaveFile open(const QString &filePath) noexcept(false);
|
||||
|
||||
QSaveFile *get() { return m_saveFile.get(); }
|
||||
QSaveFile *operator->() { return m_saveFile.get(); }
|
||||
|
||||
private:
|
||||
explicit SaveFile(const QString &filePath) noexcept(false);
|
||||
|
||||
std::unique_ptr<QSaveFile> m_saveFile;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// etc.
|
||||
THP2COMMONCORE_EXPORT void writeSaveFile(const QString &filePath, const QByteArray &content) noexcept(false);
|
||||
THP2COMMONCORE_EXPORT QByteArray readFile(const QString &filename, bool mustExist = false) noexcept(false);
|
||||
THP2COMMONCORE_EXPORT void openFile(QFile &file, bool readOnly = false, bool existingOnly = false) noexcept(false);
|
||||
THP2COMMONCORE_EXPORT void writeToFileOrRollback(QFile &file, const QByteArray &data) noexcept(false);
|
||||
THP2COMMONCORE_EXPORT void writeToFileOrRollback(QFile &file, const QString &string) noexcept(false);
|
||||
THP2COMMONCORE_EXPORT SaveFile openSaveFile(const QString &filePath) noexcept(false);
|
||||
//THP2COMMONCORE_EXPORT QVector<ExportedScriptInformation> esisFromScriptsJs(const QString &thpRoot) noexcept(false);
|
||||
|
||||
|
||||
THP2COMMONCORE_EXPORT QString localThpDir();
|
||||
THP2COMMONCORE_EXPORT QString serverThpDir();
|
||||
THP2COMMONCORE_EXPORT QString thpOverviewLocation();
|
||||
THP2COMMONCORE_EXPORT QString scriptsLocation(const QString &root);
|
||||
THP2COMMONCORE_EXPORT QString scriptsJsLocation(const QString &root);
|
||||
THP2COMMONCORE_EXPORT QString scriptLocation(const QString &root, const QString &scriptId);
|
||||
THP2COMMONCORE_EXPORT QString scriptHtmlLocation(const QString &root, const QString &scriptId);
|
||||
THP2COMMONCORE_EXPORT QString scriptArchiveLocation(const QString &root, const QString &scriptId);
|
||||
THP2COMMONCORE_EXPORT QString topicsJsLocation(const QString &root, const QString &scriptId);
|
||||
THP2COMMONCORE_EXPORT QString topicsLocation(const QString &root, const QString &scriptId);
|
||||
THP2COMMONCORE_EXPORT QString topicLocation(const QString &root, const QString &scriptId, const QString &topicFilename);
|
||||
|
||||
|
||||
|
||||
// NOTE: DeferedDelete (deleteLater) will not trigger deletions while inside any of the await functions (nested event loops)!
|
||||
template <typename Func1>
|
||||
void awaitx(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
|
||||
const int timeoutMs = 0)
|
||||
{
|
||||
QEventLoop x;
|
||||
QObject::connect(sender, signal, &x, &QEventLoop::quit);
|
||||
|
||||
std::unique_ptr<QTimer> t(new QTimer); // NOTE: do not use make_unique because of 42.3!
|
||||
bool timeout = false;
|
||||
if (timeoutMs > 0)
|
||||
{
|
||||
t->setInterval(timeoutMs);
|
||||
t->setSingleShot(true);
|
||||
QObject::connect(t.get(), &QTimer::timeout, &x, [&timeout](){ timeout = true; });
|
||||
QObject::connect(t.get(), &QTimer::timeout, &x, &QEventLoop::quit);
|
||||
}
|
||||
|
||||
x.exec();
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
throw std::runtime_error("Timeout.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Func1, typename Func2>
|
||||
void awaitWithCancelationSignalx(const typename QtPrivate::FunctionPointer<Func1>::Object *sender1, Func1 signal1,
|
||||
const typename QtPrivate::FunctionPointer<Func2>::Object *sender2, Func2 signal2,
|
||||
const int timeoutMs = 0)
|
||||
{
|
||||
QEventLoop x;
|
||||
bool success = false;
|
||||
QObject::connect(sender1, signal1, &x, [&success](){ success = true; /*qWarning() << "=> SUCCESS";*/});
|
||||
QObject::connect(sender1, signal1, &x, &QEventLoop::quit, Qt::QueuedConnection);
|
||||
|
||||
// bool cancel = false;
|
||||
// QObject::connect(sender2, signal2, &x, [/*&cancel*/](){ /*cancel = true;*/ qWarning() << "=> cancel....";});
|
||||
QObject::connect(sender2, signal2, &x, &QEventLoop::quit, Qt::QueuedConnection);
|
||||
|
||||
std::unique_ptr<QTimer> t(new QTimer); // NOTE: do not use make_unique because of 42.3!
|
||||
bool timeout = false;
|
||||
if (timeoutMs > 0)
|
||||
{
|
||||
t->setInterval(timeoutMs);
|
||||
t->setSingleShot(true);
|
||||
QObject::connect(t.get(), &QTimer::timeout, &x, [&timeout](){ timeout = true; });
|
||||
QObject::connect(t.get(), &QTimer::timeout, &x, &QEventLoop::quit, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
//qWarning() << "## STARTING AWAIT NOW!";
|
||||
x.exec();
|
||||
//qWarning() << "## AWAIT DONE!";
|
||||
|
||||
if (timeout && !success)
|
||||
{
|
||||
throw std::runtime_error("Timeout.");
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw std::runtime_error("Canceled.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user