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,49 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2016-09-19
#
SET(SRCS
dds_vector_to_pixmap.cpp
dds_vector_to_pixmap.h
request_helper.cpp
request_helper.h
)
NGL_ADD_LIBRARY2(WS LtsUtilsGuiDds SHARED ${SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(LtsUtilsGuiDds
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(LtsUtilsGuiDds
PRIVATE
LtsUtilsCoreHeaderOnly
LtsWidgets
Qt5::Gui
Qt5::Widgets
Qt5::Svg
PUBLIC
Qt5::Core
ddscore
)
NGL_TARGET_COMPILE_DEFINITIONS(LtsUtilsGuiDds
PUBLIC
REQUEST_HELPER_WITH_GUI
)
NGL_ADD_LIBRARY2(AAR HLA SV LtsUtilsDds SHARED request_helper.cpp request_helper.h)
NGL_TARGET_INCLUDE_DIRECTORIES(LtsUtilsDds
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(LtsUtilsDds
PRIVATE
LtsUtilsCoreHeaderOnly
PUBLIC
Qt5::Core
ddscore
)
@@ -0,0 +1,138 @@
/**
* Helper class to convert QByteArray/QPixmap to/from std::vector<uint8>
* $Id$
* $HeadURL$
* $Author$
*/
#include <LtsUtilsCore/dds_vector.h>
#include <LtsUtilsGuiDds/dds_vector_to_pixmap.h>
#include <QBuffer>
#include <QFile>
#include <QIcon>
#include <QImage>
#include <QPainter>
#include <QPixmap>
#include <QSvgRenderer>
namespace LtsUtils
{
QIcon iconFromSvg(const QByteArray &svgData, QSize iconSize)
{
QSvgRenderer renderer(svgData);
QPixmap p(iconSize);
p.fill(Qt::transparent);
QPainter painter(&p);
renderer.render(&painter);
painter.end();
return {p};
}
QIcon iconFromSvg(const QString &svgFilename, QSize iconSize)
{
QFile f(svgFilename);
if (!f.open(QIODevice::ReadOnly))
return {};
return iconFromSvg(f.readAll(), iconSize);
}
QPixmap pixmapFromIcon(const QIcon &icon, QSize iconSize)
{
return icon.pixmap(iconSize).scaled(100, 100, Qt::AspectRatioMode::IgnoreAspectRatio/* almost all of our svgs have a 1:1 aspect ratio, so ignore ratio */);
}
QPixmap pixmapFromSvg(const QString &svgFilename, QSize iconSize)
{
return pixmapFromIcon(iconFromSvg(svgFilename, iconSize), iconSize);
}
QPixmap getPixmap(const std::vector<uint8_t> &data)
{
if (data.size() == 0)
return QPixmap();
// fromRawData will lead to crashes when data goes out of scope
return getPixmap(QByteArray(reinterpret_cast<const char*>(&data.at(0)), data.size()));
}
QPixmap getPixmap(const QByteArray &data)
{
return QPixmap::fromImage(QImage::fromData(data));
}
QImage getImage(const std::vector<uint8_t> &data)
{
if (data.size() == 0)
return QImage();
// fromRawData will lead to crashes when data goes out of scope
return getImage(QByteArray(reinterpret_cast<const char*>(&data.at(0)), data.size()));
}
QImage getImage(const QByteArray &data)
{
return QImage::fromData(data);
}
static inline void setIf(bool *boolPtr, bool val)
{
if (boolPtr)
*boolPtr = val;
}
std::vector<uint8_t> fromPixmap(const QPixmap &pixmap, bool *bIsPng)
{
QBuffer buf;
buf.open(QIODevice::WriteOnly);
pixmap.save(&buf, "PNG");
buf.close();
QByteArray ba = buf.buffer();
setIf(bIsPng, true);
// if we have no alpha we can try to convert it to a jpg which may be smaller
if (ba.size() > 10240 && !pixmap.hasAlpha() && !pixmap.hasAlphaChannel())
{
QBuffer buf2;
buf2.open(QIODevice::WriteOnly);
pixmap.save(&buf2, "JPG");
buf2.close();
if (buf2.buffer().size() < buf.buffer().size())
{
setIf(bIsPng, false);
ba = buf2.buffer();
}
}
return convert<std::vector<uint8_t>>(ba);
}
std::vector<uint8_t> fromImage(const QImage &image, bool *bIsPng)
{
QBuffer buf;
buf.open(QIODevice::WriteOnly);
image.save(&buf, "PNG");
buf.close();
QByteArray ba = buf.buffer();
// if we have no alpha we can try to convert it to a jpg which may be smaller
setIf(bIsPng, true);
if ((ba.size() > 10240 && !image.hasAlphaChannel()) ||
ba.size() > 1024 * 1024)
{
QBuffer buf2;
buf2.open(QIODevice::WriteOnly);
image.save(&buf2, "JPG");
buf2.close();
if (buf2.buffer().size() < buf.buffer().size())
{
setIf(bIsPng, false);
ba = buf2.buffer();
}
}
return convert<std::vector<uint8_t>>(ba);
}
} // namespace LtsUtils
@@ -0,0 +1,37 @@
/**
* Helper class to convert QByteArray/QPixmap to/from std::vector<uint8>
* $Id: dds_vector_to_pixmap.h 52119 2020-09-15 12:38:49Z ojog_i $
* $HeadURL: svn://slssvn/TDS/branches/product/devel/trunk/Lts/Common/LtsUtils/LtsUtilsCore/dds_vector_to_pixmap.h $
* $Author: ojog_i $
*/
#pragma once
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QSize>
#include <QString>
#include <cstdint>
#include <vector>
class QByteArray;
class QPixmap;
class QImage;
class QIcon;
namespace LtsUtils
{
LTSUTILSCORE_EXPORT QPixmap getPixmap(const std::vector<uint8_t> &data);
LTSUTILSCORE_EXPORT QPixmap getPixmap(const QByteArray &data);
LTSUTILSCORE_EXPORT QImage getImage(const std::vector<uint8_t> &data);
LTSUTILSCORE_EXPORT QImage getImage(const QByteArray &data);
LTSUTILSCORE_EXPORT QIcon iconFromSvg(const QByteArray &svgData, QSize iconSize = QSize(100, 100));
LTSUTILSCORE_EXPORT QIcon iconFromSvg(const QString &svgFilename, QSize iconSize = QSize(100, 100));
LTSUTILSCORE_EXPORT QPixmap pixmapFromIcon(const QIcon &icon, QSize iconSize = QSize(100, 100));
LTSUTILSCORE_EXPORT QPixmap pixmapFromSvg(const QString &svgFilename, QSize iconSize = QSize(100, 100));
LTSUTILSCORE_EXPORT std::vector<uint8_t> fromPixmap(const QPixmap &pixmap, bool *bIsPng = nullptr);
LTSUTILSCORE_EXPORT std::vector<uint8_t> fromImage(const QImage &image, bool *bIsPng = nullptr);
} // namespace LtsUtils
@@ -0,0 +1,285 @@
/**
* Helper class for simple function topic request handling
* $Id$
* $HeadURL$
* $Author$
*/
#include "request_helper.h"
#ifdef REQUEST_HELPER_WITH_GUI
#include <LtsWidgets/lts_global_wait_dialog.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <QWidget>
#endif
#include <QEventLoop>
#include <QTimer>
#include <memory>
#include <QJsonDocument>
#include <QJsonObject>
#define DEBUG
namespace LtsUtils
{
bool RequestHelper::s_debug = false;
RequestHelper::RequestHelper(QObject *parent, bool quiet,
// for non-blocking
const std::function<void (void)> &success,
const std::function<void (void)> &failure)
: QObject(parent)
, m_failed(false)
, m_repliedId(-1)
, m_quiet(quiet)
, m_blockingCall(true)
, m_successFn(success)
, m_failureFn(failure)
{
connect(this, &RequestHelper::signalSuccess, this, m_successFn, Qt::QueuedConnection);
connect(this, &RequestHelper::signalFailed, this, m_failureFn, Qt::QueuedConnection);
if (s_debug)
{
QTimer *t = new QTimer(this);
t->setInterval(2000);
t->setSingleShot(true); // stop after execution, start explicitly
connect(this, &RequestHelper::signalNextRequest, t, static_cast<void (QTimer::*)(void)>(&QTimer::start));
connect(t, &QTimer::timeout, this, &RequestHelper::slotNextRequest, Qt::QueuedConnection);
}
else
{
connect(this, &RequestHelper::signalNextRequest,
this, &RequestHelper::slotNextRequest,
Qt::QueuedConnection
/*/
* This flag is the magic that the reply is
* guaranteed to arrive when we are in the
* event loop of QEventLoop, because a queued
* signal can only be processed when in the
* event loop.
/*/);
}
}
void RequestHelper::addRequest(const std::function<int64_t()> &requestFunction,
const std::function<void(const Core::FunctionReply &baseReply)> &baseReplyHandler)
{
m_requestFunctions.append(RequestFunctionContainer(requestFunction, baseReplyHandler));
}
bool RequestHelper::requestReply(const Core::FunctionReply &baseReply)
{
const Core::FunctionReplyObject fro(baseReply.id(),
baseReply.errorString(),
baseReply.errorParams());
return _requestReply(fro, &baseReply);
}
bool RequestHelper::requestReply(const Core::FunctionReplyObject &replyObject)
{
return _requestReply(replyObject, nullptr);
}
bool RequestHelper::_requestReply(const Core::FunctionReplyObject &fro, const Core::FunctionReply *baseReply)
{
m_errorString = fro.translated();
#ifdef REQUEST_HELPER_WITH_GUI
if (fro.error())
{
if (!m_quiet)
{
if (m_blockingCall)
{
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()),
m_errorString,
tr("Request failed"));
}
else // non-blocking
{
new LtsWidgets::LtsMessageDialogNew(qobject_cast<QWidget *>(parent()),
m_errorString,
tr("Request failed"));
}
}
}
#endif
m_repliedId = fro.id(); // error doesn't mean that the service might not reply with an id - so always take the id
if (m_singleRequestCustomFunctionReply != nullptr)
{
if (baseReply)
m_singleRequestCustomFunctionReply(*baseReply);
else
m_singleRequestCustomFunctionReply(Core::FunctionReply(fro.id(), fro.str(), fro.args(), fro.additionalInfo()));
}
if (fro.error())
{
failure();
return false;
}
emit signalNextRequest();
return true;
}
bool RequestHelper::startSingleRequest(const std::function<int64_t()> &requestFunction,
const std::function<void(const Core::FunctionReply &baseReply)> &baseReplyHandler)
{
addRequest(requestFunction, baseReplyHandler);
return startRequests();
}
void RequestHelper::failure()
{
m_failed = true;
emit signalFailed();
done();
}
void RequestHelper::done()
{
#ifdef REQUEST_HELPER_WITH_GUI
if (!m_quiet)
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
#endif
m_requestFunctions.clear();
m_singleRequestCustomFunctionReply = nullptr;
if (m_blockingCall)
emit signalQuitLoop(); // don't worry, is queued
m_blockingCall = true;
if (!m_blockingCall)
deleteLater(); // only working with ONE execution
}
void RequestHelper::slotNextRequest()
{
if (m_requestFunctions.isEmpty())
{
if (!m_blockingCall)
emit signalSuccess();
done(); // NOTE: resets m_blockingCall
return;
}
const RequestFunctionContainer rfc = m_requestFunctions.takeFirst();
m_singleRequestCustomFunctionReply = rfc.second;
int64_t result = rfc.first(); // execute request
if (result == 0) // request failed
{
#ifdef REQUEST_HELPER_WITH_GUI
if (!m_quiet)
{
if (m_blockingCall)
{
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()),
tr("Request failed")); // TODO: text
}
else // non-blocking
{
connect(new LtsWidgets::LtsMessageDialogNew(qobject_cast<QWidget *>(parent()),
tr("Request failed"))/* TODO: text */, &LtsWidgets::LtsMessageDialogNew::destroyed,
this, [this]()
{
failure();
});
return;
}
}
#endif
failure();
}
}
void RequestHelper::startSingleBackgroundRequest(const std::function<int64_t()> &requestFunction,
const std::function<void (const Core::FunctionReply &)> &baseReplyHandler)
{
m_blockingCall = false;
startSingleRequest(requestFunction, baseReplyHandler);
}
void RequestHelper::startBackgroundRequests()
{
m_blockingCall = false;
startRequests();
}
void RequestHelper::setCustomWaitMessage(const QString &customWaitMessage)
{
m_customWaitMessage = (customWaitMessage + QStringLiteral(" ..."));
}
bool RequestHelper::startRequests()
{
if (m_requestFunctions.isEmpty())
{
#ifdef LTS_DEBUG
qWarning("RequestHelper: started request helper without requests!");
#endif
return true;
}
m_failed = false;
#ifdef REQUEST_HELPER_WITH_GUI
if (!m_quiet)
LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait(m_customWaitMessage);
m_customWaitMessage.clear();
#endif
m_errorString.clear();
m_repliedId = -1;
if (s_debug)
{
QTimer *t = new QTimer(this);
t->setInterval(2000);
connect(t, &QTimer::timeout, this, &RequestHelper::slotNextRequest, Qt::QueuedConnection);
connect(t, &QTimer::timeout, t, &QTimer::deleteLater);
t->start();
}
else
{
slotNextRequest();
if (m_blockingCall)
{
QEventLoop loop;
connect(this, &RequestHelper::signalQuitLoop,
&loop, &QEventLoop::quit,
Qt::QueuedConnection);
loop.exec();
}
}
return (!m_failed); // ignored if non-blocking
}
} // namespace LtsUtils
@@ -0,0 +1,140 @@
/**
* Helper class for simple function topic request handling
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#ifdef REQUEST_HELPER_WITH_GUI
#include <LtsUtilsGuiDds/ltsutilsguidds_export.h>
#define LTSUTILSGUIDDS_INTERNAL_EXPORT LTSUTILSGUIDDS_EXPORT
#else
#include <LtsUtilsGuiDds/ltsutilsdds_export.h>
#define LTSUTILSGUIDDS_INTERNAL_EXPORT LTSUTILSDDS_EXPORT
#endif
#include <DDS/Core/function_reply_object.h>
#include <DDS/Core/core.hpp> // Core::FunctionReply (base reply)
#include <QObject>
#include <QVector>
#include <QPair>
#include <functional>
namespace LtsUtils
{
template<typename T>
dds::core::optional<T> toOptional(T inVal)
{
return inVal != T() ? dds::core::optional<T>(inVal) : dds::core::optional<T>();
}
template<typename T>
dds::core::optional<T> optional()
{
return dds::core::optional<T>();
}
class LTSUTILSGUIDDS_INTERNAL_EXPORT RequestHelper : public QObject // TODO: DOC !!!
{
Q_OBJECT
public:
static bool s_debug;
explicit RequestHelper(QObject *parent = nullptr, bool quiet = false,
// for non-blocking
const std::function<void (void)> &success = [](){},
const std::function<void (void)> &failure = [](){});
~RequestHelper() = default;
bool quiet() const { return m_quiet; }
void setQuiet(bool quiet) { m_quiet = quiet; }
void addRequest(const std::function<int64_t()> &requestFunction,
const std::function<void(const Core::FunctionReply &baseReply)> &baseReplyHandler = nullptr);
bool startRequests(); // blocks!
// do not throw a message if this method fails, as this method does this already // blocks!
bool startSingleRequest(const std::function<int64_t(void)> &requestFunction,
const std::function<void(const Core::FunctionReply &baseReply)> &baseReplyHandler = nullptr // for replies that return a custom FunctionReply, which has to be handled >>after successful execution<<
);
// non-blocking !
/**
* @brief startSingleBackgroundRequest << you cannot reuse this request helper after using background requests! Only use if your REALLY need it.
* @param requestFunction
* @param baseReplyHandler
*/
void startSingleBackgroundRequest(const std::function<int64_t()> &requestFunction,
const std::function<void(const Core::FunctionReply &baseReply)> &baseReplyHandler = nullptr);
/**
* @brief startBackgroundRequests << you cannot reuse this request helper after using background requests! Only use if your REALLY need it.
*/
void startBackgroundRequests(); // non-blocking !
bool requestReply(const Core::FunctionReply &baseReply); // if you have a custom FunctionReply, pass the base ptr
bool requestReply(const Core::FunctionReplyObject &replyObject);
/**
* @brief hasRequests are requests is added?
* @return True if a request is added, otherwise false
*/
bool hasRequests() const { return !m_requestFunctions.isEmpty(); }
/**
* @brief getRepliedId returns the Return-ID of the ReplyObject you gave to the method 'requestReply' - which is mostly the ID for the new Table Entry (Unique ID)
* @return the Return-ID or -1 on error (not set)
*/
int getRepliedId() const { return m_repliedId; }
/**
* @brief getErrorString returns the error string set by an ftc reply
* @return
*/
QString getErrorString() const { return m_errorString; }
/**
* @brief setCustomWaitMessage changes the default 'Waiting for server reply ...' message with a custom one (NOTE: " ..." is automagically added to the custom text)
* After a request was started, the custom wait message is immediately reset, so that the next call to start a request, shows the default message again
* @param customWaitMessage the wait message to replace the default message with (note that " ..." is added to the text)
*/
void setCustomWaitMessage(const QString &customWaitMessage);
bool failed() const { return m_failed; }
void failure();
private:
using RequestFunctionContainer = QPair<std::function<int64_t()>, std::function<void(const Core::FunctionReply &)>>;
QVector<RequestFunctionContainer> m_requestFunctions;
bool m_failed;
int m_repliedId;
std::function<void(const Core::FunctionReply &)> m_singleRequestCustomFunctionReply;
bool m_quiet;
bool m_blockingCall;
std::function<void (void)> m_successFn;
std::function<void (void)> m_failureFn;
QString m_errorString;
QString m_customWaitMessage;
void done();
bool _requestReply(const Core::FunctionReplyObject &fro, const Core::FunctionReply *baseReply);
signals:
void signalNextRequest();
void signalQuitLoop();
void signalSuccess();
void signalFailed();
private slots:
void slotNextRequest();
};
} // namespace LtsUtils