Qt6 Migration: Complete migration with DDS/RTI support and build validation

Major Changes:
- Merged latest Qt5 devel content from dlbo (292 files changed, 7 new dirs)
- Consolidated forward-declarations and include folders
- Removed unneeded modules per Niklas' repo check list

Build System Fixes:
- Fixed CMake VERSION_GREATER syntax in ParticipantManagement/CMakeLists.txt
- Added VLC packages (libvlc-dev, vlc-plugin-base) to docker_build.sh
- Added PostgreSQL dev packages (libpq-dev, postgresql-server-dev-all) to Dockerfile
- Fixed locale warnings (ANSI_X3.4-1968 → C.UTF-8)
- Fixed ArcGIS SDK path warnings when BUILD_ARCGIS=OFF

Code Generation Fixes:
- Fixed IDL enum collisions (PortType→CorePortType/DdsutPortType, PdmEventType)
- Fixed Grantlee template svc_translation.cpp.grantlee:
  - Changed {{ idl_enum.name }}_def:: to {{ idl_enum.name }}::
  - Fixed .underlying() calls for C++11 scoped enums (enum class)
- Removed generated files from repo (moc_*, *_dtc.h, *_ftc.h)

Validation:
- BUILD_RTI=ON: SUCCESS
- BUILD_RTI=OFF: SUCCESS
- C++17 standard maintained for RTI 7.7 compatibility
- Ubuntu 26.04 Docker environment verified

Remaining Warnings (expected):
- BgViewer, KDChart, KDReports, Poppler-Qt6 not found (optional features)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
torstenandCopilot committed 2026-09-15 18:20:26 +00:00
1 parent f23384bb68
commit 7173785915
18662 files changed
+4115092 -5435

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
#
# $Id$
# $HeadURL$
# $Author$
#
ADD_SUBDIRECTORY(ngldb)
ADD_SUBDIRECTORY(tcpserver)
ADD_SUBDIRECTORY(QtSingleApplication)
ADD_SUBDIRECTORY(WMS_Interface)
ADD_SUBDIRECTORY(nglapplication)
ADD_SUBDIRECTORY(nglcompression)
ADD_SUBDIRECTORY(nglsettings)
ADD_SUBDIRECTORY(ngltranslator)
ADD_SUBDIRECTORY(ngltools)
ADD_SUBDIRECTORY(nglwidgets)
ADD_SUBDIRECTORY(NGLLogger)
@@ -0,0 +1,50 @@
FIND_PACKAGE(Log4Qt REQUIRED)
# Sourcen
SET(NGLLogger_SRCS
MurmurHash2.cpp
MurmurHash2.h
INGLLogger.h
NGLLogger_export.h
NGLLoggerBootstrap.cpp
NGLLoggerBootstrap.h
NGLLogger.cpp
NGLLogger.h
)
# Header
SET(NGLLogger_HDRS
)
# Make sure NGLLogger.h compiles ..
ADD_DEFINITIONS(-DBUILDING_NGLLOGGER)
NGL_ADD_LIBRARY(ALL NGLLogger SHARED ${NGLLogger_SRCS} ${NGLLogger_HDRS})
NGL_TARGET_INCLUDE_DIRECTORIES(NGLLogger
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(NGLLogger
PRIVATE
Log4Qt::log4qt
PUBLIC
Qt5::Core
)
NGL_INSTALL_TARGET(NGLLogger)
#
# test_ngllogger
#
IF(BUILD_TESTING AND TARGET NGLLogger)
ADD_EXECUTABLE(test_ngllogger test_ngllogger.cpp)
TARGET_LINK_LIBRARIES(test_ngllogger NGLLogger)
TARGET_LINK_LIBRARIES(test_ngllogger
Log4Qt::log4qt
ngltools
)
ADD_TEST(NAME test_ngllogger COMMAND $<TARGET_FILE:test_ngllogger>)
ENDIF(BUILD_TESTING AND TARGET NGLLogger)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/log4cxx.props ${CMAKE_BINARY_DIR}/log4cxx.props COPYONLY)
@@ -0,0 +1,310 @@
/**
* Logger interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <string>
#include <sstream>
#include <QString>
#include <QPointF>
#include <QSize>
#include <QRect>
#include <QRectF>
#include <QList>
#include "NGLLogger_export.h"
namespace NGL
{
class INGLLogger;
// keep in sync with log4qt/level.h
enum class LogLevel
{
Undefined = 0,
Trace = 64,
Debug = 96,
Info = 128,
Warning = 150,
Error = 182,
Fatal = 214,
};
class LogStreamHelper
{
public:
inline LogStreamHelper(INGLLogger &logger, LogLevel level, const char *const file, int line, const char *const function)
: m_logger(logger)
, m_level(level)
, m_line(line)
, m_file(file)
, m_func(function)
{}
inline ~LogStreamHelper(); // after INGLLogger class definition
template<typename T>
inline LogStreamHelper &operator<<(const T &val);
private:
std::ostringstream m_buffer;
NGL::INGLLogger &m_logger;
const LogLevel m_level;
const int m_line;
const char *const m_file;
const char *const m_func;
};
// Interface class for source code logging.
// Use NGLLoggerBootstrap to create an instance of this interface.
// Look below in this headerfile for the macros with which to insert logging
// code into your source code.
// Lookup the log4cxx documentation (http://logging.apache.org/log4cxx/) for
// information on logger-hierarchies, logging-levels, and configuration files.
class INGLLogger
{
public:
INGLLogger(const INGLLogger &) = delete;
INGLLogger &operator=(const INGLLogger &) = delete;
INGLLogger() = default;
virtual ~INGLLogger() = default;
using String = std::string;
// Creates an instance of an INGLLogger interface. The fullqualifiedname is
// a dottet sequence (i.e. "NGL.thisandthat.mylogger"). The same name will
// always return the same interface-instance. It is not required to create
// the parent nodes.
virtual INGLLogger &getNGLLogger(const char *fullqualifiedname) = 0;
virtual INGLLogger &getNGLLogger(const std::string &fullqualifiedname) = 0;
// True if this level is enabled.
virtual bool isTraceEnabled() const = 0;
virtual bool isDebugEnabled() const = 0;
virtual bool isInfoEnabled() const = 0;
virtual bool isWarningEnabled() const = 0;
virtual bool isErrorEnabled() const = 0;
virtual bool isFatalEnabled() const = 0;
virtual bool isLevelEnabled(LogLevel level) const = 0;
// Submit a LOG message.
// Use __FILE__ and __NAME__ macros.
virtual void log(LogLevel level, const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0;
// Submit an TRACE message.
virtual void logTrace(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0;
// Submit an DEBUG message.
virtual void logDebug(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0;
// Submit an INFO message.
virtual void logInfo(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0;
// Submit a WARNING message.
virtual void logWarning(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0;
// Submit an ERROR message.
virtual void logError(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0;
// Submit a FATAL message.
virtual void logFatal(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0;
// Writes a startup message into the logfile
virtual void logStartup(const char *file, int line, const char *function = nullptr) = 0;
// Writes a shutdown message into the logfile
virtual void logShutdown(const char *file, int line, const char *function = nullptr) = 0;
// Get this loggers fullqualified name.
virtual std::string getLoggerName() const = 0;
virtual void setNoSpace(bool bNoSpace) = 0;
virtual bool noSpace() const = 0;
};
//
// LogStreamHelper
//
inline LogStreamHelper::~LogStreamHelper()
{
m_logger.log(m_level, m_buffer.str(), m_file, m_line, m_func);
}
template<typename T>
inline LogStreamHelper &LogStreamHelper::operator<<(const T &val)
{
m_buffer << val;
if (!m_logger.noSpace())
m_buffer << " ";
return *this;
}
} //namespace NGL
inline std::ostream &operator<<(std::ostream &stream, const QByteArray &str)
{
stream << std::string(str.data(), str.size());
return stream;
}
//
// operator to ease logging (at least via NglLogging)
//
inline std::ostream &operator<<(std::ostream &stream,
const QPointF &value)
{
stream << "QPointF(" << QString::number(value.x(), 'f', 6).toStdString() << "#" << QString::number(value.y(), 'f', 6).toStdString() << ")";
return stream;
}
//----------------------------------------------------------------------------
inline std::ostream &operator<< (std::ostream &stream,
const QPoint &value)
{
stream << "QPoint(" << value.x() << "#" << value.y() << ")";
return stream;
}
inline std::ostream &operator<< (std::ostream &stream,
const QSize &value)
{
stream << "QSize(w=" << value.width() << ";h=" << value.height() << ")";
return stream;
}
inline std::ostream &operator<< (std::ostream &stream,
const QSizeF &value)
{
stream << "QSize(w="
<< QString::number(value.width(), 'f', 6).toStdString() << ";h="
<< QString::number(value.height(), 'f', 6).toStdString()
<< ")";
return stream;
}
inline std::ostream &operator<< (std::ostream &stream,
const QRect &value)
{
stream << "QRect(center=" << value.center()
<< " w=" << value.width()
<< ";h=" << value.height()
<< " bottomLeft=" << value.bottomLeft()
<< " topRight=" << value.topRight()
<< ")";
return stream;
}
inline std::ostream &operator<< (std::ostream &stream,
const QRectF &value)
{
stream << "QRectF(center=" << value.center()
<< " w=" << QString::number(value.width(), 'f', 3).toStdString()
<< ";h=" << QString::number(value.height(), 'f', 3).toStdString()
<< " bottomLeft=" << value.bottomLeft()
<< " topRight=" << value.topRight()
<< ")";
return stream;
}
inline std::ostream &operator<< (std::ostream &stream,
const QList<int> &value)
{
stream << "QList<int>(" << value.size() << "): ";
for (int i : value)
stream << i << ";";
return stream;
}
inline std::ostream &operator<< (std::ostream &stream,
const QList<QPointF> &value)
{
stream << "QList<QPointF>(" << value.size() << "): ";
for (const QPointF &item : value)
stream << item << ";";
return stream;
}
inline std::ostream &operator<<(std::ostream &stream, const QString &str)
{
return stream << str.toUtf8();
}
namespace NGL
{
namespace NGLLoggerHelper
{
NGLLOGGER_EXPORT void hexDumpHelper(NGL::INGLLogger &logger,
NGL::LogLevel level,
const void *a_data,
const unsigned int a_size);
inline void hexDumpHelper(NGL::INGLLogger &logger,
NGL::LogLevel level,
const QByteArray &data)
{
return hexDumpHelper(logger, level, data.data(), data.size());
}
} // namespace NGLLoggerHelper
NGLLOGGER_EXPORT NGL::INGLLogger& getMemoryLogger();
NGLLOGGER_EXPORT std::string getMemoryData();
} // namespace NGL
//==============================================================================
// macros
//==============================================================================
#define LOGFUNCTION Q_FUNC_INFO
// log this output every time, no matter what log level is enabled
#define NOTICE_LOG(logger) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO)
#ifdef LTS_DEBUG
#define TRACE_LOG(logger) \
for (bool log_level_enabled = (logger).isTraceEnabled(); log_level_enabled; log_level_enabled = false) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Trace, __FILE__,__LINE__, Q_FUNC_INFO)
#else
#define TRACE_LOG(logger) \
for ( ; false; ) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Trace, __FILE__,__LINE__, Q_FUNC_INFO)
#endif
#define DEBUG_LOG(logger) \
for (bool log_level_enabled = (logger).isDebugEnabled(); log_level_enabled; log_level_enabled = false) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Debug, __FILE__,__LINE__, Q_FUNC_INFO)
#define INFO_LOG(logger) \
for (bool log_level_enabled = (logger).isInfoEnabled(); log_level_enabled; log_level_enabled = false) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO)
#define WARNING_LOG(logger) \
for (bool log_level_enabled = (logger).isWarningEnabled(); log_level_enabled; log_level_enabled = false) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Warning, __FILE__,__LINE__, Q_FUNC_INFO)
#define ERROR_LOG(logger) \
for (bool log_level_enabled = (logger).isErrorEnabled(); log_level_enabled; log_level_enabled = false) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Error, __FILE__,__LINE__, Q_FUNC_INFO)
#define FATAL_LOG(logger) \
for (bool log_level_enabled = (logger).isFatalEnabled(); log_level_enabled; log_level_enabled = false) \
NGL::LogStreamHelper(logger, NGL::LogLevel::Fatal, __FILE__,__LINE__, Q_FUNC_INFO)
#define STARTUP_LOG(logger) { (logger).logStartup(__FILE__, __LINE__, Q_FUNC_INFO); }
#define SHUTDOWN_LOG(logger) { (logger).logShutdown(__FILE__, __LINE__, Q_FUNC_INFO); }
//==============================================================================
// use like:
// MEMORY_LOG() << " before something nasty";
// do something nasty
// MEMORY_LOG() << " after something nasty";
#define MEMORY_LOG() \
for (bool log_level_enabled = (NGL::getMemoryLogger()).isInfoEnabled(); log_level_enabled; log_level_enabled = false) \
NGL::LogStreamHelper(NGL::getMemoryLogger(), NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO) << NGL::getMemoryData()
//==============================================================================
@@ -0,0 +1,81 @@
/**
* Simple and fast hash for logger strings
* $Id$
* $HeadURL$
* $Author$
*/
//-----------------------------------------------------------------------------
// MurmurHash2, by Austin Appleby
// http://murmurhash.googlepages.com/
// public domain
// Note - This code makes a few assumptions about how your machine behaves -
// 1. We can read a 4-byte value from any address without crashing
// 2. sizeof(int) == 4
// And it has a few limitations -
// 1. It will not work incrementally.
// 2. It will not produce the same results on little-endian and big-endian
// machines.
#include "MurmurHash2.h"
#include <QtCore/qcompilerdetection.h>
namespace NGL
{
unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed )
{
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
const unsigned int m = 0x5bd1e995;
const int r = 24;
// Initialize the hash to a 'random' value
unsigned int h = seed ^ len;
// Mix 4 bytes at a time into the hash
const unsigned char * data = (const unsigned char *)key;
while(len >= 4)
{
unsigned int k = *(reinterpret_cast<const unsigned int *>(data));
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
data += 4;
len -= 4;
}
// Handle the last few bytes of the input array
switch(len)
{
case 3: h ^= data[2] << 16;
Q_FALLTHROUGH();
case 2: h ^= data[1] << 8;
Q_FALLTHROUGH();
case 1: h ^= data[0];
h *= m;
};
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
} // namespace NGL
@@ -0,0 +1,13 @@
/**
* Simple and fast hash for logger strings
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
namespace NGL
{
unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed = 0 );
}
@@ -0,0 +1,450 @@
/**
* Implementatioin of INGLLogger interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "NGLLogger.h"
#include "MurmurHash2.h"
#include <cstdlib>
#include <iostream>
#include <log4qt/logger.h>
#include <log4qt/logmanager.h>
#include <log4qt/loggerrepository.h>
#include <log4qt/propertyconfigurator.h>
#include <log4qt/rollingfileappender.h>
#include <log4qt/helpers/configuratorhelper.h>
#include <log4qt/helpers/properties.h>
#include <log4qt/helpers/factory.h>
#include <mutex>
#include <unordered_map>
#include <QCoreApplication>
#include <QFileInfo>
namespace NGL
{
void LtsRollingFileAppender::setLtsLogfileName(const QString &ltsLogfileName)
{
m_ltsLogfileName = ltsLogfileName;
}
void LtsRollingFileAppender::activateOptions()
{
if (!m_ltsLogfileName.isEmpty())
setFile(m_ltsLogfileName);
Log4Qt::RollingFileAppender::activateOptions();
}
QString LtsRollingFileAppender::m_ltsLogfileName;
static Log4Qt::Appender *createLtsRollingFileAppender()
{
auto ret = new LtsRollingFileAppender;
ret->setAppendFile(true); // we want to append by default
return ret;
}
//==============================================================================
// Helper class zum korrekten Aufräumen beim Beenden
//==============================================================================
class CleanupHelper final
{
public:
CleanupHelper() = default;
~CleanupHelper();
std::mutex &getLoggerMapMutex();
std::unordered_map<unsigned int, NGL::NGLLogger *> m_loggermap;
protected:
std::mutex m_loggermapmutex;
};
//==============================================================================
//
//==============================================================================
NGL::NGLLogger *NGL::NGLLogger::rootlogger_ptr = nullptr;
NGL::CleanupHelper NGL::NGLLogger::s_cleanup;
//==============================================================================
//
//==============================================================================
CleanupHelper::~CleanupHelper()
{
std::lock_guard<std::mutex> lock(m_loggermapmutex);
for (auto it : m_loggermap)
delete it.second;
m_loggermap.clear();
delete NGL::NGLLogger::rootlogger_ptr;
NGL::NGLLogger::rootlogger_ptr = nullptr;
}
std::mutex &CleanupHelper::getLoggerMapMutex()
{
return m_loggermapmutex;
}
}
//==============================================================================
//
//==============================================================================
NGL::NGLLogger::NGLLogger(const std::string &fullqualifiedname)
: name(fullqualifiedname)
, currentLevel(LogLevel::Undefined)
, m_bNoSpace(true)
{
if (!fullqualifiedname.empty())
{
logger_ptr = Log4Qt::LogManager::loggerRepository()->logger(QString::fromStdString(name));
s_cleanup.m_loggermap[MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size())] = this;
}
else
{
logger_ptr = Log4Qt::LogManager::loggerRepository()->rootLogger();
// rootLogger wird in CleanupHelper gelöscht
}
// get current loglevel
configChanged();
}
//==============================================================================
//
//==============================================================================
NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const char *fullqualifiedname)
{
std::lock_guard<std::mutex> lock(s_cleanup.getLoggerMapMutex());
auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname, strlen(fullqualifiedname)));
if (it != s_cleanup.m_loggermap.end())
return *(*it).second;
return *(new NGLLogger(fullqualifiedname));
}
//==============================================================================
//
//==============================================================================
NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const std::string &fullqualifiedname)
{
std::lock_guard<std::mutex> lock(s_cleanup.getLoggerMapMutex());
auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size()));
if (it != s_cleanup.m_loggermap.end())
return *(*it).second;
return *(new NGLLogger(fullqualifiedname));
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::log(LogLevel level, const INGLLogger::String &message, const char *file, int line, const char *function)
{
logger_ptr->logWithLocation(static_cast<Log4Qt::Level::Value>(level), file, line, function, QString::fromStdString(message));
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::logTrace(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Trace)
log(LogLevel::Trace, message, file, line, function);
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::logDebug(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Debug)
log(LogLevel::Debug, message, file, line, function);
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::logInfo(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Info)
log(LogLevel::Info, message, file, line, function);
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::logWarning(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Warning)
log(LogLevel::Warning, message, file, line, function);
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::logError(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Error)
log(LogLevel::Error, message, file, line, function);
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::logFatal(const INGLLogger::String &message, const char *file, int line, const char *function)
{
log(LogLevel::Fatal, message, file, line, function);
}
//==============================================================================
//
//==============================================================================
#ifndef LTS_VERSION_MAJOR
#define LTS_VERSION_MAJOR "undefined"
#endif
#ifndef LTS_VERSION_MINOR
#define LTS_VERSION_MINOR "undefined"
#endif
#ifndef LTS_VERSION_PATCH
#define LTS_VERSION_PATCH "undefined"
#endif
#ifndef LTS_VERSION_DATE
#define LTS_VERSION_DATE "undefined"
#endif
#ifndef JENKINS_BUILD_NUMBER
#define JENKINS_BUILD_NUMBER "unknown"
#endif
static const char ver_major[] = LTS_VERSION_MAJOR;
static const char ver_minor[] = LTS_VERSION_MINOR;
static const char ver_patch[] = LTS_VERSION_PATCH;
static const char ver_date[] = LTS_VERSION_DATE;
static const char ver_jenkins[] = JENKINS_BUILD_NUMBER;
void NGL::NGLLogger::logStartup(const char *file, int line, const char *function)
{
log(LogLevel::Info, QStringLiteral("Application is started (%1.%2-%3 rev%4 from %5)")
.arg(QString::fromLatin1(ver_major),
QString::fromLatin1(ver_minor),
QString::fromLatin1(ver_jenkins),
QString::fromLatin1(ver_patch),
QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function);
}
//==============================================================================
//
//==============================================================================
void NGL::NGLLogger::logShutdown(const char *file, int line, const char *function)
{
log(LogLevel::Info, QStringLiteral("Application is shut down (%1.%2-%3 rev%4 from %5)")
.arg(QString::fromLatin1(ver_major),
QString::fromLatin1(ver_minor),
QString::fromLatin1(ver_jenkins),
QString::fromLatin1(ver_patch),
QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function);
}
//==============================================================================
//
//==============================================================================
NGL::NGLLogger &NGL::NGLLogger::getNGLRootLogger()
{
if (!rootlogger_ptr) throw NotCreatedError();
return *rootlogger_ptr;
}
//==============================================================================
// Try to find the given config file
//==============================================================================
static QString findConfigFile(const QString &configfilename)
{
if (configfilename.isEmpty())
return QString();
// 1. Absolute path or does file exists in cwd
QFileInfo fi(configfilename);
if (fi.isFile() && fi.isReadable())
return fi.absoluteFilePath();
// 2. Search same dir like executable
QString p = QCoreApplication::applicationDirPath() + QLatin1Char('/') + configfilename;
fi.setFile(p);
if (fi.isFile() && fi.isReadable())
return fi.absoluteFilePath();
return QString();
}
//==============================================================================
//
//==============================================================================
NGL::NGLLogger &NGL::NGLLogger::createNGLRootLogger(const QString &configfilename,
bool ignorealreadycreated,
const QString &logOutputName,
bool quiet)
{
if (rootlogger_ptr)
{
if (!ignorealreadycreated) throw AlreadyCreatedError();
}
else
{
Log4Qt::Factory::registerAppender("Lts::RollingFileAppender", createLtsRollingFileAppender);
LtsRollingFileAppender::setLtsLogfileName(logOutputName);
rootlogger_ptr = new NGLLogger(std::string());
const QString filename = findConfigFile(configfilename);
if (!filename.isEmpty())
{
Log4Qt::PropertyConfigurator::configureAndWatch(filename);
QObject::connect(Log4Qt::ConfiguratorHelper::instance(), &Log4Qt::ConfiguratorHelper::configurationFileChanged,
[]() { configurationFileChanged(); });
const auto l = Log4Qt::ConfiguratorHelper::instance()->configureError();
for (const auto &t : l)
std::cerr << t.message().toUtf8().data() << std::endl;
if (!l.isEmpty())
exit(-1);
}
else
{
if (!quiet)
std::cerr << "Could not find log4cxx configuration file " << configfilename << std::endl
<< "Using default logging to stdout" << std::endl;
// fallback if file does not exist -> output all to stdout
Log4Qt::Properties props;
props.setProperty(QLatin1String("log4j.rootLogger"),
QLatin1String("WARN, stdout"));
props.setProperty(QLatin1String("log4j.appender.stdout"),
QLatin1String("org.apache.log4j.ConsoleAppender"));
props.setProperty(QLatin1String("log4j.appender.stdout.layout"),
QLatin1String("org.apache.log4j.PatternLayout"));
props.setProperty(QLatin1String("log4j.appender.stdout.layout.ConversionPattern"),
QLatin1String("%d %-5p %c |#| %m (%.50F:%L) %n"));
Log4Qt::PropertyConfigurator::configure(props);
}
rootlogger_ptr->configChanged();
}
return *rootlogger_ptr;
}
void NGL::NGLLogger::configurationFileChanged()
{
for (auto ptr : s_cleanup.m_loggermap)
ptr.second->configChanged();
}
void NGL::NGLLogger::configChanged()
{
if (logger_ptr->isTraceEnabled())
currentLevel = LogLevel::Trace;
else if (logger_ptr->isDebugEnabled())
currentLevel = LogLevel::Debug;
else if (logger_ptr->isInfoEnabled())
currentLevel = LogLevel::Info;
else if (logger_ptr->isWarnEnabled())
currentLevel = LogLevel::Warning;
else if (logger_ptr->isErrorEnabled())
currentLevel = LogLevel::Error;
else
currentLevel = LogLevel::Fatal;
}
namespace NGL
{
namespace NGLLoggerHelper
{
void hexDumpHelper(NGL::INGLLogger &logger, NGL::LogLevel level,
const void *a_data, const unsigned int a_size)
{
if (!logger.isLevelEnabled(level) || !a_data)
return;
unsigned char *data = (unsigned char *)a_data;
QByteArray baBuf;
for (unsigned int i = 0; i < a_size; i++)
{
if (0 == (i % 8))
baBuf = QByteArray::number(i, 16).rightJustified(8, '0').toUpper();
baBuf += " " + QByteArray::number(data[i], 16).rightJustified(2, '0').toUpper();
if (7 == (i % 8))
logger.log(level, baBuf.constData(), __FILE__, __LINE__);
}
if (a_size % 8)
logger.log(level, baBuf.constData(), __FILE__, __LINE__);
}
} // namespace NGLLoggerHelper
NGL::INGLLogger& getMemoryLogger()
{
try
{
return NGLLogger::getNGLRootLogger().getNGLLogger("memorystate");
// return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("memorystate");
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
int parseLine(char* line){
// This assumes that a digit will be found and the line ends in " Kb".
int i = strlen(line);
const char* p = line;
while (*p <'0' || *p > '9') p++;
line[i-3] = '\0';
i = atoi(p);
return i;
}
int getMemoryValue()
{
//Note: this value is in KB!
FILE* file = fopen("/proc/self/status", "r");
int result = -1;
char line[128];
while (fgets(line, 128, file) != NULL){
// if (strncmp(line, "VmSize:", 7) == 0){
if (strncmp(line, "VmRSS:", 6) == 0){
result = parseLine(line);
break;
}
}
fclose(file);
return result;
}
std::string getMemoryData()
{
return QStringLiteral("VmRSS: %1 kB #").arg(QString::number(getMemoryValue())).toStdString();
}
} // namespace NGL
//==============================================================================
//
//==============================================================================
@@ -0,0 +1,98 @@
/**
* Implementatioin of INGLLogger interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#ifndef BUILDING_NGLLOGGER
#error Do not include me outside NGLLogger library - only use INGLLogger.h!
#endif
#include "INGLLogger.h"
#include <string>
#include <log4qt/logger.h>
#include <log4qt/rollingfileappender.h>
namespace NGL
{
class CleanupHelper;
class LtsRollingFileAppender final : public Log4Qt::RollingFileAppender
{
Q_OBJECT
public:
using Log4Qt::RollingFileAppender::RollingFileAppender;
static void setLtsLogfileName(const QString &ltsLogfileName);
void activateOptions() override;
private:
static QString m_ltsLogfileName;
};
class NGLLogger final : public INGLLogger
{
explicit NGLLogger(const std::string &fullqualifiedname);
public:
class NotCreatedError {};
class AlreadyCreatedError {};
INGLLogger &getNGLLogger(const char *fullqualifiedname) override;
INGLLogger &getNGLLogger(const std::string &fullqualifiedname) override;
inline bool isTraceEnabled() const override { return currentLevel <= LogLevel::Trace; }
inline bool isDebugEnabled() const override { return currentLevel <= LogLevel::Debug; }
inline bool isInfoEnabled() const override { return currentLevel <= LogLevel::Info; }
inline bool isWarningEnabled() const override { return currentLevel <= LogLevel::Warning; }
inline bool isErrorEnabled() const override { return currentLevel <= LogLevel::Error; }
inline bool isFatalEnabled() const override { return currentLevel <= LogLevel::Fatal; }
inline bool isLevelEnabled(LogLevel level) const override { return currentLevel <= level; }
void log(LogLevel level, const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override;
void logTrace(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override;
void logDebug(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override;
void logInfo(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override;
void logWarning(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override;
void logError(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override;
void logFatal(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override;
void logStartup(const char *file, int line, const char *function = nullptr) override;
void logShutdown(const char *file, int line, const char *function = nullptr) override;
inline void setNoSpace(bool bNoSpace) override { m_bNoSpace = bNoSpace; }
inline bool noSpace() const override { return m_bNoSpace; }
inline std::string getLoggerName() const override { return name; }
static NGLLogger &getNGLRootLogger();
static NGLLogger &createNGLRootLogger(const QString &configfilename,
bool ignorealreadycreated,
const QString &logOutputName = QString(),
bool quiet = false);
Log4Qt::Logger *log4qtLogger() { return logger_ptr; }
protected:
static void configurationFileChanged();
void configChanged();
private:
Log4Qt::Logger *logger_ptr;
const std::string name;
LogLevel currentLevel;
bool m_bNoSpace;
static NGLLogger *rootlogger_ptr;
friend class CleanupHelper;
static CleanupHelper s_cleanup;
friend class XMLWatchdog;
};
} //namespace NGL
@@ -0,0 +1,34 @@
/**
* Logger initialization
* $Id$
* $HeadURL$
* $Author$
*/
#include "NGLLoggerBootstrap.h"
#include "NGLLogger.h"
//==============================================================================
//
//==============================================================================
NGL::INGLLogger & NGL::NGLLoggerBootstrap::getNGLRootLogger()
{
return NGL::NGLLogger::getNGLRootLogger();
}
//==============================================================================
//
//==============================================================================
NGL::INGLLogger & NGL::NGLLoggerBootstrap::createNGLRootLogger(const QString &configfilename,
bool ignorealreadycreated,
const QString &logOutputName,
bool quiet)
{
return NGL::NGLLogger::createNGLRootLogger(configfilename, ignorealreadycreated, logOutputName, quiet);
}
//==============================================================================
//
//==============================================================================
@@ -0,0 +1,63 @@
/**
* Logger initialization
* $Id$
* $HeadURL$
* $Author$
*/
#ifndef NGLLOGGERBOOTSTRAP_H
#define NGLLOGGERBOOTSTRAP_H
#include "INGLLogger.h"
#include "NGLLogger_export.h"
namespace NGL
{
// obain an INGLLogger interface implementation.
namespace NGLLoggerBootstrap
{
class AlreadyCreatedError final : public std::exception
{
const char* what() const noexcept override
{
return "NGLLogger rootlogger already created!";
}
};
class NotCreatedError final : public std::exception
{
const char* what() const noexcept override
{
return "NGLLogger rootlogger not yet created!";
}
};
// Returns a reference to the root logger. The root-logger must be
// created beforehand,
// otherwise a NotCreatedError exception is thrown.
NGLLOGGER_EXPORT INGLLogger &getNGLRootLogger();
// Creates the root logger. If the root logger already has been created
// an AlreadyCreatedError exception ist thrown unless the
// ignorealreadycreated parameter is set to true, in that case the
// existing root logger is returned and the filename and lookup
// interval are ignored.
// The filename sets the path of the property-configuration file and
// the seconds parameter sets the lookup interval for this file.
NGLLOGGER_EXPORT INGLLogger &createNGLRootLogger(const QString &configfilename,
bool ignorealreadycreated,
const QString &logOutputName = QString(),
bool quiet = false);
inline INGLLogger &createNGLRootLogger(const char *configfilename,
bool ignorealreadycreated,
const QString &logOutputName = QString())
{
return createNGLRootLogger(QString::fromUtf8(configfilename), ignorealreadycreated, logOutputName);
}
} // namespace NGLLoggerBootstrap
} // namespace NGL
#endif //NGLLOGGERBOOTSTRAP_H
@@ -0,0 +1,26 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#ifndef NGLLOGGER_EXPORT_H
#define NGLLOGGER_EXPORT_H
#ifndef NGLLOGGER_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLLOGGER_EXPORT
# else
# ifdef WIN32
# ifdef MAKE_NGLLOGGER_LIB
# define NGLLOGGER_EXPORT __declspec(dllexport)
# else
# define NGLLOGGER_EXPORT __declspec(dllimport)
# endif
# else
# define NGLLOGGER_EXPORT __attribute__((visibility("default")))
# endif
# endif
#endif
#endif // NGLLOGGER_EXPORT_H
@@ -0,0 +1,42 @@
log4j.reset=true
log4j.rootLogger=ERROR, stdout
log4j.logger.Gui=TRACE, console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%p %d %t %c{1} - %F:%L %m%n
log4j.logger.ngs=FATAL, stdout
log4j.logger.ngs.Application_1=INFO, file
log4j.logger.ngs.Application_2=ERROR
log4j.logger.ngs.Application_3=ERROR
log4j.logger.libsymbol.SymbolTable=WARN, stdout
log4j.logger.libsymbol.SymbolReader=WARN, stdout
log4j.logger.libngldb=INFO, stdout
log4j.logger.NGL.main=INFO, stdout, file
log4j.logger.NGL.MainWindow=INFO, stdout, file
log4j.logger.NGL.zwmsqt=INFO, stdout, file
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=#ngs# %r %p %d %t %c %c{1} - %F:%L %m%n
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=9
log4j.appender.file.file=log.out
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=#ngs# %r %p %d %t %c %c{1} - %F:%L %m%n
log4j.appender.syslog=org.apache.log4j.SyslogAppender
log4j.appender.syslog.Threshold=WARN
log4j.appender.syslog.SysLogHost=localhost
log4j.appender.syslog.Facility=LOCAL7
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
@@ -0,0 +1,34 @@
#include "INGLLogger.h"
#include "NGLLoggerBootstrap.h"
#include <QCoreApplication>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx.props", false);
NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger(). getNGLLogger( "Gui" );
STARTUP_LOG(l);
SHUTDOWN_LOG(l);
NOTICE_LOG(l) << "Gui - NOTICE";
TRACE_LOG(l) << "Gui - TRACE";
DEBUG_LOG(l) << "Gui - DEBUG";
INFO_LOG(l) << "Gui - INFO";
WARNING_LOG(l) << "Gui - WARNING";
ERROR_LOG(l) << "Gui - ERROR";
FATAL_LOG(l) << "Gui - FATAL";
NGL::INGLLogger &l2 = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger( "Gui.AES" );
NOTICE_LOG(l2) << "Gui.AES - NOTICE";
TRACE_LOG(l2) << "Gui.AES - TRACE";
DEBUG_LOG(l2) << "Gui.AES - DEBUG";
INFO_LOG(l2) << "Gui.AES - INFO";
WARNING_LOG(l2) << "Gui.AES - WARNING";
ERROR_LOG(l2) << "Gui.AES - ERROR";
FATAL_LOG(l2) << "Gui.AES - FATAL";
SHUTDOWN_LOG(l2)
return 0;
}
@@ -0,0 +1,51 @@
# QtSingleApplication solution from
# http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Utilities/qtsingleapplication
# LGPL
SET(qtsapp_common_SRCS
qtlocalpeer.cpp
qtlocalpeer.h
)
QT5_WRAP_CPP(qtsapp_common_SRCS qtlockedfile.h)
NGL_ADD_LIBRARY(WS AAR SV qtsa_common STATIC ${qtsapp_common_SRCS})
NGL_TARGET_LINK_LIBRARIES(qtsa_common
PUBLIC
Qt5::Network
Qt5::Core
)
SET(qtsapp_SRCS
qtsingleapplication.cpp
qtsingleapplication.h
)
NGL_ADD_LIBRARY(WS qtsingleapplication SHARED ${qtsapp_SRCS})
NGL_INSTALL_TARGET(qtsingleapplication)
NGL_TARGET_INCLUDE_DIRECTORIES(qtsingleapplication
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/..
)
NGL_TARGET_LINK_LIBRARIES(qtsingleapplication
PRIVATE
qtsa_common
PUBLIC
Qt5::Core
Qt5::Widgets
)
SET(qtscoreapp_SRCS
qtsinglecoreapplication.h
qtsinglecoreapplication.cpp
)
NGL_ADD_LIBRARY(AAR SV qtsinglecoreapplication SHARED ${qtscoreapp_SRCS})
NGL_INSTALL_TARGET(qtsinglecoreapplication)
NGL_TARGET_INCLUDE_DIRECTORIES(qtsinglecoreapplication
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/..
)
NGL_TARGET_LINK_LIBRARIES(qtsinglecoreapplication
PRIVATE
qtsa_common
PUBLIC
Qt5::Core
)
@@ -0,0 +1 @@
#include "qtlockedfile.h"
@@ -0,0 +1 @@
#include "qtsingleapplication.h"
@@ -0,0 +1 @@
#include "qtsinglecoreapplication.h"
@@ -0,0 +1,204 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlocalpeer.h"
#include <QCoreApplication>
#include <QDataStream>
#include <QTime>
#if defined(Q_OS_WIN)
#include <QLibrary>
#include <qt_windows.h>
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
static PProcessIdToSessionId pProcessIdToSessionId = 0;
#endif
#if defined(Q_OS_UNIX)
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
namespace QtLP_Private {
#include "qtlockedfile.cpp"
#if defined(Q_OS_WIN)
#include "qtlockedfile_win.cpp"
#else
#include "qtlockedfile_unix.cpp"
#endif
}
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
: QObject(parent), id(appId)
{
QString prefix = id;
if (id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
id = id.toLower();
#endif
prefix = id.section(QLatin1Char('/'), -1);
}
prefix.remove(QRegExp(QLatin1String("[^a-zA-Z]")));
prefix.truncate(6);
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib(QLatin1String("kernel32"));
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile");
lockFile.setFileName(lockName);
lockFile.open(QIODevice::ReadWrite);
}
bool QtLocalPeer::isClient()
{
if (lockFile.isLocked())
return false;
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
return true;
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
res = server->listen(socketName);
}
#endif
if (!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection);
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
{
if (!isClient())
return false;
QLocalSocket socket;
bool connOk = false;
for(int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout/2);
if (connOk || i)
break;
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, nullptr);
#endif
}
if (!connOk)
return false;
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if (res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if (res)
res &= (socket.read(qstrlen(ack)) == ack);
}
return res;
}
void QtLocalPeer::receiveConnection()
{
QLocalSocket* socket = server->nextPendingConnection();
if (!socket)
return;
while (socket->bytesAvailable() < (int)sizeof(quint32))
socket->waitForReadyRead();
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
if (got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
emit messageReceived(message); //### (might take a long time to return)
}
@@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCALPEER_H
#define QTLOCALPEER_H
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include "qtlockedfile.h"
class QtLocalPeer : public QObject
{
Q_OBJECT
public:
QtLocalPeer(QObject *parent = nullptr, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
QString applicationId() const
{ return id; }
Q_SIGNALS:
void messageReceived(const QString &message);
protected Q_SLOTS:
void receiveConnection();
protected:
QString id;
QString socketName;
QLocalServer* server;
QtLP_Private::QtLockedFile lockFile;
private:
static const char* ack;
};
#endif // QTLOCALPEER_H
@@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
/*!
\class QtLockedFile
\brief The QtLockedFile class extends QFile with advisory locking
functions.
A file may be locked in read or write mode. Multiple instances of
\e QtLockedFile, created in multiple processes running on the same
machine, may have a file locked in read mode. Exactly one instance
may have it locked in write mode. A read and a write lock cannot
exist simultaneously on the same file.
The file locks are advisory. This means that nothing prevents
another process from manipulating a locked file using QFile or
file system functions offered by the OS. Serialization is only
guaranteed if all processes that access the file use
QLockedFile. Also, while holding a lock on a file, a process
must not open the same file again (through any API), or locks
can be unexpectedly lost.
The lock provided by an instance of \e QtLockedFile is released
whenever the program terminates. This is true even when the
program crashes and no destructors are called.
*/
/*! \enum QtLockedFile::LockMode
This enum describes the available lock modes.
\value ReadLock A read lock.
\value WriteLock A write lock.
\value NoLock Neither a read lock nor a write lock.
*/
/*!
Constructs an unlocked \e QtLockedFile object. This constructor
behaves in the same way as \e QFile::QFile().
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile()
: QFile()
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Constructs an unlocked QtLockedFile object with file \a name. This
constructor behaves in the same way as \e QFile::QFile(const
QString&).
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile(const QString &name)
: QFile(name)
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Opens the file in OpenMode \a mode.
This is identical to QFile::open(), with the one exception that the
Truncate mode flag is disallowed. Truncation would conflict with the
advisory file locking, since the file would be modified before the
write lock is obtained. If truncation is required, use resize(0)
after obtaining the write lock.
Returns true if successful; otherwise false.
\sa QFile::open(), QFile::resize()
*/
bool QtLockedFile::open(OpenMode mode)
{
if (mode & QIODevice::Truncate) {
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
return false;
}
return QFile::open(mode);
}
/*!
Returns \e true if this object has a in read or write lock;
otherwise returns \e false.
\sa lockMode()
*/
bool QtLockedFile::isLocked() const
{
return m_lock_mode != NoLock;
}
/*!
Returns the type of lock currently held by this object, or \e
QtLockedFile::NoLock.
\sa isLocked()
*/
QtLockedFile::LockMode QtLockedFile::lockMode() const
{
return m_lock_mode;
}
/*!
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
Obtains a lock of type \a mode. The file must be opened before it
can be locked.
If \a block is true, this function will block until the lock is
aquired. If \a block is false, this function returns \e false
immediately if the lock cannot be aquired.
If this object already has a lock of type \a mode, this function
returns \e true immediately. If this object has a lock of a
different type than \a mode, the lock is first released and then a
new lock is obtained.
This function returns \e true if, after it executes, the file is
locked by this object, and \e false otherwise.
\sa unlock(), isLocked(), lockMode()
*/
/*!
\fn bool QtLockedFile::unlock()
Releases a lock.
If the object has no lock, this function returns immediately.
This function returns \e true if, after it executes, the file is
not locked by this object, and \e false otherwise.
\sa lock(), isLocked(), lockMode()
*/
/*!
\fn QtLockedFile::~QtLockedFile()
Destroys the \e QtLockedFile object. If any locks were held, they
are released.
*/
@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCKEDFILE_H
#define QTLOCKEDFILE_H
#include <QFile>
#ifdef Q_OS_WIN
#include <QVector>
#endif
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)
# if defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# endif
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
# elif defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTLOCKEDFILE_EXPORT
#endif
namespace QtLP_Private {
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
{
Q_OBJECT
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
explicit QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
#ifdef Q_OS_WIN
Qt::HANDLE wmutex;
Qt::HANDLE rmutex;
QVector<Qt::HANDLE> rmutexes;
QString mutexname;
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
#endif
LockMode m_lock_mode;
};
}
#endif
@@ -0,0 +1,115 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qtlockedfile.h"
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
int cmd = block ? F_SETLKW : F_SETLK;
int ret = fcntl(handle(), cmd, &fl);
if (ret == -1) {
if (errno != EINTR && errno != EAGAIN)
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
int ret = fcntl(handle(), F_SETLKW, &fl);
if (ret == -1) {
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
}
@@ -0,0 +1,211 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
#include <qt_windows.h>
#include <QFileInfo>
#define MUTEX_PREFIX "QtLockedFile mutex "
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
#if QT_VERSION >= 0x050000
#define QT_WA(unicode, ansi) unicode
#endif
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
{
if (mutexname.isEmpty()) {
QFileInfo fi(*this);
mutexname = QString::fromLatin1(MUTEX_PREFIX)
+ fi.absoluteFilePath().toLower();
}
QString mname(mutexname);
if (idx >= 0)
mname += QString::number(idx);
Qt::HANDLE mutex;
if (doCreate) {
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
return 0;
}
}
else {
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
if (GetLastError() != ERROR_FILE_NOT_FOUND)
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
return 0;
}
}
return mutex;
}
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
{
Q_ASSERT(mutex);
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
switch (res) {
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
return true;
break;
case WAIT_TIMEOUT:
break;
default:
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
}
return false;
}
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
return false;
if (!waitMutex(wmutex, block))
return false;
if (mode == ReadLock) {
int idx = 0;
for (; idx < MAX_READERS; idx++) {
rmutex = getMutexHandle(idx, false);
if (!rmutex || waitMutex(rmutex, false))
break;
CloseHandle(rmutex);
}
bool ok = true;
if (idx >= MAX_READERS) {
qWarning("QtLockedFile::lock(): too many readers");
rmutex = 0;
ok = false;
}
else if (!rmutex) {
rmutex = getMutexHandle(idx, true);
if (!rmutex || !waitMutex(rmutex, false))
ok = false;
}
if (!ok && rmutex) {
CloseHandle(rmutex);
rmutex = 0;
}
ReleaseMutex(wmutex);
if (!ok)
return false;
}
else {
Q_ASSERT(rmutexes.isEmpty());
for (int i = 0; i < MAX_READERS; i++) {
Qt::HANDLE mutex = getMutexHandle(i, false);
if (mutex)
rmutexes.append(mutex);
}
if (rmutexes.size()) {
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
TRUE, block ? INFINITE : 0);
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
if (res != WAIT_TIMEOUT)
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
unlock();
return false;
}
}
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
if (m_lock_mode == ReadLock) {
ReleaseMutex(rmutex);
CloseHandle(rmutex);
rmutex = 0;
}
else {
for (Qt::HANDLE mutex : qAsConst(rmutexes)) {
ReleaseMutex(mutex);
CloseHandle(mutex);
}
rmutexes.clear();
ReleaseMutex(wmutex);
}
m_lock_mode = QtLockedFile::NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
if (wmutex)
CloseHandle(wmutex);
}
@@ -0,0 +1,291 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsingleapplication.h"
#include "qtlocalpeer.h"
#include <QWidget>
/*!
\class QtSingleApplication qtsingleapplication.h
\brief The QtSingleApplication class provides an API to detect and
communicate with running instances of an application.
This class allows you to create applications where only one
instance should be running at a time. I.e., if the user tries to
launch another instance, the already running instance will be
activated instead. Another usecase is a client-server system,
where the first started instance will assume the role of server,
and the later instances will act as clients of that server.
By default, the full path of the executable file is used to
determine whether two processes are instances of the same
application. You can also provide an explicit identifier string
that will be compared instead.
The application should create the QtSingleApplication object early
in the startup phase, and call isRunning() to find out if another
instance of this application is already running. If isRunning()
returns false, it means that no other instance is running, and
this instance has assumed the role as the running instance. In
this case, the application should continue with the initialization
of the application user interface before entering the event loop
with exec(), as normal.
The messageReceived() signal will be emitted when the running
application receives messages from another instance of the same
application. When a message is received it might be helpful to the
user to raise the application so that it becomes visible. To
facilitate this, QtSingleApplication provides the
setActivationWindow() function and the activateWindow() slot.
If isRunning() returns true, another instance is already
running. It may be alerted to the fact that another instance has
started by using the sendMessage() function. Also data such as
startup parameters (e.g. the name of the file the user wanted this
new instance to open) can be passed to the running instance with
this function. Then, the application should terminate (or enter
client mode).
If isRunning() returns true, but sendMessage() fails, that is an
indication that the running instance is frozen.
Here's an example that shows how to convert an existing
application to use QtSingleApplication. It is very simple and does
not make use of all QtSingleApplication's functionality (see the
examples for that).
\code
// Original
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyMainWidget mmw;
mmw.show();
return app.exec();
}
// Single instance
int main(int argc, char **argv)
{
QtSingleApplication app(argc, argv);
if (app.isRunning())
return !app.sendMessage(someDataString);
MyMainWidget mmw;
app.setActivationWindow(&mmw);
mmw.show();
return app.exec();
}
\endcode
Once this QtSingleApplication instance is destroyed (normally when
the process exits or crashes), when the user next attempts to run the
application this instance will not, of course, be encountered. The
next instance to call isRunning() or sendMessage() will assume the
role as the new running instance.
For console (non-GUI) applications, QtSingleCoreApplication may be
used instead of this class, to avoid the dependency on the QtGui
library.
\sa QtSingleCoreApplication
*/
void QtSingleApplication::sysInit(const QString &appId)
{
actWin = nullptr;
peer = new QtLocalPeer(this, appId);
connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived);
}
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a GUIenabled are passed on to the QAppliation constructor.
If you are creating a console application (i.e. setting \a
GUIenabled to false), you may consider using
QtSingleCoreApplication instead.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
: QApplication(argc, argv, GUIenabled)
{
sysInit();
}
/*!
Creates a QtSingleApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv)
{
sysInit(appId);
}
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleApplication::id() const
{
return peer->applicationId();
}
/*!
Sets the activation window of this application to \a aw. The
activation window is the widget that will be activated by
activateWindow(). This is typically the application's main window.
If \a activateOnMessage is true (the default), the window will be
activated automatically every time a message is received, just prior
to the messageReceived() signal being emitted.
\sa activateWindow(), messageReceived()
*/
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
{
actWin = aw;
if (activateOnMessage)
connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
else
disconnect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
}
/*!
Returns the applications activation window if one has been set by
calling setActivationWindow(), otherwise returns 0.
\sa setActivationWindow()
*/
QWidget* QtSingleApplication::activationWindow() const
{
return actWin;
}
/*!
De-minimizes, raises, and activates this application's activation window.
This function does nothing if no activation window has been set.
This is a convenience function to show the user that this
application instance has been activated when he has tried to start
another instance.
This function should typically be called in response to the
messageReceived() signal. By default, that will happen
automatically, if an activation window has been set.
\sa setActivationWindow(), messageReceived(), initialize()
*/
void QtSingleApplication::activateWindow()
{
if (actWin) {
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
actWin->raise();
actWin->activateWindow();
}
}
/*!
\fn void QtSingleApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage(), setActivationWindow(), activateWindow()
*/
/*!
\fn void QtSingleApplication::initialize(bool dummy = true)
\obsolete
*/
@@ -0,0 +1,93 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QApplication>
class QtLocalPeer;
#ifndef QTSINGLEAPPLICATION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define QTSINGLEAPPLICATION_EXPORT
# else
# if defined(MAKE_QTSINGLEAPPLICATION_LIB)
# define QTSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT
# else
# define QTSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
class QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
{
Q_OBJECT
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &appId, int &argc, char **argv);
bool isRunning();
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const;
// Obsolete:
void initialize(bool dummy = true)
{ isRunning(); Q_UNUSED(dummy) }
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
void activateWindow();
Q_SIGNALS:
void messageReceived(const QString &message);
private:
void sysInit(const QString &appId = QString());
QtLocalPeer *peer;
QWidget *actWin;
};
#endif // QTSINGLEAPPLICATION_H
@@ -0,0 +1,149 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsinglecoreapplication.h"
#include "qtlocalpeer.h"
/*!
\class QtSingleCoreApplication qtsinglecoreapplication.h
\brief A variant of the QtSingleApplication class for non-GUI applications.
This class is a variant of QtSingleApplication suited for use in
console (non-GUI) applications. It is an extension of
QCoreApplication (instead of QApplication). It does not require
the QtGui library.
The API and usage is identical to QtSingleApplication, except that
functions relating to the "activation window" are not present, for
obvious reasons. Please refer to the QtSingleApplication
documentation for explanation of the usage.
A QtSingleCoreApplication instance can communicate to a
QtSingleApplication instance if they share the same application
id. Hence, this class can be used to create a light-weight
command-line tool that sends commands to a GUI application.
\sa QtSingleApplication
*/
/*!
Creates a QtSingleCoreApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc and \a
argv are passed on to the QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this);
connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleCoreApplication::messageReceived);
}
/*!
Creates a QtSingleCoreApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this, appId);
connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleCoreApplication::messageReceived);
}
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleCoreApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleCoreApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleCoreApplication::id() const
{
return peer->applicationId();
}
/*!
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage()
*/
@@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLECOREAPPLICATION_H
#define QTSINGLECOREAPPLICATION_H
#include <QCoreApplication>
class QtLocalPeer;
#ifndef QTSINGLECOREAPPLICATION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define QTSINGLEAPPLICATION_EXPORT
# else
# if defined(MAKE_QTSINGLECOREAPPLICATION_LIB)
# define QTSINGLECOREAPPLICATION_EXPORT Q_DECL_EXPORT
# else
# define QTSINGLECOREAPPLICATION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
class QTSINGLECOREAPPLICATION_EXPORT QtSingleCoreApplication : public QCoreApplication
{
Q_OBJECT
public:
QtSingleCoreApplication(int &argc, char **argv);
QtSingleCoreApplication(const QString &appId, int &argc, char **argv);
bool isRunning();
QString id() const;
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
Q_SIGNALS:
void messageReceived(const QString &message);
private:
QtLocalPeer* peer;
};
#endif // QTSINGLECOREAPPLICATION_H
@@ -0,0 +1,35 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(wms_ds_SRCS
IECC2WMS.h
IWMS2ECC.h
wms_ecc_equipmenttypes.cpp
wms_ecc_equipmenttypes.h
wms_ecc_equipRequirements.cpp
wms_ecc_equipRequirements.h
wms_ecc_exercises.cpp
wms_ecc_exercises.h
wms_ecc_ibase.h
wms_ecc_playerInfo.cpp
wms_ecc_playerInfo.h
wms_ecc_registration.cpp
wms_ecc_registration.h
wms_ecc_unregister.cpp
wms_ecc_unregister.h
json_keys.h
)
NGL_ADD_LIBRARY2(AAR SV wms_json_ds SHARED ${wms_ds_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(wms_json_ds
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(wms_json_ds
PUBLIC
Qt5::Core
)
@@ -0,0 +1,25 @@
/**
* @RDE_HEADER@
* Interface zwischen ECC und WMS
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
namespace WmsJson
{
class IECC2WMS
{
public:
IECC2WMS() = default;
virtual ~IECC2WMS() = default;
// Wird von EXCON aufgerufen
virtual void playerChanged(int playerId, int exerciseId) = 0;
virtual void exerciseDataChanged(int exerciseId, int betrZustand) = 0;
};
} // namespace WmsJson
@@ -0,0 +1,142 @@
/**
* @RDE_HEADER@
* Interface zwischen WMS und ECC
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QString>
#include <QMap>
#include <QSet>
#include <QMetaType>
class IWMS2ECC
{
public:
IWMS2ECC() = default;
virtual ~IWMS2ECC() = default;
enum RegisterReturnValue
{
RegistrationOk = 0,
PlayerNotFound = 1,
PlayerDeleted = 2,
AssignmentIncorrect = 3,
EquipNoAlreadyAssigned = 4,
RegistrationFailed = 5
};
enum UnregisterReturnValue
{
UnregisterOk = 0,
EquipNoNotFound = 1,
UnregisterFailed = 2
};
enum PlayerState
{
NOT_FOUND = 0,
FOUND = 1,
DELETED = 2
};
enum PlayerAssignState
{
UNDEFINED = -2,
NOT_ASSIGNED = -1,
ASSIGNED = 0,
HANDOUT_EXCON = 1,
HANDOUT_WMS = 2,
HANDOUT_EXCON_OVERRULED_WMS = 3
};
static inline PlayerAssignState int2PlayerAssignState(int s)
{
switch (s)
{
case UNDEFINED:
case NOT_ASSIGNED:
case ASSIGNED:
case HANDOUT_EXCON:
case HANDOUT_WMS:
case HANDOUT_EXCON_OVERRULED_WMS:
return static_cast<PlayerAssignState>(s);
}
Q_ASSERT(false);
return UNDEFINED;
}
struct PlayerInfo
{
PlayerState playerState = NOT_FOUND;
int playerId = -1;
int parentPlayerId = -1;
int equipNo = -1;
PlayerAssignState assignState = UNDEFINED;
int exerciseId = -1;
int forceId = -1;
int typeId = -1;
int equipTypeId = -1;
int typeClassId = -1;
int symbolColor = -1;
bool isDeleted = false;
QByteArray symbolPNG;
QString hierarchy;
QString designator;
QString tactIdent;
QString info;
QString alias;
QString forceName;
};
struct Exercise
{
int id = -1;
int actExercise = 0;
time_t start = 0;
time_t end = 0;
QString name;
QString stateAsString;
};
using exerciseMap = QMap<int, Exercise>;
struct EquipmentType
{
QString name;
int id = 0;
int specialType = 0;
int minEquipNo = 0;
int maxEquipNo = 0;
int taVulnerabilityModelId = 0; //ta = Training Area
int taPlayerTypeId = 0;
bool deletedInWMS = false;
};
using equipTypeMap = QMap<int, EquipmentType>;
// Pure virtual functions
virtual RegisterReturnValue registerPlayer(int playerId, int equipNo, const PlayerAssignState &zuordnung, const QString &alias,
const QString &info, int exerciseId) = 0;
virtual UnregisterReturnValue unregister(int equipNo, int exerciseId) = 0;
virtual PlayerInfo getPlayerInfo(int playerId, int exerciseId) = 0;
virtual exerciseMap getExercises() const = 0;
virtual Exercise getActualExercise() const = 0;
// QMap<EquipmentTypeId,Amount>
virtual QMap<int, int> getEquipRequirements(int exerciseId) const = 0;
virtual QMap<int, PlayerInfo> getAllPlayers(int exerciseId) const = 0;
virtual QMap<int, PlayerInfo> getAllVehicles(int exerciseId) const = 0;
virtual int getPlayerId(int equipNo, int exerciseId) const = 0;
virtual int getEquipNo(int playerId, int exerciseId) const = 0;
virtual int getTypeClassId(int equipTypeId) const = 0;
};
Q_DECLARE_METATYPE(IWMS2ECC::Exercise)
Q_DECLARE_METATYPE(IWMS2ECC::EquipmentType)
Q_DECLARE_METATYPE(IWMS2ECC::RegisterReturnValue)
@@ -0,0 +1,59 @@
/**
* @RDE_HEADER@
* Header file which holds all occuring JSON keys
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, SLST, 2017-12-05
*/
#pragma once
#include <QtCore/QString>
namespace WebSocketInterface
{
/**
* @brief Namespace which holds all occuring JSON keys as const QString objects
*/
namespace JsonKeys
{
inline QString EXERCISE_ID() { return QStringLiteral("exerciseId"); }
inline QString DATA_MODIFICATION() { return QStringLiteral("dataModification"); }
inline QString PARTICIPANT_ID() { return QStringLiteral("participantId"); }
inline QString REGISTRATION_RETURN_VALUE() { return QStringLiteral("registrationReturnValue"); }
// types for client --> server messages
inline QString EQUIPMENT_TYPES_REQUEST() { return QStringLiteral("equipmentTypesRequest"); }
// types for server --> client messages
inline QString EQUIPMENT_TYPES_REPLY() { return QStringLiteral("equipmentTypesReply"); }
// types for client --> server messages
inline QString EXERCISES_REQUEST() { return QStringLiteral("exercisesRequest"); }
// types for server --> client messages
inline QString EXERCISES_REPLY() { return QStringLiteral("exercisesReply"); }
// types for server --> client messages
inline QString EXERCISE_UPDATE() { return QStringLiteral("exercisesUpdate"); }
// types for client --> server messages
inline QString PARTICIPANTS_REQUEST() { return QStringLiteral("participantsRequest"); }
// types for server --> client messages
inline QString PARTICIPANTS_REPLY() { return QStringLiteral("participantsReply"); }
// types for server --> client messages
inline QString PARTICIPANTS_UPDATE() { return QStringLiteral("participantsUpdate"); }
// types for client --> server messages
inline QString PARTICIPANT_REGISTER_IN_EXCON_REQUEST() { return QStringLiteral("participantRegisterInEXCONRequest");}
// types for server --> client messages
inline QString PARTICIPANT_REGISTER_IN_EXCON_REPLY() { return QStringLiteral("participantRegisterInEXCONReply");}
// data keys
} // namespace JsonKeys
} // namespace WebSocketInterface
@@ -0,0 +1,76 @@
/**
* @RDE_HEADER@
* Interface client <-> server - EquipRequirements
* $Id$
* $HeadURL$
* $Author$
*/
#include "wms_ecc_equipRequirements.h"
#include <QJsonArray>
#include <QJsonObject>
QJsonObject EquipRequirements::toJson() const
{
QJsonArray arr;
for (QMap<int, int>::ConstIterator it = m_equipRequire.begin(); it != m_equipRequire.end(); ++it)
{
QJsonObject obj;
obj[QLatin1String("key")] = it.key();
obj[QLatin1String("value")] = it.value();
arr.append(obj);
}
QJsonObject retMap;
retMap[QLatin1String("equipMap")] = arr;
retMap[QLatin1String("ok")] = m_ok;
return retMap;
}
EquipRequirements EquipRequirements::fromJson(const QJsonObject &map)
{
EquipRequirements eq;
const QJsonArray arr = map[QLatin1String("equipMap")].toArray();
for (const auto &ele : arr)
{
const QJsonObject obj = ele.toObject();
int equipmentTypeId = obj[QLatin1String("key")].toInt();
int amount = obj[QLatin1String("value")].toInt();
eq.m_equipRequire.insert(equipmentTypeId, amount);
}
eq.m_ok = map[QLatin1String("ok")].toBool();
return eq;
}
QVariantMap EquipRequirements::toVariantMap() const
{
QVariantMap viMap;
for (QMap<int, int>::ConstIterator it = m_equipRequire.begin(); it != m_equipRequire.end(); ++it)
viMap.insert(QString::number(it.key()), QVariant(it.value()));
QVariantMap retMap;
retMap[QLatin1String("equipMap")] = QVariant(viMap);
retMap[QLatin1String("ok")] = QVariant(m_ok);
return retMap;
}
EquipRequirements EquipRequirements::fromVariantMap(const QVariantMap &map)
{
EquipRequirements eq;
const QVariantMap viMap = map[QLatin1String("equipMap")].toMap();
for (QVariantMap::ConstIterator it = viMap.begin(); it != viMap.end(); ++it)
{
const int key = it.key().toInt();
eq.m_equipRequire.insert(key, it.value().toInt());
}
eq.m_ok = map[QLatin1String("ok")].toBool();
return eq;
}
@@ -0,0 +1,35 @@
/**
* @RDE_HEADER@
* Interface client(WMS) <-> server (ECC) - PlayerInfo
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "wms_ecc_ibase.h"
#include "IWMS2ECC.h"
#include <QtCore/QVariantMap>
class WMS_JSON_DS_EXPORT EquipRequirements : public IBase
{
public:
QJsonObject toJson() const;
static EquipRequirements fromJson(const QJsonObject &map);
QVariantMap toVariantMap() const;
static EquipRequirements fromVariantMap(const QVariantMap &map);
// <EquipmentTypeId,Amount>
QMap<int, int> getEquipRequirements() const { return m_equipRequire; }
bool getOk() const { return m_ok; }
void setEquipRequirements(const QMap<int, int> &equip) { m_equipRequire = equip; }
void setOk(bool ok) { m_ok = ok; }
private:
QMap<int, int> m_equipRequire;
bool m_ok = false;
};
@@ -0,0 +1,137 @@
/**
* @RDE_HEADER@
* Interface client <-> server - EquipmentTypes
* $Id$
* $HeadURL$
* $Author$
*/
#include "wms_ecc_equipmenttypes.h"
#include <QJsonArray>
QJsonObject EquipmentTypes::toJson(const IWMS2ECC::EquipmentType &et)
{
QJsonObject obj;
obj[QLatin1String("id")] = et.id;
obj[QLatin1String("name")] = et.name;
obj[QLatin1String("minEquipNo")] = et.minEquipNo;
obj[QLatin1String("maxEquipNo")] = et.maxEquipNo;
obj[QLatin1String("specialType")] = et.specialType;
obj[QLatin1String("taVulnerabilityModelId")] = et.taVulnerabilityModelId;
obj[QLatin1String("taPlayerTypeId")] = et.taPlayerTypeId;
obj[QLatin1String("deletedInWMS")] = et.deletedInWMS;
return obj;
}
IWMS2ECC::EquipmentType EquipmentTypes::fromJson(const QJsonObject &obj)
{
IWMS2ECC::EquipmentType et;
et.id = obj[QLatin1String("id")].toInt();
et.name = obj[QLatin1String("name")].toString();
et.minEquipNo = obj[QLatin1String("minEquipNo")].toInt();
et.maxEquipNo = obj[QLatin1String("maxEquipNo")].toInt();
et.specialType = obj[QLatin1String("specialType")].toInt();
et.taVulnerabilityModelId = obj[QLatin1String("taVulnerabilityModelId")].toInt();
et.taPlayerTypeId = obj[QLatin1String("taPlayerTypeId")].toInt();
et.deletedInWMS = obj[QLatin1String("deletedInWMS")].toBool();
return et;
}
QJsonObject EquipmentTypes::toJsonAll() const
{
QJsonArray arr;
for (const IWMS2ECC::EquipmentType &et : m_equipmentTypes)
arr.append(toJson(et));
QJsonObject retMap;
retMap[QLatin1String("etMap")] = arr;
retMap[QLatin1String("ok")] = m_ok;
return retMap;
}
EquipmentTypes EquipmentTypes::fromJsonAll(const QJsonObject &map)
{
EquipmentTypes ets;
const QJsonArray arr = map[QLatin1String("etMap")].toArray();
for (const auto &ele : arr)
{
const IWMS2ECC::EquipmentType val = fromJson(ele.toObject());
ets.m_equipmentTypes.insert(val.id, val);
}
ets.m_ok = map[QLatin1String("ok")].toBool();
return ets;
}
QVariantMap EquipmentTypes::toVariantMap() const
{
QVariantMap vMap;
vMap[QLatin1String("id")] = QVariant(m_equipmentType.id);
vMap[QLatin1String("name")] = m_equipmentType.name;
vMap[QLatin1String("minEquipNo")] = QVariant((int)m_equipmentType.minEquipNo);
vMap[QLatin1String("maxEquipNo")] = QVariant((int)m_equipmentType.maxEquipNo);
vMap[QLatin1String("specialType")] = QVariant(m_equipmentType.specialType);
vMap[QLatin1String("deletedInWMS")] = QVariant(m_equipmentType.deletedInWMS);
vMap[QLatin1String("ok")] = QVariant(m_ok);
return vMap;
}
EquipmentTypes EquipmentTypes::fromVariantMap(const QVariantMap &map)
{
EquipmentTypes ets;
ets.m_equipmentType.id = map[QLatin1String("id")].toInt();
ets.m_equipmentType.name = map[QLatin1String("name")].toString();
ets.m_equipmentType.minEquipNo = map[QLatin1String("minEquipNo")].toInt();
ets.m_equipmentType.maxEquipNo = map[QLatin1String("maxEquipNo")].toInt();
ets.m_equipmentType.specialType = map[QLatin1String("specialType")].toInt();
ets.m_equipmentType.deletedInWMS = map[QLatin1String("deletedInWMS")].toBool();
ets.m_ok = map[QLatin1String("ok")].toBool();
return ets;
}
QVariantMap EquipmentTypes::toVariantMapAll() const
{
QVariantMap vMap;
for (IWMS2ECC::equipTypeMap::ConstIterator it = m_equipmentTypes.begin(); it != m_equipmentTypes.end(); ++it)
{
m_equipmentType = it.value(); // really?
vMap.insert(QString::number(it.key()), QVariant(toVariantMap()));
}
QVariantMap retMap;
retMap[QLatin1String("etMap")] = QVariant(vMap);
retMap[QLatin1String("ok")] = QVariant(m_ok);
return retMap;
}
EquipmentTypes EquipmentTypes::fromVariantMapAll(const QVariantMap &map)
{
EquipmentTypes ets;
const QVariantMap vMap = map[QLatin1String("etMap")].toMap();
for (QVariantMap::ConstIterator it = vMap.begin(); it != vMap.end(); ++it)
{
int key = it.key().toInt();
IWMS2ECC::EquipmentType et = EquipmentTypes::fromVariantMap(it.value().toMap()).m_equipmentType;
ets.m_equipmentTypes.insert(key, et);
}
ets.m_ok = map[QLatin1String("ok")].toBool();
return ets;
}
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Interface client(WMS) <-> server (ECC) - PlayerInfo
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "wms_ecc_ibase.h"
#include "IWMS2ECC.h"
#include <QJsonObject>
#include <QVariantMap>
class WMS_JSON_DS_EXPORT EquipmentTypes : public IBase
{
public:
QJsonObject toJsonAll() const;
static EquipmentTypes fromJsonAll(const QJsonObject &map);
static QJsonObject toJson(const IWMS2ECC::EquipmentType &et);
static IWMS2ECC::EquipmentType fromJson(const QJsonObject &obj);
QVariantMap toVariantMapAll() const;
static EquipmentTypes fromVariantMapAll(const QVariantMap &map);
QVariantMap toVariantMap() const;
static EquipmentTypes fromVariantMap(const QVariantMap &map);
IWMS2ECC::EquipmentType getEquipmentType() const { return m_equipmentType; }
IWMS2ECC::equipTypeMap getEquipmentTypes() const { return m_equipmentTypes; }
bool getOk() const { return m_ok; }
void setEquipmentType(const IWMS2ECC::EquipmentType &et) { m_equipmentType = et; }
void setEquipmentTypes(const IWMS2ECC::equipTypeMap &map) { m_equipmentTypes = map; }
void setOk(bool ok) { m_ok = ok; }
private:
IWMS2ECC::equipTypeMap m_equipmentTypes;
mutable IWMS2ECC::EquipmentType m_equipmentType; // because of strange assignment in toVariantMapAll()
bool m_ok = false;
};
@@ -0,0 +1,140 @@
/**
* @RDE_HEADER@
* Interface client <-> server - Exercises
* $Id$
* $HeadURL$
* $Author$
*/
#include "wms_ecc_exercises.h"
#include <QJsonArray>
#include <QJsonObject>
namespace EXCON
{
QJsonObject Exercises::toJson(const IWMS2ECC::Exercise &ex) const
{
QJsonObject obj;
obj[QLatin1String("id")] = ex.id;
obj[QLatin1String("actExercise")] = ex.actExercise;
obj[QLatin1String("start")] = static_cast<qint64>(ex.start);
obj[QLatin1String("end")] = static_cast<qint64>(ex.end);
obj[QLatin1String("name")] = ex.name;
obj[QLatin1String("state")] = ex.stateAsString;
obj[QLatin1String("ok")] = m_ok;
return obj;
}
IWMS2ECC::Exercise Exercises::fromJson(const QJsonObject &obj)
{
IWMS2ECC::Exercise ex;
ex.id = obj[QLatin1String("id")].toInt();
ex.actExercise = obj[QLatin1String("actExercise")].toInt();
ex.start = static_cast<time_t>(obj[QLatin1String("start")].toInt());
ex.end = static_cast<time_t>(obj[QLatin1String("end")].toInt());
ex.name = obj[QLatin1String("name")].toString();
ex.stateAsString = obj[QLatin1String("state")].toString();
return ex;
}
QJsonObject Exercises::toJsonAll() const
{
QJsonArray arr;
for (const IWMS2ECC::Exercise &ex : m_exercises)
arr.append(toJson(ex));
QJsonObject obj;
obj[QLatin1String("exMap")] = arr;
obj[QLatin1String("ok")] = m_ok;
return obj;
}
Exercises Exercises::fromJsonAll(const QJsonObject &map)
{
Exercises ex;
const QJsonArray arr = map[QLatin1String("exMap")].toArray();
for (const QJsonValue &val : arr)
{
const IWMS2ECC::Exercise exinfo = fromJson(val.toObject());
ex.m_exercises.insert(exinfo.id, exinfo);
}
ex.m_ok = map[QLatin1String("ok")].toBool();
return ex;
}
QVariantMap Exercises::toVariantMap() const
{
QVariantMap vMap;
vMap[QLatin1String("id")] = QVariant(m_exercise.id);
vMap[QLatin1String("name")] = m_exercise.name;
vMap[QLatin1String("start")] = QVariant(static_cast<qint64>(m_exercise.start));
vMap[QLatin1String("end")] = QVariant(static_cast<qint64>(m_exercise.end));
vMap[QLatin1String("state")] = m_exercise.stateAsString;
vMap[QLatin1String("ok")] = QVariant(m_ok);
return vMap;
}
Exercises Exercises::fromVariantMap(const QVariantMap &map)
{
Exercises ex;
ex.m_exercise.id = map[QLatin1String("id")].toInt();
ex.m_exercise.name = map[QLatin1String("name")].toString();
ex.m_exercise.start = map[QLatin1String("start")].toLongLong();
ex.m_exercise.end = map[QLatin1String("end")].toLongLong();
ex.m_exercise.stateAsString = map[QLatin1String("state")].toString();
ex.m_ok = map[QLatin1String("ok")].toBool();
return ex;
}
QVariantMap Exercises::toVariantMapAll() const
{
QVariantMap vMap;
for (IWMS2ECC::exerciseMap::ConstIterator it = m_exercises.begin(); it != m_exercises.end(); ++it)
{
m_exercise = it.value(); // really?
vMap.insert(QString::number(it.key()), QVariant(toVariantMap()));
}
QVariantMap retMap;
retMap[QLatin1String("exeMap")] = QVariant(vMap);
retMap[QLatin1String("ok")] = QVariant(m_ok);
return retMap;
}
Exercises Exercises::fromVariantMapAll(const QVariantMap &map)
{
Exercises ex;
const QVariantMap vMap = map[QLatin1String("exeMap")].toMap();
for (QVariantMap::ConstIterator it = vMap.begin(); it != vMap.end(); ++it)
{
//ex.m_exercises.insert(keyStr.toInt(), Exercises::fromVariantMap(vMap[keyStr].toMap()).m_exercise);
int key = it.key().toInt();
IWMS2ECC::Exercise e = Exercises::fromVariantMap(it.value().toMap()).m_exercise;
ex.m_exercises.insert(key, e);
}
ex.m_ok = map[QLatin1String("ok")].toBool();
return ex;
}
} // namespace EXCON
@@ -0,0 +1,46 @@
/**
* @RDE_HEADER@
* Interface client(WMS) <-> server (ECC) - PlayerInfo
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "wms_ecc_ibase.h"
#include "IWMS2ECC.h"
#include <QVariantMap>
namespace EXCON
{
class WMS_JSON_DS_EXPORT Exercises : public IBase
{
public:
QJsonObject toJsonAll() const;
static Exercises fromJsonAll(const QJsonObject &map);
QJsonObject toJson(const IWMS2ECC::Exercise &ex) const;
static IWMS2ECC::Exercise fromJson(const QJsonObject &obj);
QVariantMap toVariantMapAll() const;
static Exercises fromVariantMapAll(const QVariantMap &map);
QVariantMap toVariantMap() const;
static Exercises fromVariantMap(const QVariantMap &map);
IWMS2ECC::Exercise getExercise() const { return m_exercise; }
IWMS2ECC::exerciseMap getExercises() const { return m_exercises; }
bool getOk() const { return m_ok; }
void setExercise(const IWMS2ECC::Exercise &exe) { m_exercise = exe; }
void setExercises(const IWMS2ECC::exerciseMap &exe) { m_exercises = exe; }
void setOk(bool ok) { m_ok = ok; }
private:
IWMS2ECC::exerciseMap m_exercises;
mutable IWMS2ECC::Exercise m_exercise; // because of strange assignment in toVariantMapAll()
bool m_ok = false;
};
}
@@ -0,0 +1,20 @@
/**
* @RDE_HEADER@
* Base Class for interface classes
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <WMS_Interface/wms_json_ds_export.h>
class WMS_JSON_DS_EXPORT IBase
{
public:
IBase() = default;
virtual ~IBase() = default;
};
@@ -0,0 +1,181 @@
/**
* @RDE_HEADER@
* Interface client <-> server - PlayerInfo
* $Id$
* $HeadURL$
* $Author$
*/
#include "wms_ecc_playerInfo.h"
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
QJsonObject PlayerInfo::toJson(const IWMS2ECC::PlayerInfo &pi)
{
QJsonObject obj;
obj[QLatin1String("playerState")] = pi.playerState;
obj[QLatin1String("playerId")] = pi.playerId;
obj[QLatin1String("parentPlayerId")] = pi.parentPlayerId;
obj[QLatin1String("equipNo")] = pi.equipNo;
obj[QLatin1String("assignState")] = pi.assignState;
obj[QLatin1String("exerciseId")] = pi.exerciseId;
obj[QLatin1String("forceId")] = pi.forceId;
obj[QLatin1String("typeId")] = pi.typeId;
obj[QLatin1String("isDeleted")] = pi.isDeleted;
obj[QLatin1String("equipTypeId")] = pi.equipTypeId;
obj[QLatin1String("typeClassId")] = pi.typeClassId;
obj[QLatin1String("symbolColor")] = pi.symbolColor;
obj[QLatin1String("symbolPNG")] = QString::fromLatin1(pi.symbolPNG.toBase64());
obj[QLatin1String("hierarchy")] = pi.hierarchy;
obj[QLatin1String("designator")] = pi.designator;
obj[QLatin1String("tactIdent")] = pi.tactIdent;
obj[QLatin1String("info")] = pi.info;
obj[QLatin1String("alias")] = pi.alias;
obj[QLatin1String("forceName")] = pi.forceName;
return obj;
}
IWMS2ECC::PlayerInfo PlayerInfo::fromJson(const QJsonObject &obj)
{
IWMS2ECC::PlayerInfo pi;
pi.playerState = static_cast<IWMS2ECC::PlayerState>(obj[QLatin1String("playerState")].toInt());
pi.playerId = obj[QLatin1String("playerId")].toInt();
pi.parentPlayerId = obj[QLatin1String("parentPlayerId")].toInt();
pi.equipNo = obj[QLatin1String("equipNo")].toInt();
pi.assignState = static_cast<IWMS2ECC::PlayerAssignState>(obj[QLatin1String("assignState")].toInt());
pi.exerciseId = obj[QLatin1String("exerciseId")].toInt();
pi.forceId = obj[QLatin1String("forceId")].toInt();
pi.typeId = obj[QLatin1String("typeId")].toInt();
pi.isDeleted = obj[QLatin1String("isDeleted")].toBool();
pi.equipTypeId = obj[QLatin1String("equipTypeId")].toInt();
pi.typeClassId = obj[QLatin1String("typeClassId")].toInt();
pi.symbolColor = obj[QLatin1String("symbolColor")].toInt();
pi.symbolPNG = QByteArray::fromBase64(obj[QLatin1String("symbolPNG")].toString().toLatin1());
pi.hierarchy = obj[QLatin1String("hierarchy")].toString();
pi.designator = obj[QLatin1String("designator")].toString();
pi.tactIdent = obj[QLatin1String("tactIdent")].toString();
pi.info = obj[QLatin1String("info")].toString();
pi.alias = obj[QLatin1String("alias")].toString();
pi.forceName = obj[QLatin1String("forceName")].toString();
return pi;
}
QJsonObject PlayerInfo::toJsonAll() const
{
QJsonArray arr;
for (const IWMS2ECC::PlayerInfo &pi : m_allPlayerInfo)
arr.append(toJson(pi));
QJsonObject retMap;
retMap[QLatin1String("piMap")] = arr;
retMap[QLatin1String("ok")] = m_ok;
return retMap;
}
PlayerInfo PlayerInfo::fromJsonAll(const QJsonObject &map)
{
PlayerInfo pi;
const QJsonArray arr = map[QLatin1String("piMap")].toArray();
for (const QJsonValue &val : arr)
{
const IWMS2ECC::PlayerInfo player = fromJson(val.toObject());
pi.m_allPlayerInfo.insert(player.playerId, player);
}
pi.m_ok = map[QLatin1String("ok")].toBool();
return pi;
}
QVariantMap PlayerInfo::toVariantMap() const
{
QVariantMap retMap;
retMap[QLatin1String("playerId")] = QVariant(m_playerInfo.playerId);
retMap[QLatin1String("parentPlayerId")] = QVariant(m_playerInfo.parentPlayerId);
retMap[QLatin1String("equipNo")] = QVariant(m_playerInfo.equipNo);
retMap[QLatin1String("equipTypeId")] = QVariant(m_playerInfo.equipTypeId);
retMap[QLatin1String("typeClassId")] = QVariant(m_playerInfo.typeClassId);
retMap[QLatin1String("forceId")] = QVariant(m_playerInfo.forceId);
retMap[QLatin1String("designator")] = m_playerInfo.designator;
retMap[QLatin1String("tactIdent")] = m_playerInfo.tactIdent;
retMap[QLatin1String("hierarchy")] = m_playerInfo.hierarchy;
retMap[QLatin1String("forceName")] = m_playerInfo.forceName;
retMap[QLatin1String("info")] = m_playerInfo.info;
retMap[QLatin1String("alias")] = m_playerInfo.alias;
retMap[QLatin1String("symbolPNG")] = QVariant(m_playerInfo.symbolPNG);
retMap[QLatin1String("symbolColor")] = QVariant(m_playerInfo.symbolColor);
retMap[QLatin1String("assignState")] = QVariant(m_playerInfo.assignState);
retMap[QLatin1String("playerState")] = QVariant(m_playerInfo.playerState);
retMap[QLatin1String("ok")] = QVariant(m_ok);
return retMap;
}
PlayerInfo PlayerInfo::fromVariantMap(const QVariantMap &map)
{
PlayerInfo pi;
pi.m_playerInfo.playerId = map[QLatin1String("playerId")].toInt();
pi.m_playerInfo.parentPlayerId = map[QLatin1String("parentPlayerId")].toInt();
pi.m_playerInfo.equipNo = map[QLatin1String("equipNo")].toInt();
pi.m_playerInfo.forceId = map[QLatin1String("forceId")].toInt();
pi.m_playerInfo.equipTypeId = map[QLatin1String("equipTypeId")].toInt();
pi.m_playerInfo.typeClassId = map[QLatin1String("typeClassId")].toInt();
pi.m_playerInfo.designator = map[QLatin1String("designator")].toString();
pi.m_playerInfo.tactIdent = map[QLatin1String("tactIdent")].toString();
pi.m_playerInfo.hierarchy = map[QLatin1String("hierarchy")].toString();
pi.m_playerInfo.forceName = map[QLatin1String("forceName")].toString();
pi.m_playerInfo.info = map[QLatin1String("info")].toString();
pi.m_playerInfo.alias = map[QLatin1String("alias")].toString();
pi.m_playerInfo.symbolPNG = map[QLatin1String("symbolPNG")].toByteArray();
pi.m_playerInfo.symbolColor = map[QLatin1String("symbolColor")].toInt();
pi.m_playerInfo.assignState = (IWMS2ECC::PlayerAssignState) map[QLatin1String("assignState")].toInt();
pi.m_playerInfo.playerState = (IWMS2ECC::PlayerState) map[QLatin1String("playerState")].toInt();
pi.m_ok = map[QLatin1String("ok")].toBool();
return pi;
}
QVariantMap PlayerInfo::toVariantMapAll() const
{
QVariantMap vMap;
for (const IWMS2ECC::PlayerInfo &pi : m_allPlayerInfo)
{
m_playerInfo = pi; // really?
vMap.insert(QString::number(pi.playerId), QVariant(toVariantMap()));
}
QVariantMap retMap;
retMap[QLatin1String("plMap")] = QVariant(vMap);
retMap[QLatin1String("ok")] = QVariant(m_ok);
return retMap;
}
PlayerInfo PlayerInfo::fromVariantMapAll(const QVariantMap &map)
{
PlayerInfo players;
const QVariantMap vMap = map[QLatin1String("plMap")].toMap();
for (const QVariant &data : vMap)
{
PlayerInfo player = PlayerInfo::fromVariantMap(data.toMap());
IWMS2ECC::PlayerInfo pi = player.getPlayerInfo();
players.m_allPlayerInfo.insert(pi.playerId, pi);
}
players.m_ok = vMap[QLatin1String("ok")].toBool();
return players;
}
@@ -0,0 +1,45 @@
/**
* @RDE_HEADER@
* Interface client(WMS) <-> server (ECC) - PlayerInfo
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "wms_ecc_ibase.h"
#include "IWMS2ECC.h"
#include <QtCore/QVariantMap>
class WMS_JSON_DS_EXPORT PlayerInfo : public IBase
{
public:
static QJsonObject toJson(const IWMS2ECC::PlayerInfo &pi);
static IWMS2ECC::PlayerInfo fromJson(const QJsonObject &obj);
QJsonObject toJsonAll() const;
static PlayerInfo fromJsonAll(const QJsonObject &map);
QVariantMap toVariantMap() const;
static PlayerInfo fromVariantMap(const QVariantMap &map);
QVariantMap toVariantMapAll() const;
static PlayerInfo fromVariantMapAll(const QVariantMap &map);
IWMS2ECC::PlayerInfo getPlayerInfo() const { return m_playerInfo; }
QMap<int, IWMS2ECC::PlayerInfo> getAllPlayerInfo() const { return m_allPlayerInfo; }
bool getOk() const { return m_ok; }
void setPlayerInfo(const IWMS2ECC::PlayerInfo &info) { m_playerInfo = info; }
void setAllPlayerInfo(const QMap<int, IWMS2ECC::PlayerInfo> &pi) { m_allPlayerInfo = pi; }
void setOk(bool ok) { m_ok = ok; }
private:
QMap<int, IWMS2ECC::PlayerInfo> m_allPlayerInfo;
mutable IWMS2ECC::PlayerInfo m_playerInfo; // because of strange assignment in toVariantMapAll()
bool m_ok = false;
};
@@ -0,0 +1,94 @@
/**
* @RDE_HEADER@
* Interface client <-> server - Registration
* $Id$
* $HeadURL$
* $Author$
*/
#include "wms_ecc_registration.h"
#include <QJsonObject>
QJsonObject Registration::toJson() const
{
QJsonObject obj;
obj[QLatin1String("playerId")] = m_playerId;
obj[QLatin1String("assignment")] = m_assignment;
obj[QLatin1String("exerciseId")] = m_exerciseId;
obj[QLatin1String("ok")] = m_ok;
if (m_bEquipNoIsSet)
obj[QLatin1String("equipNo")] = m_equipNo;
if (m_bAliasIsSet)
obj[QLatin1String("alias")] = m_alias;
if (m_bInfoIsSet)
obj[QLatin1String("info")] = m_info;
return obj;
}
Registration Registration::fromJson(const QJsonObject &obj)
{
Registration rg;
rg.m_playerId = obj[QLatin1String("playerId")].toInt();
rg.m_assignment = IWMS2ECC::int2PlayerAssignState(obj[QLatin1String("assignment")].toInt());
rg.m_exerciseId = obj[QLatin1String("exerciseId")].toInt();
rg.m_bEquipNoIsSet = obj.contains(QLatin1String("equipNo"));
if (rg.m_bEquipNoIsSet)
rg.m_equipNo = obj[QLatin1String("equipNo")].toInt();
rg.m_bAliasIsSet = obj.contains(QLatin1String("alias"));
if (rg.m_bAliasIsSet)
rg.m_alias = obj[QLatin1String("alias")].toString();
rg.m_bInfoIsSet = obj.contains(QLatin1String("info"));
if (rg.m_bInfoIsSet)
rg.m_info = obj[QLatin1String("info")].toString();
rg.m_ok = obj[QLatin1String("ok")].toBool();
return rg;
}
QVariantMap Registration::toVariantMap() const
{
QVariantMap retMap;
retMap[QLatin1String("playerId")] = QVariant(m_playerId);
retMap[QLatin1String("assignment")] = QVariant(m_assignment);
retMap[QLatin1String("exerciseId")] = QVariant(m_exerciseId);
if (m_bEquipNoIsSet)
retMap[QLatin1String("equipNo")] = QVariant(m_equipNo);
if (m_bAliasIsSet)
retMap[QLatin1String("alias")] = m_alias;
if (m_bInfoIsSet)
retMap[QLatin1String("info")] = m_info;
retMap[QLatin1String("ok")] = QVariant(m_ok);
return retMap;
}
Registration Registration::fromVariantMap(const QVariantMap &map)
{
Registration rg;
rg.m_playerId = map[QLatin1String("playerId")].toInt();
rg.m_assignment = IWMS2ECC::int2PlayerAssignState(map[QLatin1String("assignment")].toInt());
rg.m_exerciseId = map[QLatin1String("exerciseId")].toInt();
rg.m_ok = map[QLatin1String("ok")].toBool();
rg.m_bEquipNoIsSet = map.contains(QLatin1String("equipNo"));
if (rg.m_bEquipNoIsSet)
rg.m_equipNo = map[QLatin1String("equipNo")].toInt();
rg.m_bAliasIsSet = map.contains(QLatin1String("alias"));
if (rg.m_bAliasIsSet)
rg.m_alias = map[QLatin1String("alias")].toString();
rg.m_bInfoIsSet = map.contains(QLatin1String("info"));
if (rg.m_bInfoIsSet)
rg.m_info = map[QLatin1String("info")].toString();
return rg;
}
@@ -0,0 +1,60 @@
/**
* @RDE_HEADER@
* Interface client(WMS) <-> server (ECC) - registration
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "wms_ecc_ibase.h"
#include "IWMS2ECC.h"
#include <QtCore/QString>
#include <QtCore/QVariantMap>
class WMS_JSON_DS_EXPORT Registration : public IBase
{
public:
QJsonObject toJson() const;
static Registration fromJson(const QJsonObject &obj);
QVariantMap toVariantMap() const;
static Registration fromVariantMap(const QVariantMap &map);
int getPlayerId() const { return m_playerId; }
int getEquipNo() const { return m_equipNo; }
int getExerciseId() const { return m_exerciseId; }
QString getAlias() const { return m_alias; }
QString getInfo() const { return m_info; }
bool isEquipNoSet() const { return m_bEquipNoIsSet; }
bool isAliasSet() const { return m_bAliasIsSet; }
bool isInfoSet() const { return m_bInfoIsSet; }
IWMS2ECC::PlayerAssignState getAssignment() const { return m_assignment; }
bool getOk() const { return m_ok; }
void setPlayerId(int playerId) { m_playerId = playerId; }
void setEquipNo(int equipNo) { m_equipNo = equipNo; m_bEquipNoIsSet = true; }
void setAssignment(IWMS2ECC::PlayerAssignState assignment) { m_assignment = assignment; }
void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; }
void setAlias(const QString &alias) { m_alias = alias; m_bAliasIsSet = true; }
void setInfo(const QString &info) { m_info = info; m_bInfoIsSet = true; }
void setOk(bool ok) { m_ok = ok; }
private:
QString m_alias;
QString m_info;
IWMS2ECC::PlayerAssignState m_assignment = IWMS2ECC::UNDEFINED;
int m_playerId = 0;
int m_equipNo = 0;
int m_exerciseId = -1;
bool m_bEquipNoIsSet = false;
bool m_bAliasIsSet = false;
bool m_bInfoIsSet = false;
bool m_ok = false;
};
@@ -0,0 +1,55 @@
/**
* @RDE_HEADER@
* Interface client <-> server - Unregister
* $Id$
* $HeadURL$
* $Author$
*/
#include "wms_ecc_unregister.h"
#include <QJsonObject>
QJsonObject Unregister::toJson() const
{
QJsonObject obj;
obj[QLatin1String("equipNo")] = m_equipNo;
obj[QLatin1String("exerciseId")] = m_exerciseId;
obj[QLatin1String("ok")] = m_ok;
return obj;
}
Unregister Unregister::fromJson(const QJsonObject &obj)
{
Unregister ur;
ur.m_equipNo = obj[QLatin1String("equipNo")].toInt();
ur.m_exerciseId = obj[QLatin1String("exerciseId")].toInt();
ur.m_ok = obj[QLatin1String("ok")].toBool();
return ur;
}
QVariantMap Unregister::toVariantMap() const
{
QVariantMap retMap;
retMap[QLatin1String("equipNo")] = QVariant(m_equipNo);
retMap[QLatin1String("exerciseId")] = QVariant(m_exerciseId);
retMap[QLatin1String("ok")] = QVariant(m_ok);
return retMap;
}
Unregister Unregister::fromVariantMap(const QVariantMap &map)
{
Unregister ur;
ur.m_equipNo = map[QLatin1String("equipNo")].toInt();
ur.m_exerciseId = map[QLatin1String("exerciseId")].toInt();
ur.m_ok = map[QLatin1String("ok")].toBool();
return ur;
}
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Interface client(WMS) <-> server (ECC) - Unregister
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "wms_ecc_ibase.h"
#include <QtCore/QString>
#include <QtCore/QVariantMap>
class WMS_JSON_DS_EXPORT Unregister : public IBase
{
public:
QJsonObject toJson() const;
static Unregister fromJson(const QJsonObject &obj);
QVariantMap toVariantMap() const;
static Unregister fromVariantMap(const QVariantMap &map);
int getEquipNo() const { return m_equipNo; }
int getExerciseId() const { return m_exerciseId; }
bool getOk() const { return m_ok; }
void setEquipNo(int equipNo) { m_equipNo = equipNo; }
void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; }
void setOk(bool ok) { m_ok = ok; }
private:
int m_equipNo = 0;
int m_exerciseId = -1;
bool m_ok = false;
};
@@ -0,0 +1,134 @@
#
# $Id$
# $HeadURL$
# $Author$
#
#
# nglapplication
#
SET(nglapplication_SRCS
nglapplication.cpp
nglapplication.h
nglloggerhandler.cpp
nglloggerhandler.h
ngl_qt_msg_handler.inc
ngl_signal_handler.inc
)
NGL_ADD_LIBRARY(WS AAR SV HLA nglapplication SHARED ${nglapplication_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(nglapplication
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(nglapplication
PRIVATE
NGLLogger
nglsettings
PUBLIC
Qt5::Core
Qt5::Widgets
)
NGL_INSTALL_TARGET(nglapplication)
#
# nglsingleapplication
#
SET(nglsingleapplication_SRCS
nglsingleapplication.cpp
nglsingleapplication.h
nglloggerhandler.cpp
nglloggerhandler.h
ngl_qt_msg_handler.inc
ngl_signal_handler.inc
)
NGL_ADD_LIBRARY(WS nglsingleapplication SHARED ${nglsingleapplication_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(nglsingleapplication
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(nglsingleapplication
PRIVATE
NGLLogger
nglsettings
PUBLIC
qtsingleapplication
)
NGL_INSTALL_TARGET(nglsingleapplication)
#
# nglcoreapplication
#
SET(nglcoreapplication_SRCS
nglcoreapplication.cpp
nglcoreapplication.h
nglloggerhandler.cpp
nglloggerhandler.h
ngl_qt_msg_handler.inc
ngl_signal_handler.inc
)
NGL_ADD_LIBRARY(ALL nglcoreapplication SHARED ${nglcoreapplication_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(nglcoreapplication
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(nglcoreapplication
PRIVATE
NGLLogger
nglsettings
PUBLIC
Qt5::Core
)
NGL_INSTALL_TARGET(nglcoreapplication)
#
# nglsinglecoreapplication
#
SET(nglsinglecoreapplication_SRCS
nglsinglecoreapplication.cpp
nglsinglecoreapplication.h
nglloggerhandler.cpp
nglloggerhandler.h
ngl_qt_msg_handler.inc
ngl_signal_handler.inc
)
NGL_ADD_LIBRARY(AAR SV nglsinglecoreapplication SHARED ${nglsinglecoreapplication_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(nglsinglecoreapplication
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(nglsinglecoreapplication
PRIVATE
NGLLogger
nglsettings
PUBLIC
qtsinglecoreapplication
)
NGL_INSTALL_TARGET(nglsinglecoreapplication)
#
# nglguiapplication
#
SET(nglguiapplication_SRCS
nglguiapplication.cpp
nglguiapplication.h
nglloggerhandler.cpp
nglloggerhandler.h
ngl_qt_msg_handler.inc
ngl_signal_handler.inc
)
NGL_ADD_LIBRARY(ALL nglguiapplication SHARED ${nglguiapplication_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(nglguiapplication
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(nglguiapplication
PRIVATE
NGLLogger
nglsettings
PUBLIC
Qt5::Gui
)
NGL_INSTALL_TARGET(nglguiapplication)
@@ -0,0 +1,64 @@
/**
* @RDE_HEADER@
* callback to catch qt log messages
* $Id$
* $HeadURL$
* $Author$
*/
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QtCore/qglobal.h>
static void qtMsgHandler(QtMsgType type, const QMessageLogContext &, const QString &msg)
{
// pulse audio connect errors are important but can be very annoying - so only print it ONE time only and also as an error
static bool pulseAudioMessageSent = false;
static QString pulseAudioMessage = QStringLiteral("PulseAudioService: pa_context_connect() failed");
if (msg.startsWith(pulseAudioMessage))
{
if (pulseAudioMessageSent)
{
return;
}
type = QtCriticalMsg;
pulseAudioMessageSent = true;
}
try
{
NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger( "NGL.Qt" );
switch (type) {
case QtDebugMsg:
DEBUG_LOG(l) << msg ;
break;
case QtInfoMsg:
INFO_LOG(l) << msg ;
break;
case QtWarningMsg:
WARNING_LOG(l) << msg ;
break;
case QtCriticalMsg:
ERROR_LOG(l) << msg ;
break;
case QtFatalMsg:
FATAL_LOG(l) << msg ;
break;
}
} catch (...) {
switch (type)
{
case QtDebugMsg:
case QtInfoMsg:
fputs(qPrintable(msg), stdout);
break;
case QtWarningMsg:
case QtCriticalMsg:
case QtFatalMsg:
fputs(qPrintable(msg), stderr);
break;
}
}
}
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* small stub to catch SIGTERM for proper shutdown
* $Id$
* $HeadURL$
* $Author$
*/
#include <signal.h>
#include <QtCore/QCoreApplication>
#ifdef Q_OS_WIN
#include <QtCore/QAbstractNativeEventFilter>
#include <windows.h>
class MyEventFilter final : public QAbstractNativeEventFilter
{
public:
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override
{
Q_UNUSED(eventType);
Q_UNUSED(result);
const MSG *msg = reinterpret_cast<const MSG*>(message);
if (msg->message == WM_CLOSE && msg->hwnd == nullptr)
QCoreApplication::quit();
return false;
}
};
#endif
#ifndef SIGTERM
# define SIGTERM 15
#endif
static void signalHandler(int signal_number)
{
if(signal_number != SIGTERM)
return;
QCoreApplication::quit();
}
@@ -0,0 +1,36 @@
/**
* @RDE_HEADER@
* small extension to QApplication for window handling
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglapplication.h"
#include "ngl_signal_handler.inc"
//----------------------------------------------------------------------------
NGLApplication::NGLApplication(int &argc, char **argv)
: QApplication(argc, argv)
{
// auf SIGTERM reagieren
signal(SIGTERM, &signalHandler);
#ifdef Q_OS_WIN
installNativeEventFilter(new MyEventFilter);
#endif
}
//----------------------------------------------------------------------------
bool NGLApplication::notify(QObject *o, QEvent *e)
{
bool bRet = false;
try
{
bRet = QApplication::notify(o, e);
}
catch (const std::exception &e)
{
fprintf(stderr, "exception %s\n", e.what());
}
return bRet;
}
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* small extension to QApplication for window handling
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QApplication>
#include "nglloggerhandler.h"
#ifndef NGLAPPLICATION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLAPPLICATION_EXPORT
# else
# ifdef MAKE_NGLAPPLICATION_LIB
# define NGLAPPLICATION_EXPORT Q_DECL_EXPORT
# else
# define NGLAPPLICATION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
namespace NGL
{
class INGLLogger;
}
class NGLAPPLICATION_EXPORT NGLApplication : public QApplication, public NGL::LoggerHandler
{
Q_OBJECT
public:
NGLApplication(int &argc, char **argv);
protected:
bool notify(QObject *o, QEvent *e) override;
};
#define nglApp static_cast<NGLApplication*>(NGLApplication::instance())
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* small extension to QCoreApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglcoreapplication.h"
#include "ngl_signal_handler.inc"
//----------------------------------------------------------------------------
NGLCoreApplication::NGLCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv)
{
// auf SIGTERM reagieren
signal(SIGTERM, &signalHandler);
#ifdef Q_OS_WIN
installNativeEventFilter(new MyEventFilter);
#endif
}
@@ -0,0 +1,36 @@
/**
* @RDE_HEADER@
* small extension to QCoreApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QCoreApplication>
#include "nglloggerhandler.h"
#ifndef NGLCOREAPPLICATION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLCOREAPPLICATION_EXPORT
# else
# ifdef MAKE_NGLCOREAPPLICATION_LIB
# define NGLCOREAPPLICATION_EXPORT Q_DECL_EXPORT
# else
# define NGLCOREAPPLICATION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
namespace NGL
{
class INGLLogger;
}
class NGLCOREAPPLICATION_EXPORT NGLCoreApplication : public QCoreApplication, public NGL::LoggerHandler
{
Q_OBJECT
public:
NGLCoreApplication(int &argc, char **argv);
};
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* small extension to QCoreApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglguiapplication.h"
#include "ngl_signal_handler.inc"
//----------------------------------------------------------------------------
NGLGuiApplication::NGLGuiApplication(int &argc, char **argv)
: QGuiApplication(argc, argv)
{
// auf SIGTERM reagieren
signal(SIGTERM, &signalHandler);
#ifdef Q_OS_WIN
installNativeEventFilter(new MyEventFilter);
#endif
}
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* small extension to QCoreApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtGui/QGuiApplication>
#include "nglloggerhandler.h"
#ifndef NGLGUIAPPLICATION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLGUIAPPLICATION_EXPORT
# else
# ifdef MAKE_NGLGUIAPPLICATION_LIB
# define NGLGUIAPPLICATION_EXPORT Q_DECL_EXPORT
# else
# define NGLGUIAPPLICATION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
namespace NGL
{
class INGLLogger;
}
class NGLGUIAPPLICATION_EXPORT NGLGuiApplication : public QGuiApplication, public NGL::LoggerHandler
{
Q_OBJECT
public:
NGLGuiApplication(int &argc, char **argv);
};
#define nglGuiApp static_cast<NGLGuiApplication*>(NGLGuiApplication::instance())
@@ -0,0 +1,96 @@
/**
* @RDE_HEADER@
* Logger handling stuff for NGL(Core|Gui)Application
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglloggerhandler.h"
#include "ngl_qt_msg_handler.inc"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <nglsettings/nglsettings_settings.h>
#include <nglcoreapplication.h>
namespace NGL
{
static QByteArray username()
{
#ifdef Q_OS_WIN
return qgetenv("USERNAME");
#else
return qgetenv("USER");
#endif
}
static void setEnvVars()
{
// set LOGPATH to the globally configured path
const QString logPath = NGL::Settings::logPath();
qputenv("LOG4QT_LOGDIR", logPath.toLocal8Bit());
qputenv("LOG4QT_USER", username());
}
//----------------------------------------------------------------------------
void LoggerHandler::createLogger(const QByteArray &baseName, const char *configFileName, bool quiet)
{
setEnvVars();
m_baseLoggerName = baseName;
const QString bnStr(QString::fromLatin1(baseName.toLower()));
const QString logPath = NGL::Settings::logPath();
m_loggerFilenamePostfix = logPath + QLatin1Char('/') + QString::fromLocal8Bit(username()) + QLatin1Char('_') + bnStr;
m_loggerFilenamePrefix = QLatin1String(".log");
const QString logOutputName = m_loggerFilenamePostfix + m_loggerFilenamePrefix;
NGL::NGLLoggerBootstrap::createNGLRootLogger(QString::fromLatin1(configFileName), false, logOutputName, quiet);
// Qt-Messages abfangen
qInstallMessageHandler(&qtMsgHandler);
}
//----------------------------------------------------------------------------
void LoggerHandler::createLogger(const QByteArray &baseName, int exerciseId, int additionalId, bool quiet)
{
setEnvVars();
const QString bnStr(QString::fromLatin1(baseName.toLower()));
const QString configFileName = QLatin1String("log4cxx_") + bnStr + QLatin1String(".props");
const QString logPath = NGL::Settings::logPath();
m_loggerFilenamePostfix = logPath + QLatin1Char('/') + QString::fromLocal8Bit(username()) + QLatin1Char('_') + bnStr;
if (exerciseId > 0)
m_loggerFilenamePostfix += QLatin1Char('_') + QString::number(exerciseId);
if (additionalId > 0)
m_loggerFilenamePostfix += QLatin1Char('_') + QString::number(additionalId);
m_loggerFilenamePrefix = QLatin1String(".log");
m_baseLoggerName = baseName + QByteArray(".main");
const QString logOutputName = m_loggerFilenamePostfix + m_loggerFilenamePrefix;
NGL::NGLLoggerBootstrap::createNGLRootLogger(configFileName, false, logOutputName, quiet);
// Qt-Messages abfangen
qInstallMessageHandler(&qtMsgHandler);
}
//----------------------------------------------------------------------------
NGL::INGLLogger &LoggerHandler::baseLogger() const
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(m_baseLoggerName.data());
}
//----------------------------------------------------------------------------
NGL::INGLLogger &LoggerHandler::logger(const char *loggerName) const
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName);
}
//----------------------------------------------------------------------------
LoggerHandler *LoggerHandler::getLoggerHandler()
{
return dynamic_cast<LoggerHandler*>(QCoreApplication::instance());
}
} // namespace NGL
@@ -0,0 +1,88 @@
/**
* @RDE_HEADER@
* Logger handling stuff for NGL(Core|Gui)Application
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QByteArray>
#include <QString>
#ifndef LOGGERHANDLER_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define LOGGERHANDLER_EXPORT
# else
# if defined(MAKE_NGLCOREAPPLICATION_LIB) || defined(MAKE_NGLGUIAPPLICATION_LIB) || defined(MAKE_NGLAPPLICATION_LIB) || defined(MAKE_NGLSINGLECOREAPPLICATION_LIB) || defined(MAKE_NGLSINGLEAPPLICATION_LIB)
# define LOGGERHANDLER_EXPORT Q_DECL_EXPORT
# else
# define LOGGERHANDLER_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
namespace NGL
{
class INGLLogger;
class LOGGERHANDLER_EXPORT LoggerHandler
{
public:
LoggerHandler() = default;
~LoggerHandler() = default;
/**
* @brief Creates a NGL RootLogger instance, using baseName as the name for the base logger and configFileName for the .props file
* @param baseName the name of the service/application
* @param configFileName The file name with the logging informations
* @param checkTime the time (in seconds) to check for modifications of the file
*/
void createLogger(const QByteArray &baseName,
const char *configFileName,
bool quiet = false);
/**
* @brief Creates a NGL RootLogger instance, using <svcName>.main as the base logger name,
* configFileName is created with 'log4cxx_<svcNameLowerCase>.props'
* @param baseName the name of the service/application
* @param exerciseId the (optional) exercise id, if > 0,
* @param additionalId an (optional) id to be used for logfile name creation,
* the output log name is created with ${USER}_<svcNameLowerCase>_<exerciseId>.log
*/
void createLogger(const QByteArray &baseName,
int exerciseId = 0,
int additionalId = 0,
bool quiet = false);
/**
* @brief get the base Logger created with createLogger()
*/
NGL::INGLLogger &baseLogger() const;
/**
* @brief Get a logger with the given name
* @param The logger to retrieve
*/
NGL::INGLLogger &logger(const char *loggerName) const;
/**
* @brief get the log filename postfix (e.g. /shd/CTC/log/ctc_foo)
*/
QString loggerNamePostfix() const { return m_loggerFilenamePostfix; }
/**
* @brief get the log filename prefix (e.g. .log)
*/
QString loggerNamePrefix() const { return m_loggerFilenamePrefix; }
/**
* @brief Retrieves the loggerhandler from ngl(core)application or nullptr
*/
static LoggerHandler *getLoggerHandler();
private:
QByteArray m_baseLoggerName;
QString m_loggerFilenamePostfix;
QString m_loggerFilenamePrefix;
};
} // namespace NGL
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* small extension to QtSingleApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglsingleapplication.h"
#include "ngl_signal_handler.inc"
//----------------------------------------------------------------------------
NGLSingleApplication::NGLSingleApplication(int &argc, char **argv)
: QtSingleApplication(argc, argv)
{
// auf SIGTERM reagieren
signal(SIGTERM, &signalHandler);
#ifdef Q_OS_WIN
installNativeEventFilter(new MyEventFilter);
#endif
}
//----------------------------------------------------------------------------
bool NGLSingleApplication::notify(QObject *o, QEvent *e)
{
bool bRet = false;
try
{
bRet = QtSingleApplication::notify(o, e);
}
catch (const std::exception &e)
{
fprintf(stderr, "exception %s\n", e.what());
}
return bRet;
}
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* small extension to QtSingleApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtSingleApplication/QtSingleApplication>
#include "nglloggerhandler.h"
#ifndef NGLSINGLEAPPLICATION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLSINGLEAPPLICATION_EXPORT
# else
# ifdef MAKE_NGLSINGLEAPPLICATION_LIB
# define NGLSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT
# else
# define NGLSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
namespace NGL
{
class INGLLogger;
}
class NGLSINGLEAPPLICATION_EXPORT NGLSingleApplication : public QtSingleApplication, public NGL::LoggerHandler
{
Q_OBJECT
public:
NGLSingleApplication(int &argc, char **argv);
protected:
bool notify(QObject *o, QEvent *e) override;
};
#define nglApp static_cast<NGLSingleApplication*>(NGLSingleApplication::instance())
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* small extension to QCoreApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglsinglecoreapplication.h"
#include "ngl_signal_handler.inc"
//----------------------------------------------------------------------------
NGLSingleCoreApplication::NGLSingleCoreApplication(int &argc, char **argv)
: QtSingleCoreApplication(argc, argv)
{
// auf SIGTERM reagieren
signal(SIGTERM, &signalHandler);
#ifdef Q_OS_WIN
installNativeEventFilter(new MyEventFilter);
#endif
}
@@ -0,0 +1,36 @@
/**
* @RDE_HEADER@
* small extension to QCoreApplication with NGL specific stuff
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtSingleApplication/QtSingleCoreApplication>
#include "nglloggerhandler.h"
#ifndef NGLSINGLECOREAPPLICATION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLSINGLECOREAPPLICATION_EXPORT
# else
# ifdef MAKE_NGLSINGLECOREAPPLICATION_LIB
# define NGLSINGLECOREAPPLICATION_EXPORT Q_DECL_EXPORT
# else
# define NGLSINGLECOREAPPLICATION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
namespace NGL
{
class INGLLogger;
}
class NGLSINGLECOREAPPLICATION_EXPORT NGLSingleCoreApplication : public QtSingleCoreApplication, public NGL::LoggerHandler
{
Q_OBJECT
public:
NGLSingleCoreApplication(int &argc, char **argv);
};
@@ -0,0 +1,47 @@
#
# CMake Script
# $Id$
# $HeadURL$
# $Author$
#
FIND_PACKAGE(BZip2 REQUIRED)
SET(nglcomp_SRCS
nglcomp_bzip2iodevice.cpp
nglcomp_bzip2iodevice.h
nglcomp_compress.cpp
nglcomp_compress.h
nglcomp_export.h
nglcomp_tarfilter.cpp
nglcomp_tarfilter.h
)
NGL_ADD_LIBRARY(WS nglcompression SHARED ${nglcomp_SRCS})
NGL_TARGET_LINK_LIBRARIES(nglcompression
PUBLIC
Qt5::Core
PRIVATE
Qt5::Concurrent
NGLLogger
${BZIP2_LIBRARIES}
# BZip2::BZip2 # not available with cmake 3.5
)
NGL_TARGET_INCLUDE_DIRECTORIES(nglcompression
PRIVATE
${BZIP2_INCLUDE_DIR}
)
NGL_INSTALL_TARGET(nglcompression)
IF(BUILD_WS AND BUILD_TESTING)
REMOVE_DEFINITIONS(-DQT_GUI_LIB)
ADD_EXECUTABLE(nglcomp_test nglcomp_test.cpp nglcomp_test.h)
TARGET_LINK_LIBRARIES(nglcomp_test
NGLLogger
nglcoreapplication
ngltools
nglcompression
Qt5::Test
)
ADD_TEST(NAME nglcomp_test COMMAND $<TARGET_FILE:nglcomp_test>)
ENDIF()
@@ -0,0 +1,385 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
/****************************************************************************
**
** Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>.
** All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Library General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Library General Public License for more details.
**
** You should have received a copy of the GNU Library General Public License
** along with this library; see the file COPYING.LIB. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "nglcomp_bzip2iodevice.h"
#include <QIODevice>
#include <QString>
#include <bzlib.h>
//
// BZip2IODevice::Private
//
class BZip2IODevice::Private
{
public:
Private(BZip2IODevice *parent_, QIODevice *dev, int bs)
: parent(parent_)
, device(dev)
, iCurPos(0)
, iMaxBufSize(1024 * 1024)
, blocksize(bs)
, initialized(false)
, decomressStreamEnd(false)
{
buffer.resize(iMaxBufSize);
}
bool initializeCompress();
qint64 doCompress(const char *in, qint64 iMaxLen);
bool finishCompress();
bool initializeDecompress();
qint64 doDecompress(char *out, qint64 iMaxLen);
bool finishDecompress();
static QString bzipError2String(int errCode);
QAtomicInt aborted { 0 };
BZip2IODevice *parent;
QIODevice *device;
unsigned int iCurPos;
unsigned int iMaxBufSize;
unsigned int blocksize;
bool initialized;
bool decomressStreamEnd;
QByteArray buffer;
bz_stream stream;
};
bool BZip2IODevice::Private::initializeCompress()
{
if (initialized)
return true;
memset(&stream, 0, sizeof(stream));
int blockSize = (blocksize > 0 && blocksize < 10) ? blocksize : 10;
int ret = BZ2_bzCompressInit(&stream, blockSize, 0, 0);
if (ret != BZ_OK)
{
parent->setErrorString(QStringLiteral("Error initializing bzip2 %1").arg(bzipError2String(ret)));
initialized = false;
}
else
initialized = true;
return initialized;
}
qint64 BZip2IODevice::Private::doCompress(const char *in, qint64 iMaxLen)
{
if (!initialized)
{
if (parent->errorString().isEmpty())
parent->setErrorString(QLatin1String("Internal Error - bzip not initialized"));
finishCompress();
return -1;
}
if (iMaxLen > 2 * 1024 * 1024 * 1024LL)
{
finishCompress();
parent->setErrorString(QLatin1String("Currently can't handle more than 2GB!"));
return -1;
}
stream.next_in = const_cast<char *>(in);
stream.avail_in = iMaxLen;
do
{
if (aborted) return 0;
stream.next_out = buffer.data();
stream.avail_out = buffer.size();
const int ret = BZ2_bzCompress(&stream, BZ_RUN);
if (ret != BZ_RUN_OK)
{
finishCompress();
parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret)));
return -1;
}
int iBytesToWrite = buffer.size() - stream.avail_out;
if (iBytesToWrite)
{
if (device->write(buffer.constData(), iBytesToWrite) != iBytesToWrite)
{
finishCompress();
parent->setErrorString(QLatin1String("Error writing to QIODevice"));
return -1;
}
}
}
while (stream.avail_in != 0);
return stream.next_in - in;
}
bool BZip2IODevice::Private::finishCompress()
{
if (!initialized || aborted)
return true;
int ret = -1;
do
{
stream.next_out = buffer.data();
stream.avail_out = buffer.size();
ret = BZ2_bzCompress(&stream, BZ_FINISH);
if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
{
finishCompress();
parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret)));
return false;
}
int iBytesToWrite = buffer.size() - stream.avail_out;
if (device->write(buffer.constData(), iBytesToWrite) != iBytesToWrite)
{
finishCompress();
parent->setErrorString(QLatin1String("Error writing to QIODevice"));
return false;
}
}
while (ret != BZ_STREAM_END);
BZ2_bzCompressEnd(&stream);
initialized = false;
return true;
}
bool BZip2IODevice::Private::initializeDecompress()
{
if (initialized)
return true;
memset(&stream, 0, sizeof(stream));
int ret = BZ2_bzDecompressInit(&stream, 0, 0);
if (ret != BZ_OK)
{
parent->setErrorString(QStringLiteral("Error initializing bzip2: %1").arg(bzipError2String(ret)));
initialized = false;
}
else
initialized = true;
decomressStreamEnd = false;
return initialized;
}
qint64 BZip2IODevice::Private::doDecompress(char *out, qint64 iMaxLen)
{
int ret = -1;
if (!initialized)
{
if (parent->errorString().isEmpty())
parent->setErrorString(QLatin1String("Internal Error - bzip not initialized"));
finishDecompress();
return -1;
}
if (decomressStreamEnd)
return 0;
if (iMaxLen > 2 * 1024 * 1024 * 1024LL)
{
finishCompress();
parent->setErrorString(QLatin1String("Currently can't handle more than 2GB!"));
return -1;
}
stream.next_out = out;
stream.avail_out = iMaxLen;
do
{
if (ret != BZ_STREAM_END && stream.avail_in == 0)
{
qint64 iReadCnt = device->read(buffer.data(), buffer.size());
if (iReadCnt <= 0)
return -1;
stream.next_in = buffer.data();
stream.avail_in = iReadCnt;
}
ret = BZ2_bzDecompress(&stream);
if (ret != BZ_OK && ret != BZ_STREAM_END)
{
parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret)));
finishDecompress();
return -1;
}
}
while (stream.avail_out != 0 && ret != BZ_STREAM_END);
decomressStreamEnd = (ret == BZ_STREAM_END);
return stream.next_out - out;
}
bool BZip2IODevice::Private::finishDecompress()
{
if (!initialized)
return true;
BZ2_bzDecompressEnd(&stream);
initialized = false;
return true;
}
QString BZip2IODevice::Private::bzipError2String(int errCode)
{
switch (errCode)
{
case BZ_SEQUENCE_ERROR:
return QLatin1String("Sequence error");
case BZ_PARAM_ERROR:
return QLatin1String("Parameter not correct");
case BZ_MEM_ERROR:
return QLatin1String("Memory allocation error");
case BZ_DATA_ERROR:
return QLatin1String("Invalid input data");
case BZ_DATA_ERROR_MAGIC:
return QLatin1String("Not a bzip2 file");
case BZ_IO_ERROR:
return QLatin1String("I/O error");
case BZ_UNEXPECTED_EOF:
return QLatin1String("Unexpected end of file");
case BZ_OUTBUFF_FULL:
return QLatin1String("Output buffer full");
case BZ_CONFIG_ERROR:
return QLatin1String("Wrong config parameter");
};
return QString::number(errCode);
}
//
// BZip2IODevice
//
BZip2IODevice::BZip2IODevice(QIODevice *dev, int blocksize)
: d(new Private(this, dev, blocksize))
{}
BZip2IODevice::~BZip2IODevice()
{
close();
delete d;
}
void BZip2IODevice::setBufferSize(unsigned int size)
{
d->iMaxBufSize = size > 1024 ? size : 1024;
d->buffer.resize(d->iMaxBufSize);
}
void BZip2IODevice::setBlockSize(unsigned int size)
{
if (isOpen())
return;
d->blocksize = size;
}
bool BZip2IODevice::isSequential() const
{
return true;
}
bool BZip2IODevice::open(OpenMode mode)
{
if ((mode & QIODevice::ReadWrite) == 0)
{
setErrorString(QStringLiteral("Unsupported OpenMode %1").arg(mode));
return false;
}
if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite)
{
setErrorString(QLatin1String("Can't read and write simultaniously"));
return false;
}
if ((mode & QIODevice::ReadOnly) == QIODevice::ReadOnly)
{
if (!d->device)
{
setErrorString(QLatin1String("No QIODevice for reading available"));
return false;
}
if ((d->device->openMode() & QIODevice::ReadOnly) == 0)
{
setErrorString(QLatin1String("QIODevice not opened for reading"));
return false;
}
if (!d->initializeDecompress())
return false;
}
else
{
if (!d->device)
{
setErrorString(QLatin1String("No QIODevice for writing available"));
return false;
}
if ((d->device->openMode() & QIODevice::WriteOnly) == 0)
{
setErrorString(QLatin1String("QIODevice not opened for writing"));
return false;
}
if (!d->initializeCompress())
return false;
}
setErrorString(QString());
setOpenMode(mode);
return QIODevice::open(mode);
}
void BZip2IODevice::abort()
{
d->aborted = 1;
}
void BZip2IODevice::close()
{
if (!isOpen())
return;
if ((openMode() & QIODevice::ReadOnly) == QIODevice::ReadOnly)
d->finishDecompress();
else
d->finishCompress();
QIODevice::close();
}
bool BZip2IODevice::atEnd() const
{
if (!d->device)
return true;
return d->device->atEnd() && d->decomressStreamEnd && QIODevice::atEnd();
}
qint64 BZip2IODevice::readData(char *data, qint64 maxSize)
{
return d->doDecompress(data, maxSize);
}
qint64 BZip2IODevice::writeData(const char *data, qint64 maxSize)
{
return d->doCompress(data, maxSize);
}
@@ -0,0 +1,69 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
/****************************************************************************
**
** Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>.
** All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Library General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Library General Public License for more details.
**
** You should have received a copy of the GNU Library General Public License
** along with this library; see the file COPYING.LIB. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef BZIP2IODEVICE_H
#define BZIP2IODEVICE_H
#include <QString>
#include <QIODevice>
/* This small class provides a QIODevice interface to (de-)compress
data with the bzip2 algorithm
You need to link against bzip lib!
*/
class BZip2IODevice : public QIODevice
{
public:
// @dev - the device to write data to or read data from
// @blocksize - the blocksize (*100000) to use for compression,
// between 1 (fast) and 9 (best compression)
BZip2IODevice(QIODevice *dev, int blocksize = 5);
virtual ~BZip2IODevice();
void abort();
void setBufferSize(unsigned int size); // default: 1MB
void setBlockSize(unsigned int size); // default: 5
// QIODevice functions
virtual bool isSequential() const;
virtual bool open(OpenMode mode);
virtual void close();
virtual bool atEnd() const;
protected:
virtual qint64 readData(char *data, qint64 maxSize);
virtual qint64 writeData(const char *data, qint64 maxSize);
private:
class Private;
friend class Private;
Private *const d;
};
#endif // BZIP2IODEVICE_H
@@ -0,0 +1,570 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglcomp_compress.h"
#include "nglcomp_bzip2iodevice.h"
#include "nglcomp_tarfilter.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QBuffer>
#include <QtConcurrent>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QFutureWatcher>
#include <QIODevice>
#include <QStringList>
#include <memory>
#include <QDebug>
namespace NGL
{
Compress::Compress(QObject *parent)
: QObject(parent)
, m_u2_memFiles()
, m_aborted(0)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("nglcompress"))
{
DEBUG_LOG(m_logger) << "c_tor";
QTimer *t = new QTimer(this);
t->setInterval(1000);
connect(t, &QTimer::timeout, this, [](){qWarning() << "still alive ...";});
t->start();
}
Compress::~Compress()
{
qWarning() << "## COMPRESS DTOR!!!!";
// from QFuture manpage: "Note that this neither waits nor cancels the asynchronous computation."
DEBUG_LOG(m_logger) << "~";
abort();
m_future.waitForFinished();
DEBUG_LOG(m_logger) << "~ finished";
}
void Compress::abort()
{
DEBUG_LOG(m_logger) << "ABORT";
m_aborted = 1;
m_lastError = tr("Aborted");
if (m_currentTarFilter != nullptr) // not thread-safe - gl !
{
DEBUG_LOG(m_logger) << "aborting tar";
m_currentTarFilter->abort();
}
if (m_currentBzipDevice != nullptr) // not thread-safe - gl !
{
DEBUG_LOG(m_logger) << "aborting bzip";
m_currentBzipDevice->abort();
}
}
void Compress::compress(QIODevice *out,
const QString &filesRootDir,
const QVector<FileInformations> &files,
const QVector<FileInformations> &memFiles,
const QString &destRootDir)
{
DEBUG_LOG(m_logger) << "compress #2";
reset();
setupFutureWatcher(QtConcurrent::run(this, &Compress::_compress, out, filesRootDir, files, memFiles, destRootDir));
}
void Compress::compress(QIODevice *out, const QString &sourceDir, const QString &destRootDir)
{
DEBUG_LOG(m_logger) << "compress #1 source dir: " << sourceDir << ", destRootDir: " << destRootDir;
reset();
QVector<Compress::FileInformations> inFiles = directoryFileList(sourceDir, true);
// Alles relativ zu dem angegebenen Directory
int len = sourceDir.length();
if (!sourceDir.endsWith(QLatin1Char('/')))
len += 1;
for (auto &fi : inFiles)
{
fi.inputFileName = fi.inputFileName.mid(len);
fi.bAbsInputPath = false;
DEBUG_LOG(m_logger) << "fi: ifm = " << fi.inputFileName << ", abs = " << fi.bAbsInputPath;
}
DEBUG_LOG(m_logger) << "FI list size: " << inFiles.count();
compress(out, sourceDir, inFiles, {}, destRootDir);
}
bool Compress::_compress(QIODevice *output,
const QString &filesRootDir,
const QVector<FileInformations> &files,
const QVector<FileInformations> &memFiles,
const QString &_destRootDir)
{
std::shared_ptr<int> invalidatePointersOnScopeLeave(nullptr, [this](int *)
{
DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #1";
m_currentTarFilter = nullptr;
m_currentBzipDevice = nullptr;
});
(void)invalidatePointersOnScopeLeave;
if (!output || !output->isWritable())
{
m_lastError = tr("Device is not writeable");
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;;
//emit error(m_lastError);
return false;
}
const QString destRootDir = _destRootDir.endsWith(QLatin1Char('/')) ?
_destRootDir : _destRootDir + QLatin1Char('/');
const qint64 maxCount = files.count() + memFiles.count();
qint64 count = 0;
DEBUG_LOG(m_logger) << "destRootDir = " << destRootDir << ", maxCount = " << maxCount << ", count = " << count;
BZip2IODevice bzip2(output, 9);
m_currentBzipDevice = &bzip2;
if (!bzip2.open(QIODevice::WriteOnly))
{
m_lastError = bzip2.errorString();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
// get size of all files
qint64 bytesTotal = 0;
for (const FileInformations &file : qAsConst(files))
{
if (m_aborted) return false;
const QString in = file.bAbsInputPath ? file.inputFileName : filesRootDir + QLatin1Char('/') + file.inputFileName;
const QFileInfo fi(in);
bytesTotal += fi.size();
}
qint64 currentFileSize = 0;
QString currentFileName;
auto readCallback = [this, &maxCount, &count, &currentFileSize, &currentFileName, &bytesTotal](const qint64 iSize)
{
DEBUG_LOG(m_logger) << "readCallback: maxCount = " << maxCount << ", count = " << count
<< ", currentFileSize = " << currentFileSize << ", currentFileName = " << currentFileName << ", iSize = " << iSize;
emit compressInfoEx(maxCount, count, currentFileSize, (currentFileSize - iSize), currentFileName, bytesTotal);
};
TarFilter tf(&bzip2, nullptr, readCallback);
m_currentTarFilter = &tf;
const QVector<QStringRef> paths = destRootDir.splitRef(QLatin1Char('/'), QString::SkipEmptyParts);
QString curPath;
// add empty directories to archive
DEBUG_LOG(m_logger) << "prepairing tar filter";
for (const QStringRef &path : paths)
{
DEBUG_LOG(m_logger) << "path = " << path.toString();
if (m_aborted) return false;
if (curPath.isEmpty())
curPath = path + QLatin1Char('/');
else
curPath += path + QLatin1Char('/');
DEBUG_LOG(m_logger) << "curPath = " << curPath << ", filesRootDir.isEmpty() = " << filesRootDir.isEmpty();
if (filesRootDir.isEmpty())
{
if (!tf.addData(curPath, QByteArray(), true))
{
m_lastError = tf.lastError();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
}
else
{
if (!tf.addFile(filesRootDir, curPath))
{
m_lastError = tf.lastError();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
}
}
m_c_sizeInfo.realSize = 0;
for (const FileInformations &file : qAsConst(files))
{
DEBUG_LOG(m_logger) << "file = " << file.inputFileName;
emit compressInfo(maxCount, ++count, file.inputFileName);
//count++;
if (m_aborted) return false;
QString in = file.bAbsInputPath ? file.inputFileName : filesRootDir + QLatin1Char('/') + file.inputFileName;
QString out = destRootDir + (file.outputFileName.isEmpty() ? file.inputFileName : file.outputFileName);
DEBUG_LOG(m_logger) << "in = " << in << ", out = " << out;
QFileInfo fi(in);
currentFileName = fi.fileName();
currentFileSize = fi.size();
m_c_sizeInfo.realSize += currentFileSize;
DEBUG_LOG(m_logger) << "currentFileName = " << currentFileName << ", currentFileSize = " << currentFileSize << "m_c_sizeInfo.realSize" << m_c_sizeInfo.realSize;
if (!tf.addFile(in, out))
{
m_lastError = tf.lastError();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
}
for (const FileInformations &file : qAsConst(memFiles))
{
DEBUG_LOG(m_logger) << "(mem) file = " << file.inputFileName;
emit compressInfo(maxCount, ++count, file.inputFileName);
//count++;
if (m_aborted) return false;
currentFileName = file.inputFileName;
currentFileSize = file.fileData.size();
m_c_sizeInfo.compressedSize += currentFileSize;
DEBUG_LOG(m_logger) << "(mem) currentFileName = " << currentFileName << ", currentFileSize = " << currentFileSize << "m_c_sizeInfo.realSize" << m_c_sizeInfo.realSize;
if (!tf.addData(file.inputFileName, file.fileData))
{
m_lastError = tf.lastError();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
}
DEBUG_LOG(m_logger) << "writing eos";
tf.writeEOS();
DEBUG_LOG(m_logger) << "closing bzip";
bzip2.close();
m_c_sizeInfo.compressedSize = output->size();
DEBUG_LOG(m_logger) << "m_c_sizeInfo.compressedSize = " << m_c_sizeInfo.compressedSize;
m_success = true;
DEBUG_LOG(m_logger) << "DONE!";
return true;
}
void Compress::uncompress(QIODevice *in, const QString &outDir)
{
DEBUG_LOG(m_logger) << "uncompress #1";
reset();
setupFutureWatcher(QtConcurrent::run(this, &Compress::_uncompressDirectory, in, outDir));
}
bool Compress::_uncompressDirectory(QIODevice *input, const QString &outDir)
{
DEBUG_LOG(m_logger) << "_uncompressDirectory";
std::shared_ptr<int> invalidatePointersOnScopeLeave(nullptr, [this](int *)
{
DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #2";
m_currentTarFilter = nullptr;
m_currentBzipDevice = nullptr;
});
(void)invalidatePointersOnScopeLeave;
if (!input || !input->isReadable())
{
m_lastError = tr("Device is not readable");
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
BZip2IODevice bzip2(input, 9);
m_currentBzipDevice = &bzip2;
if (!bzip2.open(QIODevice::ReadOnly))
{
m_lastError = bzip2.errorString();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
TarFilter tf(&bzip2);
m_currentTarFilter = &tf;
TarFilter::FileInformations tfi;
QDir dir(outDir);
DEBUG_LOG(m_logger) << "dir = " << dir.path();
while (tf.getData(tfi))
{
DEBUG_LOG(m_logger) << "tfi.fileName = " << tfi.fileName;
emit uncompressInfo(input->size(), input->pos(), tfi.fileName);
if (m_aborted) return false;
QString path = outDir + QLatin1Char('/') + tfi.fileName;
DEBUG_LOG(m_logger) << "path = " << path;
if (tfi.fileType == TarFilter::directory)
{
DEBUG_LOG(m_logger) << "tfi.fileType == TarFilter::directory";
if (!dir.exists(path) && !dir.mkpath(path))
{
m_lastError = tr("Error creating directory %1").arg(outDir);
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
}
else
{
// make sure the directory exists
QString pathName = QFileInfo(path).absolutePath();
if (!dir.exists(pathName) && !dir.mkpath(pathName))
{
m_lastError = tr("Error creating directory %1").arg(pathName);
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
QFile f(path);
if (!f.open(QIODevice::WriteOnly))
{
m_lastError = tr("Error opening %1 for writing (%2)").arg(path, f.errorString());
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
if (!tf.getData(&f))
{
m_lastError = tf.lastError();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
}
}
DEBUG_LOG(m_logger) << "uncompress done!";
m_success = true;
return true;
}
void Compress::uncompress(QIODevice *in)
{
DEBUG_LOG(m_logger) << "uncompress #2!";
reset();
setupFutureWatcher(QtConcurrent::run(this, &Compress::_uncompressBuffer, in));
}
bool Compress::_uncompressBuffer(QIODevice *input)
{
DEBUG_LOG(m_logger) << "uncompressBuffer";
std::shared_ptr<int> invalidatePointersOnScopeLeave(nullptr, [this](int *)
{
DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #2";
m_currentTarFilter = nullptr;
m_currentBzipDevice = nullptr;
});
(void)invalidatePointersOnScopeLeave;
if (!input->isReadable())
{
m_lastError = tr("Device is not readable");
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
BZip2IODevice bzip2(input, 9);
m_currentBzipDevice = &bzip2;
if (!bzip2.open(QIODevice::ReadOnly))
{
m_lastError = bzip2.errorString();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
TarFilter tf(&bzip2);
m_currentTarFilter = &tf;
TarFilter::FileInformations tfi;
while (tf.getData(tfi))
{
DEBUG_LOG(m_logger) << "tfi.fileName = " << tfi.fileName;
emit uncompressInfo(input->size(), input->pos(), tfi.fileName);
if (m_aborted) return false;
FileInformations fi;
fi.outputFileName = tfi.fileName;
DEBUG_LOG(m_logger) << "fi.outputFileName = " << fi.outputFileName;
if (tfi.fileType == TarFilter::directory)
{
fi.outputFileName += QLatin1Char('/');
DEBUG_LOG(m_logger) << "> fi.outputFileName = " << fi.outputFileName;
}
else
{
DEBUG_LOG(m_logger) << "stuff";
QBuffer buf(&fi.fileData);
if (!buf.open(QIODevice::WriteOnly))
{
m_lastError = tr("Error opening buffer for writing (%1)").arg(buf.errorString());
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
if (!tf.getData(&buf))
{
m_lastError = tf.lastError();
ERROR_LOG(m_logger) << "compress failed: " << m_lastError;
//emit error(m_lastError);
return false;
}
}
fi.bAbsInputPath = fi.outputFileName.startsWith(QLatin1Char('/'));
DEBUG_LOG(m_logger) << "added fi.bAbsInputPath = " << fi.bAbsInputPath;
m_u2_memFiles += fi;
}
return true;
}
bool Compress::success() const
{
/*DEBUG_LOG*/
ERROR_LOG(m_logger) << "success? " << (m_future.isFinished() && !m_future.isCanceled() && m_success);
ERROR_LOG(m_logger) << "success details: "
<< "success m_future.isFinished() = " << (m_future.isFinished())
<< " !m_future.isCanceled() = " << !m_future.isCanceled()
<< " m_success = " << m_success;
return (m_future.isFinished() && !m_future.isCanceled() && m_success);
}
bool Compress::waitForFinished()
{
DEBUG_LOG(m_logger) << "waitForFinished...";
m_future.waitForFinished();
DEBUG_LOG(m_logger) << "waitForFinished... done!";
return success();
}
QVector<Compress::FileInformations> Compress::directoryFileList(const QString &dir, bool recursive)
{
DEBUG_LOG(m_logger) << "directoryFileList";
QVector<FileInformations> sl_absolute;
QDir d(dir);
if (d.exists())
{
DEBUG_LOG(m_logger) << "exists";
const auto entries = d.entryList(QDir::Files);
sl_absolute.reserve(sl_absolute.size() + entries.size());
for (const QString &entry : entries)
sl_absolute << FileInformations(QFileInfo(d, entry).absoluteFilePath(), true);
}
if (recursive)
{
DEBUG_LOG(m_logger) << "recursive";
const auto entries = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
sl_absolute.reserve(sl_absolute.size() + entries.size());
for (const QString &s : entries)
sl_absolute << directoryFileList(dir + QLatin1Char('/') + s, true);
}
DEBUG_LOG(m_logger) << "done";
return sl_absolute;
}
void Compress::reset()
{
DEBUG_LOG(m_logger) << "reset";
m_u2_memFiles.clear();
m_lastError.clear();
m_c_sizeInfo.realSize = 0;
m_c_sizeInfo.compressedSize = 0;
m_success = false;
}
void Compress::setupFutureWatcher(const QFuture<bool> &future)
{
DEBUG_LOG(m_logger) << "setupFutureWatcher";
m_future = future;
QFutureWatcher<bool> *fw = new QFutureWatcher<bool>(this);
QObject::connect(fw, &QObject::destroyed, this, [this]() { DEBUG_LOG(m_logger) << "Future Watcher destroyed"; });
QObject::connect(fw, &QFutureWatcher<bool>::finished, this, &Compress::finished);
QObject::connect(fw, &QFutureWatcher<bool>::finished, fw, &QObject::deleteLater);
QObject::connect(fw, &QFutureWatcher<bool>::finished, fw, [this]() { DEBUG_LOG(m_logger) << "Future Watcher about to be deleted"; });
fw->setFuture(m_future);
}
} // namespace NGL
@@ -0,0 +1,182 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "nglcomp_export.h"
#include <NGLLogger/INGLLogger.h>
#include <QByteArray>
#include <QFuture>
#include <QObject>
#include <QString>
#include <QVector>
class QIODevice;
class TarFilter;
class BZip2IODevice;
namespace NGL
{
class NGLCOMPRESSION_EXPORT Compress : public QObject
{
Q_OBJECT
public:
struct FileInformations
{
QString inputFileName; ///<! the input filename (when it's a real file)
QString outputFileName; ///<! the output filename (can be empty when inputFileName is set)
QByteArray fileData; ///<! the input file data (when it's an in-memory file)
bool bAbsInputPath = true; ///<! true when inputFileName should be treated as absolute path
FileInformations() = default;
FileInformations(const QString &name, bool isAbsolute)
: inputFileName(name)
, bAbsInputPath(isAbsolute)
{}
};
struct FileSizeInfo
{
qint64 realSize = 0; ///<! the real size of the compressed data
qint64 compressedSize = 0; ///<! the compressed file size
};
/**
* Ctor
* @param parent the parent of this thread
*/
explicit Compress(QObject *parent = nullptr);
~Compress();
/**
* Retrieve all uncompressed files which were uncompressed into memory. This
* function only return files uncompressed with uncompress(QIODevice *in)
* @return all in-memory uncompressed files
*/
QVector<FileInformations> getMemFiles() const { return m_u2_memFiles; }
/**
* Get informations about the compressed and uncompressed complete file size
* @return FileSizeInfo after a compress/uncompress
*/
FileSizeInfo getFileSizeInfo() const { return m_c_sizeInfo; }
/**
* Returns the state of the last action
* @return True when the last action was successful
*/
bool success() const;
/**
* Compress the given data. You have to call start() afterwards to start the real compression
* @param out The QIODevice to write the compressed data to. It must be writeable
* @param sourceRootDir the source directory with the files to compress (when bAbsInputPath is set to false)
* @param realFiles all files on a filesystem which should be compressed
* @param memFiles all files in memory which should be compressed
* @param destRootDir the destination root dir which should be prepended to all files in the archive
*/
void compress(QIODevice *out,
const QString &sourceRootDir,
const QVector<FileInformations> &files,
const QVector<FileInformations> &memFiles,
const QString &destRootDir);
/**
* Compress the given data. You have to call start() afterwards to start the real compression
* @param out The QIODevice to write the compressed data to. It must be writeable
* @param sourceDir the directory that shall be compressed, all paths are relative to this directory plus destRootDir
* @param destRootDir the destination root dir which should be prepended to all files in the archive
*/
void compress(QIODevice *out,
const QString &sourceDir,
const QString &destRootDir);
/**
* Uncompress data from QIODevice into directory outDir
* @param in The QIODevice to read the compressed data from. It must be readable
* @param outDir The directory to write all uncomressed files to. This directory must exist
*/
void uncompress(QIODevice *in,
const QString &outDir);
/**
* Uncompress data from QIODevice into memory. Retrieve
* data with getMemFiles()
* @param in The QIODevice to read the compressed data from. It must be readable
*/
void uncompress(QIODevice *in);
/**
* Returns the last error occoured. The value is not reset until start() is called again
* @return the last error
*/
QString lastError() const { return m_lastError; }
/**
* Blocking execution, returns success()
*/
bool waitForFinished();
public Q_SLOTS:
void abort();
Q_SIGNALS:
/**
* This signal is emitted every time a new file is uncompressed
* @param totalSize complete filesize
* @param curPos current read position
* @param curName current filename
*/
void uncompressInfo(qint64 totalSize, qint64 curPos, const QString &curName);
/**
* This signal is emitted every time a new file get compressed
* @param totalFiles complete number of files to compress
* @param curFile current file index
* @param curName current filename
*/
void compressInfo(qint64 totalFiles, qint64 curFile, const QString &curName);
void compressInfoEx(qint64 totalFiles, qint64 curFile, qint64 totalSize, qint64 curPos, const QString &curName, const qint64 bytesTotal);
/**
* This signal is emitted when an error occoured
* @param errorString the error string
*/
void error(const QString &errorString);
/**
* This signal is emitted when the async (un)compression finished
*/
void finished();
private:
bool _compress(QIODevice *output,
const QString &filesRootDir,
const QVector<FileInformations> &files,
const QVector<FileInformations> &memFiles,
const QString &_destRootDir);
bool _uncompressDirectory(QIODevice *input, const QString &outDir);
bool _uncompressBuffer(QIODevice *input);
void reset();
void setupFutureWatcher(const QFuture<bool> &future);
QVector<FileInformations> directoryFileList(const QString &dir, bool recursive = false);
FileSizeInfo m_c_sizeInfo;
QVector<FileInformations> m_u2_memFiles;
QString m_lastError;
QAtomicInt m_aborted;
TarFilter *m_currentTarFilter { nullptr };
BZip2IODevice *m_currentBzipDevice { nullptr };
QFuture<bool> m_future;
bool m_success { false };
NGL::INGLLogger &m_logger;
};
}
Q_DECLARE_TYPEINFO(NGL::Compress::FileInformations, Q_MOVABLE_TYPE);
@@ -0,0 +1,21 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef NGLCOMPRESSION_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLCOMPRESSION_EXPORT
# else
# if defined(MAKE_NGLCOMPRESSION_LIB)
# define NGLCOMPRESSION_EXPORT Q_DECL_EXPORT
# else
# define NGLCOMPRESSION_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
@@ -0,0 +1,552 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
/****************************************************************************
**
** Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>.
** All rights reserved.
**
** This file is part of the KDE installer for windows
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Library General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Library General Public License for more details.
**
** You should have received a copy of the GNU Library General Public License
** along with this library; see the file COPYING.LIB. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include <QBuffer>
#include <QFile>
#include <QIODevice>
#include <QFileInfo>
#include <QDateTime>
#include <QTextCodec>
#include <time.h>
#include "nglcomp_tarfilter.h"
#ifndef Q_OS_WIN
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#endif
// TODO: proper cleanup states on error
// add full support than the default one used by tar
// add support for special devices & links
//
// TarFilter::Private
//
class TarFilter::Private
{
public:
Private(QIODevice *dev, QTextCodec *c)
: device(dev)
, codec(c ? c : QTextCodec::codecForLocale())
, iBufSize(1024 * 1024)
, nextChunkSize(-1)
{}
struct tar_posix_header
{
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag;
char linkname[100];
char magic[6];
char version[2];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
char unused[12]; // to align to 512bytes
};
bool fi2tph(const FileInformations &infos); // converts FileInformations to tar_posix_header and adds them to QIODevice
bool addHeader(const FileInformations &infos); // adds a complete header for FileInformations
bool tph2fi(FileInformations &infos); // reads a tar_posix_header and convert it to FileInformations
bool getHeader(FileInformations &infos); // reads a header and converts them to FileInformations
bool checkDevice(QIODevice *in, QIODevice *out);
bool copyData(QIODevice *in, QIODevice *out, qint64 iSize);
QIODevice *device;
QTextCodec *codec;
QString lastError;
unsigned int iBufSize;
qint64 nextChunkSize;
QAtomicInt aborted { 0 };
std::function<void(qint64)> readCallback;
};
bool TarFilter::Private::fi2tph(const FileInformations &infos)
{
QByteArray fn = codec->fromUnicode(infos.fileName);
#ifdef Q_OS_WIN
if (fn.size() > 3 && fn[1] == ':' && (fn[2] == '\\' || fn[2] == '/'))
fn = fn.mid(3);
#endif
if (fn.startsWith('/'))
fn = fn.mid(1);
long unsigned int fileSize = infos.fileType == directory ? 0 : infos.fileSize;
long unsigned int mtime = infos.mtime != -1 ? infos.mtime : time(nullptr);
tar_posix_header hdr;
memset(&hdr, 0, sizeof(hdr));
QByteArray fn_part1 = fn.left(sizeof(hdr.name));
memcpy(hdr.name, fn_part1.constData(), fn_part1.size());
sprintf(hdr.mode, "%07x", 0x0fff & infos.mode);
sprintf(hdr.uid, "%07o", infos.uid);
sprintf(hdr.gid, "%07o", infos.gid);
sprintf(hdr.size, "%011lo", fileSize);
sprintf(hdr.mtime, "%011lo", mtime);
memset(hdr.chksum, ' ', sizeof(hdr.chksum)); // 8 * ' '
hdr.typeflag = infos.fileType;
//memset(hdr.linkname, 0, sizeof(hdr.linkname));
memcpy(hdr.magic, "ustar ",sizeof(hdr.magic) + sizeof(hdr.version));
#ifdef Q_OS_WIN
//memset(hdr.uname, 0, sizeof(hdr.uname));
//memset(hdr.gname, 0, sizeof(hdr.gname));
#else
qstrncpy(hdr.uname, codec->fromUnicode(infos.uname).constData(), sizeof(hdr.uname));
qstrncpy(hdr.gname, codec->fromUnicode(infos.gname).constData(), sizeof(hdr.gname));
#endif
//memset(hdr.devmajor, 0, sizeof(hdr.devmajor));
//memset(hdr.devminor, 0, sizeof(hdr.devminor));
//memset(hdr.prefix, 0, sizeof(hdr.prefix));
unsigned int checksum = 0;
const unsigned char *ptr = reinterpret_cast<const unsigned char *>(&hdr);
for (unsigned i = 0; i < sizeof(hdr); i++)
checksum += ptr[i];
constexpr int octalMax = 01000000;
while (checksum > octalMax)
checksum -= octalMax;
sprintf(hdr.chksum, "%06o", checksum);
if (!device->write((const char *)&hdr, sizeof(hdr)))
{
lastError = QLatin1String("Error writing to QIODevice");
return false;
}
return true;
}
bool TarFilter::Private::addHeader(const FileInformations &infos)
{
// TODO: do some sanity checks (e.g. for filesize)
QByteArray fn = codec->fromUnicode(infos.fileName);
#ifdef Q_OS_WIN
if (fn.size() > 3 && fn[1] == ':' && (fn[2] == '\\' || fn[2] == '/'))
fn = fn.mid(3);
#endif
if (fn.startsWith('/'))
fn = fn.mid(1);
if (fn.size() > 512)
{
lastError = QLatin1String("Can't handle filenames with more then 512 bytes");
return false;
}
if (fn.size() > 100)
{
FileInformations longlink;
longlink.fileName = QLatin1String("././@LongLink");
longlink.fileType = gnu_longname;
longlink.fileSize = strlen(fn.constData()) + 1; // including '\0' ?
longlink.mtime = 0;
longlink.uid = 0;
longlink.gid = 0;
#ifndef Q_OS_WIN
struct passwd *p = getpwuid(longlink.uid);
if (p)
longlink.uname = codec->toUnicode(p->pw_name);
struct group *g = getgrgid(longlink.gid);
if (g)
longlink.gname = codec->toUnicode(g->gr_name);
#endif
fi2tph(longlink);
QByteArray ba(512, '\0');
qstrncpy(ba.data(), fn.constData(), ba.size());
if (!device->write(ba.constData(), ba.size()))
{
lastError = QLatin1String("Error writing to QIODevice");
return false;
}
}
if (!fi2tph(infos))
return false;
return true;
}
bool TarFilter::Private::tph2fi(FileInformations &infos)
{
Private::tar_posix_header hdr;
do
{
int iBytesRead = device->read((char *)&hdr, sizeof(hdr));
if (iBytesRead != sizeof(hdr))
{
if (iBytesRead == 0 && device->atEnd())
{
lastError = QString();
return false;
}
lastError = QStringLiteral("Error reading from QIODevice! needed: %1, got: %2").arg(sizeof(hdr)).arg(iBytesRead);
return false;
}
}
while (memcmp(hdr.magic, "\0\0\0\0\0\0", sizeof(hdr.magic)) == 0);
if (memcmp(hdr.magic, "ustar ", sizeof(hdr.magic)))
{
lastError = QLatin1String("The archive is not supported");
return false;
}
int checksum = QByteArray(hdr.chksum, sizeof(hdr.chksum)).toUInt(nullptr, 8);
memset(hdr.chksum, ' ', sizeof(hdr.chksum));
int realChecksum = 0;
const unsigned char *ptr = reinterpret_cast<const unsigned char *>(&hdr);
for (unsigned i = 0; i < sizeof(hdr); i++)
realChecksum += ptr[i];
if (checksum != realChecksum)
{
lastError = QStringLiteral("Checksum does not match! needed: %1, got: %2").arg(checksum).arg(realChecksum);
return false;
}
QByteArray ba(hdr.name, sizeof(hdr.name));
ba.resize(qstrlen(ba.constData()));
infos.fileName = codec->toUnicode(ba);
infos.fileSize = QByteArray(hdr.size, sizeof(hdr.size)).toUInt(nullptr, 8);
infos.mode = static_cast<QFile::Permissions>(QByteArray(hdr.mode, sizeof(hdr.mode)).toUInt(nullptr, 16));
infos.uid = QByteArray(hdr.uid, sizeof(hdr.uid)).toUInt(nullptr, 8);
infos.gid = QByteArray(hdr.gid, sizeof(hdr.gid)).toUInt(nullptr, 8);
infos.mtime = QByteArray(hdr.mtime, sizeof(hdr.mtime)).toUInt(nullptr, 8);
infos.fileType = (FileType)hdr.typeflag;
infos.uname = codec->toUnicode(hdr.uname, sizeof(hdr.uname));
infos.gname = codec->toUnicode(hdr.gname, sizeof(hdr.gname));
return true;
}
bool TarFilter::Private::getHeader(FileInformations &infos)
{
if (!tph2fi(infos))
return false;
switch (infos.fileType)
{
case regular:
case regular2:
case directory:
case gnu_longname:
break;
default:
lastError = QStringLiteral("Unsupported fileType %1").arg(infos.fileType);
return false;
}
if (infos.fileType == gnu_longname)
{
const QByteArray fn = device->read(512);
if (fn.size() != 512)
{
lastError = QLatin1String("Unexpected end of inputstream");
return false;
}
if (!tph2fi(infos))
return false;
const int len = qstrlen(fn.constData()); // get the real length
infos.fileName = codec->toUnicode(fn.constData(), len);
}
return true;
}
bool TarFilter::Private::checkDevice(QIODevice *in, QIODevice *out)
{
if (!in)
{
lastError = QLatin1String("No QIODevice for reading available");
return false;
}
if ((in->openMode() & QIODevice::ReadOnly) == 0)
{
lastError = QLatin1String("QIODevice not opened for reading");
return false;
}
if (!out)
{
lastError = QLatin1String("No QIODevice for writing available");
return false;
}
if ((out->openMode() & QIODevice::WriteOnly) == 0)
{
lastError = QLatin1String("QIODevice not opened for writing");
return false;
}
return true;
}
bool TarFilter::Private::copyData(QIODevice *in, QIODevice *out, qint64 iSize)
{
if (iSize <= 0)
return true;
while (iSize > 0)
{
if (aborted) return false;
const qint64 iBytesToRead = iSize > iBufSize ? iBufSize : iSize;
const QByteArray ba = in->read(iBytesToRead);
if (aborted) return false;
if (ba.size() == 0)
{
lastError = QStringLiteral("Could not read %1 bytes from QIODevice").arg(iBytesToRead);
return false;
}
if (out->write(ba) != ba.size())
{
lastError = QStringLiteral("Could not write %1 bytes to QIODevice").arg(ba.size());
return false;
}
iSize -= ba.size();
if (readCallback)
readCallback(iSize);
}
return true;
}
//
// TarFilter
//
TarFilter::TarFilter(QIODevice *dev, QTextCodec *codec, const std::function<void(qint64)> &readCallback)
: d(new Private(dev, codec))
{
d->readCallback = readCallback;
}
TarFilter::~TarFilter()
{
delete d;
}
void TarFilter::abort()
{
d->aborted = 1;
}
void TarFilter::setLocaleCodec(QTextCodec *codec)
{
d->codec = codec ? codec : QTextCodec::codecForLocale();
}
void TarFilter::setBufferSize(unsigned int size)
{
d->iBufSize = size > 1024 ? size : 1024;
}
bool TarFilter::error() const
{
return !d->lastError.isEmpty();
}
QString TarFilter::lastError() const
{
return d->lastError;
}
bool TarFilter::addFile(const QString &filename, const QString &filenameInArchive)
{
QFileInfo fi(filename);
if (!fi.exists())
{
d->lastError = QStringLiteral("File %1 does not exist").arg(filename);
return false;
}
if (!(fi.isDir() || fi.isFile()))
{
d->lastError = QStringLiteral("%1 isn't a directory or a regular file").arg(filename);
return false;
}
FileInformations fInfos;
fInfos.fileName = (filenameInArchive.isEmpty() ? filename : filenameInArchive);
fInfos.fileSize = fi.isDir() ? 0 : fi.size();
fInfos.mode = fi.permissions() & 0x0fff;
#ifdef Q_OS_WIN
fInfos.uid = 1000;
fInfos.gid = 100;
#else
fInfos.uid = fi.ownerId();
fInfos.gid = fi.groupId();
fInfos.uname = fi.owner();
fInfos.gname = fi.group();
#endif
fInfos.mtime = fi.lastModified().toSecsSinceEpoch();
fInfos.fileType = fi.isDir() ? directory : regular;
if (fi.isDir())
{
QBuffer buf;
buf.open(QIODevice::ReadOnly);
return addData(fInfos, &buf);
}
QFile f(filename);
if (!f.open(QIODevice::ReadOnly))
{
d->lastError = QStringLiteral("Error opening %1 for reading").arg(filename);
return false;
}
if (d->aborted) return false;
return addData(fInfos, &f);
}
bool TarFilter::addData(const QString &filename, const QByteArray &data, bool bIsDir)
{
if (d->aborted) return false;
FileInformations fi;
fi.fileName = filename;
fi.fileSize = bIsDir ? 0 : data.size();
fi.mode = static_cast<QFile::Permissions>(bIsDir ? 0x0755 : 0x0644);
fi.fileType = bIsDir ? directory : regular;
#ifndef Q_OS_WIN
fi.uid = getuid();
fi.gid = getgid();
char name[256];
struct passwd *p_ptr = nullptr;
struct passwd p;
getpwuid_r(fi.uid, &p, name, sizeof(name) - 1, &p_ptr);
if (p_ptr)
fi.uname = d->codec->toUnicode(p_ptr->pw_name);
struct group *g_ptr;
struct group g;
getgrgid_r(fi.gid, &g, name, sizeof(name) - 1, &g_ptr);
if (g_ptr)
fi.gname = d->codec->toUnicode(g_ptr->gr_name);
#endif
QBuffer buf(const_cast<QByteArray *>(&data));
if (!buf.open(QIODevice::ReadOnly))
{
d->lastError = QLatin1String("Internal Error - can't open QBuffer for reading!");
return false;
}
return addData(fi, &buf);
}
bool TarFilter::addData(const FileInformations &fi, QIODevice *in)
{
if (d->aborted) return false;
if (!d->checkDevice(in, d->device))
return false;
if (!d->addHeader(fi))
return false;
if (fi.fileSize)
{
if (!d->copyData(in, d->device, fi.fileSize))
return false;
int align = fi.fileSize % 512;
if (align)
{
align = 512 - align;
QByteArray ba2(align, '\0');
d->device->write(ba2.constData(), align);
}
}
return true;
}
bool TarFilter::writeEOS()
{
/* The end of an archive is marked by at least two consecutive zero-filled records. */
const int size = sizeof(TarFilter::Private::tar_posix_header) * 2;
QByteArray ba(size, '\0');
return (d->device->write(ba) == size);
}
bool TarFilter::getData(FileInformations &fi)
{
if (d->aborted) return false;
d->nextChunkSize = -1;
if (!d->getHeader(fi))
return false;
d->nextChunkSize = fi.fileSize;
return true;
}
bool TarFilter::getData(QIODevice *out)
{
if (d->aborted) return false;
if (!d->checkDevice(d->device, out))
return false;
if (d->nextChunkSize < 0)
{
d->lastError = QLatin1String("No informations about next chunk size. Did you call getData(FileInformations &fi) before?");
return false;
}
if (!d->copyData(d->device, out, d->nextChunkSize))
return false;
int align = d->nextChunkSize % 512;
if (align)
d->device->read(512 - align);
d->nextChunkSize = -1;
return true;
}
bool TarFilter::getData(FileInformations &fi, QByteArray &data)
{
if (!getData(fi))
return false;
QBuffer buf(&data);
buf.open(QIODevice::WriteOnly);
return getData(&buf);
}
bool TarFilter::getData(FileInformations &fi, QIODevice *out)
{
if (!getData(fi))
return false;
return getData(out);
}
@@ -0,0 +1,112 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
/****************************************************************************
**
** Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>.
** All rights reserved.
**
** This file is part of the KDE installer for windows
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Library General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Library General Public License for more details.
**
** You should have received a copy of the GNU Library General Public License
** along with this library; see the file COPYING.LIB. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef TARFILTER_H
#define TARFILTER_H
#include <QString>
#include <QFile>
#include <functional>
class QIODevice;
class QTextCodec;
class QByteArray;
/* This small class provides a 'filter' to create/read from a tar stream
It currently only supports a small piece of the tar specs as it's only
intended to use it inside the kdewin-installer project
Feel free to extend it :)
*/
class TarFilter
{
public:
Q_DISABLE_COPY(TarFilter)
enum FileType
{
regular = '0',
regular2 = '\0',
link = '1',
reserved = '2',
charType = '3',
block = '4',
directory = '5',
fifo = '6',
reserved2 = '7',
gnu_longLink = 'K', // next chunk is a long linkname
gnu_longname = 'L', // next chunk is a long filename
};
struct FileInformations
{
QString fileName;
qint64 fileSize = 0;
int uid = 1000;
int gid = 100;
QString uname;
QString gname;
time_t mtime = -1;
FileType fileType = regular;
QFile::Permissions mode = QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther;
};
// @dev - the device to add data to or get data from
// @codec - codec to use for filenames in archive
TarFilter(QIODevice *dev, QTextCodec *codec = nullptr, const std::function<void(qint64)> &readCallback = nullptr);
~TarFilter();
void abort();
void setLocaleCodec(QTextCodec *codec); // default: codecForLocale()
void setBufferSize(unsigned int size); // default: 1MB
bool error() const; // true when an error occoured
QString lastError() const; // last error occoured, not rest on usage
// add Data to a tar stream
bool addData(const FileInformations &fi, QIODevice *in);
// convenience functions for addData()
bool addFile(const QString &filename, const QString &filenameInArchive = QString());
bool addData(const QString &filename, const QByteArray &data = QByteArray(), bool bIsDir = false);
// write empty header as end of stream marker
bool writeEOS();
// read data from a tar stream
bool getData(FileInformations &fi, QIODevice *out);
// convenience functions for getData()
bool getData(FileInformations &fi); // only reads data, for use with getData(QIODevice)
bool getData(QIODevice *out);
bool getData(FileInformations &fi, QByteArray &data);
private:
class Private;
Private *const d;
};
#endif // TARFILTER_H
@@ -0,0 +1,178 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglcomp_test.h"
#include "nglcomp_compress.h"
#include <ngltools/ngltools_filesystem.h>
#include <nglapplication/nglcoreapplication.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QtTest>
// QTEST_MAIN(nglcomp_test)
void nglcomp_test::initTestCase()
{
m_tempDirIn.setAutoRemove(true);
m_tempDirOut.setAutoRemove(true);
QVERIFY(m_tempDirIn.isValid());
QVERIFY(m_tempDirOut.isValid());
QVERIFY(m_tf.open());
m_tf.setAutoRemove(true);
m_fileContent[QLatin1String("1.txt")] = "111111111111111111111111";
m_fileContent[QLatin1String("sub1/s1.txt")] = "222222222222222222222222";
m_fileContent[QLatin1String("sub1/sub11/s11.txt")] = "333333333333333333333333";
m_fileContent[QLatin1String("sub1/sub12/s12.txt")] = "444444444444444444444444";
m_fileContent[QLatin1String("sub2/2.txt")] = "555555555555555555555555";
}
void nglcomp_test::testCompressFile()
{
QDir dir;
const auto directories = {
QLatin1String("sub1"),
QLatin1String("sub1/sub11"),
QLatin1String("sub1/sub12"),
QLatin1String("sub2")
};
for (const QLatin1String &directory : directories)
QVERIFY(dir.mkdir(subPathIn(directory)));
for (auto it = m_fileContent.cbegin(); it != m_fileContent.cend(); ++it)
writeTestFile(it.key(), it.value());
NGL::Compress c;
c.compress(&m_tf, subPathIn(QString()), QLatin1String("out"));
QVERIFY(c.waitForFinished());
}
void nglcomp_test::testCompressMemory()
{
QBuffer f(&m_ba);
QVERIFY(f.open(QIODevice::WriteOnly));
QVector<NGL::Compress::FileInformations> fi1;
QVector<NGL::Compress::FileInformations> fi2;
NGL::Compress::FileInformations fi;
fi.inputFileName = QLatin1String("chris.txt");
fi.fileData = QByteArray("dumdidum\n");
fi2 += fi;
fi.inputFileName = QLatin1String("blub/chris.txt");
fi.fileData = QByteArray("dumdidum im Verzeichnis blub\n");
fi2 += fi;
fi.inputFileName = QLatin1String("blub/blub/chris2.txt");
fi.fileData = QByteArray("dumdidum im Verzeichnis blub/blub\n");
fi2 += fi;
NGL::Compress c;
c.compress(&f, QString(), fi1, fi2, QLatin1String("blub"));
QVERIFY(c.waitForFinished());
f.close();
}
void nglcomp_test::testUncompressMemory()
{
QBuffer f(&m_ba);
QVERIFY(f.open(QIODevice::ReadOnly));
NGL::Compress c;
c.uncompress(&f, subPathIn(QString()));
QVERIFY(c.waitForFinished());
f.close();
QVERIFY(f.open(QIODevice::ReadOnly));
c.uncompress(&f);
QVERIFY(c.waitForFinished());
QVector<NGL::Compress::FileInformations> fi1 = c.getMemFiles();
QVERIFY(fi1.count() == 4);
f.close();
}
void nglcomp_test::testUncompressFile()
{
NGL::Compress c;
m_tf.seek(0);
c.uncompress(&m_tf, subPathOut(QString()));
QVERIFY(c.waitForFinished());
for (auto it = m_fileContent.cbegin(); it != m_fileContent.cend(); ++it)
checkContent(it.key(), it.value());
}
void nglcomp_test::cleanupTestCase()
{
m_tf.close();
m_tempDirIn.remove();
m_tempDirOut.remove();
}
void nglcomp_test::writeTestFile(const QString &fn, const QByteArray &content) const
{
QFile f(subPathIn(fn));
QVERIFY(f.open(QIODevice::WriteOnly));
QVERIFY(f.write(content) == content.size());
f.close();
}
void nglcomp_test::checkContent(const QString &fn, const QByteArray &content) const
{
QFile f(subPathOut(QLatin1String("out/") + fn));
QVERIFY(f.open(QIODevice::ReadOnly));
QCOMPARE(f.readAll(), content);
}
QString nglcomp_test::subPathIn(const QString &p) const
{
return m_tempDirIn.path() + QLatin1Char('/') + p;
}
QString nglcomp_test::subPathOut(const QString &p) const
{
return m_tempDirOut.path() + QLatin1Char('/') + p;
}
// 14.11.2024, Norbert Thoden:
// replace macro 'QTEST_MAIN' (on top)
// by this explicit main declaration.
// reason: nglcomp_test crashes. within macro
// so use NGLCoreApplication, createLogger
// Unfortunately one testcase is still not successful:
//********* Start testing of nglcomp_test *********
//Config: Using QtTest library 5.15.2, Qt 5.15.2 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 7.5.0), opensuse-leap 15.4
//PASS : nglcomp_test::initTestCase()
//2024-11-14 09:24:53.176 ERROR nglcompress |#| success? 1 (l/source/Z/src/nglcompression/nglcomp_compress.cpp:499)
//QWARN : nglcomp_test::testCompressFile() ## COMPRESS DTOR!!!!
//PASS : nglcomp_test::testCompressFile()
//2024-11-14 09:24:53.176 ERROR nglcompress |#| success? 1 (l/source/Z/src/nglcompression/nglcomp_compress.cpp:499)
//QWARN : nglcomp_test::testCompressMemory() ## COMPRESS DTOR!!!!
//PASS : nglcomp_test::testCompressMemory()
//2024-11-14 09:24:53.176 ERROR nglcompress |#| success? 1 (l/source/Z/src/nglcompression/nglcomp_compress.cpp:499)
//QWARN : nglcomp_test::testUncompressFile() ## COMPRESS DTOR!!!!
//PASS : nglcomp_test::testUncompressFile()
//2024-11-14 09:24:53.176 ERROR nglcompress |#| success? 1 (l/source/Z/src/nglcompression/nglcomp_compress.cpp:499)
//2024-11-14 09:24:53.176 ERROR nglcompress |#| success? 0 (l/source/Z/src/nglcompression/nglcomp_compress.cpp:499)
//FAIL! : nglcomp_test::testUncompressMemory() 'c.waitForFinished()' returned FALSE. ()
// Loc: [/shd/CTC/TOOLS/TDS/3dws_devel/source/Z/src/nglcompression/nglcomp_test.cpp(92)]
//QWARN : nglcomp_test::testUncompressMemory() ## COMPRESS DTOR!!!!
int main(int argc, char *argv[])
{
NGLCoreApplication app(argc, argv);
//app.setAttribute(Qt::AA_Use96Dpi, true);
app.createLogger("nglcomp_test", "log4cxx_nglcomp_test.props");
nglcomp_test tc;
return QTest::qExec(&tc, argc, argv);
}
@@ -0,0 +1,39 @@
/**
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QByteArray>
#include <QHash>
#include <QObject>
#include <QTemporaryDir>
#include <QTemporaryFile>
class nglcomp_test : public QObject
{
Q_OBJECT
public:
nglcomp_test() = default;
private Q_SLOTS:
void initTestCase();
void testCompressFile();
void testCompressMemory();
void testUncompressFile();
void testUncompressMemory();
void cleanupTestCase();
private:
void writeTestFile(const QString &fn, const QByteArray &content) const;
void checkContent(const QString &fn, const QByteArray &content) const;
QString subPathIn(const QString &p) const;
QString subPathOut(const QString &p) const;
private:
QHash<QString, QByteArray> m_fileContent;
QByteArray m_ba;
QTemporaryFile m_tf;
QTemporaryDir m_tempDirIn;
QTemporaryDir m_tempDirOut;
};
@@ -0,0 +1,45 @@
# NGLDB
FIND_PACKAGE(PostgreSQL REQUIRED)
OPTION(ENABLE_DB_TRACING "Enable trace output for NGLDB library" OFF)
IF(ENABLE_DB_TRACING)
add_compile_definitions(NGLDB_ENABLE_TRACE)
ENDIF(ENABLE_DB_TRACING)
#
# NGL Database Library
#
SET(ngldb_SRCS
dbcommon.h
dbconnection.cpp
dbconnection.h
db_service_handler.h
dbtransaction.cpp
dbtransaction.h
ngldb_export.h
ngldb_logger.cpp
ngldb_logger.h
nsqlquery.cpp
nsqlquery.h
sql_query_janitor.cpp
sql_query_janitor.h
)
NGL_ADD_LIBRARY(AAR SV HLA WS ngldb SHARED ${ngldb_SRCS})
NGL_TARGET_LINK_LIBRARIES(ngldb
PRIVATE
NGLLogger
nglsettings
${PostgreSQL_LIBRARIES}
PUBLIC
Qt5::Core
Qt5::Sql
)
NGL_TARGET_INCLUDE_DIRECTORIES(ngldb
PRIVATE
${PostgreSQL_INCLUDE_DIR}
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_INSTALL_TARGET(ngldb)
@@ -0,0 +1,62 @@
/**
* Database Handler for Aes
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <nglsettings/nglsettings_settings.h>
#include <memory>
class QSqlDatabase;
namespace NGLDB
{
template<typename DB>
class DbServiceHandler
{
public:
DbServiceHandler() = default;
~DbServiceHandler() = default;
//!< Initializes the database connection and the db interface
bool init(int exerciseId, NGL::Settings *settings)
{
if (m_dbInterface)
return true;
m_dbInterface = DB::create(exerciseId);
if (!m_dbInterface->init(m_dbInterface->dbUser(),
settings->databasePassword(m_dbInterface->dbUser()),
settings->databaseDriver(),
settings->databaseHostname(),
settings->databaseName()))
{
m_dbInterface = nullptr;
return false;
}
return true;
}
bool init(int exerciseId, const QSqlDatabase &db)
{
if (m_dbInterface)
return true;
m_dbInterface = DB::create(exerciseId);
if (!m_dbInterface->init(db))
{
m_dbInterface = nullptr;
return false;
}
return true;
}
std::shared_ptr<DB> db() const { return m_dbInterface; }
private:
std::shared_ptr<DB> m_dbInterface;
};
} // namespace DbServiceHandler
+58
View File
@@ -0,0 +1,58 @@
/**
* @RDE_HEADER@
* Common functions and types for the database access
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "ngldb_export.h"
#include <QString>
/**
* Common functions for database access.
* It also has some convenience functions for the current exercise/currently logged in user
*/
namespace DBCommon
{
enum class eDatabaseSchema
{
Exercise //!< The exercise schema - depends on the choosen exercise (i.e exercise_<id>)
};
/**
* Return the schema name used for exercises (ex_%1).
*/
inline QString getExerciseSchemaName(int exerciseId)
{
return QLatin1String("ex_") + QString::number(exerciseId);
}
/**
* Return the complete table name with given database schema.
* @param tableName the table to build the name for
* @param exerciseId only relevant for the exercise conf/data schema.
* Uses the given id instead the current
* (e.g. for new exercise creation)
* @return the complete table name
*/
inline QString getTableName(const QString &tableName, const QString &schemaName)
{
if (schemaName.isEmpty())
return tableName;
return schemaName + QLatin1Char('.') + tableName;
}
/**
* Return a table name to directly access the exercise configuration schema
* @param tableName table to access
* @return table name ( i.e. ex_2.ppm_partiticpant )
*/
inline QString getExerciseTableName(const QString &tableName, int exerciseId)
{
return getTableName(tableName, getExerciseSchemaName(exerciseId));
}
}
@@ -0,0 +1,73 @@
/**
* @RDE_HEADER@
* Connect to a Database and set the default connection
* $Id$
* $HeadURL$
* $Author$
*/
#include "dbconnection.h"
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlError>
#include <NGLLogger/INGLLogger.h>
#include "nsqlquery.h"
namespace DBConnection
{
QSqlDatabase open(NGL::INGLLogger &logger,
const QString &dbUser,
const QString &dbPasswd,
const QString &dbDriver,
const QString &dbHost,
const QString &dbName,
const QString &schemaName,
const QString &connectionName)
{
// really needed?
//const QString connectionName((driver == QLatin1String("QODBC")) ? dbName : connectionNameForDatabase(eDb));
DEBUG_LOG(logger) << "host: " << dbHost << " database: " << dbName;
QString realConnectionName(connectionName);
if (connectionName.isEmpty())
{
realConnectionName = dbHost + QLatin1Char('_') + dbName;
if (!schemaName.isEmpty())
realConnectionName += QLatin1Char('_') + schemaName;
}
auto dbConnection = QSqlDatabase::addDatabase(dbDriver, realConnectionName);
dbConnection.setHostName(dbHost);
dbConnection.setDatabaseName(dbName);
dbConnection.setUserName(dbUser);
dbConnection.setPassword(dbPasswd);
if (!dbConnection.open())
{
const QString err = dbConnection.lastError().nativeErrorCode();
FATAL_LOG(logger) << "Error opening database " << dbHost
<< ":" << dbName << " as user " << dbUser;
FATAL_LOG(logger) << dbConnection.lastError().driverText() << " "
<< dbConnection.lastError().databaseText() << " " << err;
return dbConnection;
}
DEBUG_LOG(logger) << "Database Initialisation successful -> DB: " << dbName << ", con: " << realConnectionName;
if (!schemaName.isEmpty())
{
const QString stmt = QLatin1String("SET SEARCH_PATH TO ") + schemaName + QLatin1String(", PUBLIC");
NSqlQuery q(dbConnection);
if (!q.exec(stmt))
{
ERROR_LOG(logger) << "Set SEARCH_PATH to " << schemaName << " failed!";
dbConnection.close();
}
}
return dbConnection;
}
} // namespace DBConnection
@@ -0,0 +1,29 @@
/**
* @RDE_HEADER@
* Connect to a Database and set the default connection
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtSql/QSqlDatabase>
#include "ngldb_export.h"
namespace NGL
{
class INGLLogger;
}
namespace DBConnection
{
NGLDB_EXPORT QSqlDatabase open(NGL::INGLLogger &logger,
const QString &dbUser,
const QString &dbPasswd,
const QString &dbDriver,
const QString &dbHost,
const QString &dbName,
const QString &schemaName = QString(),
const QString &connectionName = QString());
} // namespace DBConnection
@@ -0,0 +1,87 @@
/**
* @RDE_HEADER@
* Wrapper around QSqlDatabase::transaction() & co with auto rollback
* $Id$
* $HeadURL$
* $Author$
*/
#include "dbtransaction.h"
#include "ngldb_logger.h"
#include <QtSql/QSqlError>
thread_local int s_refCounter = 0;
DBTransaction::DBTransaction(const QSqlDatabase &db)
: m_db(db)
, m_bCommitted(true)
, mLogger(NGLDB::getLogger("DBTransaction"))
{
++s_refCounter;
if (s_refCounter == 1)
begin();
}
DBTransaction::~DBTransaction()
{
if (s_refCounter == 1)
{
if (!m_bCommitted)
rollback();
}
--s_refCounter;
}
bool DBTransaction::begin()
{
if (!m_bCommitted)
return setState(false);
if (!m_db.transaction())
{
ERROR_LOG(mLogger) << "Error starting a transaction: " << m_db.lastError().driverText();
return setState(false);
}
m_bCommitted = false;
return setState(true);
}
bool DBTransaction::commit()
{
if (s_refCounter == 1)
{
if (!m_db.commit())
{
ERROR_LOG(mLogger) << "Error committing a transaction: " << m_db.lastError().driverText();
return setState(false);
}
m_bCommitted = true;
return setState(true);
}
return true;
}
bool DBTransaction::rollback()
{
if (s_refCounter == 1)
{
if (!m_db.rollback())
{
ERROR_LOG(mLogger) << "Error rolling back a transaction" << m_db.lastError().driverText();
return setState(false);
}
m_bCommitted = true;
return setState(true);
}
return true;
}
bool DBTransaction::state() const
{
return m_lastState;
}
bool DBTransaction::setState(bool bState)
{
m_lastState = bState;
return m_lastState;
}
@@ -0,0 +1,71 @@
/**
* @RDE_HEADER@
* Wrapper around QSqlDatabase::transaction() & co with auto rollback
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtSql/QSqlDatabase>
#include "ngldb_export.h"
namespace NGL
{
class INGLLogger;
}
/**
* A small wrapper class for QSqlDatabase transactions.
* The destructor does an automatic rollback if there was
* no commit before. Therefore you can't accidently forget to
* close the transaction
*/
class NGLDB_EXPORT DBTransaction
{
public:
/**
* Begins a trtasaction on database db
* @param db selected database
*/
explicit DBTransaction(const QSqlDatabase &db);
/**
* When no commit() or rollback() was called, the dtor
* automatically rolls back the current transaction
*/
~DBTransaction();
/**
* Begins a new transaction. Normally you don't have to
* call this function because the dtor does this fopr you.
* @return true on success
*/
bool begin();
/**
* Commits a transaction
* @return true on success
*/
bool commit();
/**
* Rolls back a transaction
* @return true on success
*/
bool rollback();
/**
* Returns the last state. Usefull when you want to check
* the result of begin() called inside the ctor.
* @return the success state of the last action
*/
bool state() const;
private:
bool setState(bool bState);
QSqlDatabase m_db;
bool m_bCommitted;
bool m_lastState;
NGL::INGLLogger &mLogger;
};
// kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef NGLDB_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLDB_EXPORT
# else
# if defined(MAKE_NGLDB_LIB)
# define NGLDB_EXPORT Q_DECL_EXPORT
# else
# define NGLDB_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
@@ -0,0 +1,29 @@
/**
* @RDE_HEADER@
* Logger for ngldb
* $Id$
* $HeadURL$
* $Author$
*/
#include "ngldb_logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
NGLDB::LOGGER_T NGLDB::getLogger(const char *name)
{
static const char ns[] = "NGLDB.";
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();
}
}
@@ -0,0 +1,36 @@
/**
* @RDE_HEADER@
* Logger for ngldb
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
#ifdef Q_CC_GNU
#define DB_TRACE_FUNCTION __PRETTY_FUNCTION__
#else
#define DB_TRACE_FUNCTION __FUNCTION__
#endif
#ifdef NGLDB_ENABLE_TRACE
#define DB_TRACE { TRACE_LOG(mLogger) << DB_TRACE_FUNCTION }
#define DB_TRACE2(x) { TRACE_LOG(mLogger) << DB_TRACE_FUNCTION << x }
#else
#define DB_TRACE
#define DB_TRACE2(x)
#endif
namespace NGLDB
{
typedef NGL::INGLLogger &LOGGER_T;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace NGLDB
+462
View File
@@ -0,0 +1,462 @@
/**
* @RDE_HEADER@
* Wrapper around QSqlQuery with enhanced logging functionality
* $Id$
* $HeadURL$
* $Author$
*/
#include "nsqlquery.h"
#include <QtCore/QVariant>
#include <QtSql/QSqlDriver>
#include <QtSql/QSqlError>
#include <QtSql/QSqlRecord>
#include <QtSql/QSqlResult>
#include <QtCore/QTextStream>
#include <QtCore/QFile>
#include <QtCore/QDateTime>
#include <QtCore/QJsonValue>
#include "ngldb_logger.h"
#include <libpq-fe.h>
static QString getSqlErrorString(const QSqlError &error)
{
return error.driverText() + QLatin1Char(' ') +
error.databaseText() + QLatin1Char(' ') +
error.nativeErrorCode();
}
NSqlQuery::NSqlQuery(const QSqlDatabase &db)
: QSqlQuery(db)
, m_db(db)
, mLogger(NGLDB::getLogger("NSqlQuery"))
{
DB_TRACE
setForwardOnly(true);
}
NSqlQuery::NSqlQuery(const QSqlDatabase &db, NGL::INGLLogger &logger)
: QSqlQuery(db)
, m_db(db)
, mLogger(logger)
{
DB_TRACE
setForwardOnly(true);
}
NSqlQuery::NSqlQuery(const QString &query, const QSqlDatabase &db)
: QSqlQuery(query, db)
, m_db(db)
, mLogger(NGLDB::getLogger("NSqlQuery"))
{
DB_TRACE
setForwardOnly(true);
}
NSqlQuery::NSqlQuery(const QString &query, const QSqlDatabase &db, NGL::INGLLogger &logger)
: QSqlQuery(query, db)
, m_db(db)
, mLogger(logger)
{
DB_TRACE
setForwardOnly(true);
}
void NSqlQuery::addBindValue(const QVariant &val, QSql::ParamType paramType)
{
DB_TRACE;
DEBUG_LOG(mLogger) << "type: " << val.type() << " paramType: " << paramType;
QSqlQuery::addBindValue(val, paramType);
}
int NSqlQuery::at() const
{
DB_TRACE
return QSqlQuery::at();
}
void NSqlQuery::bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType)
{
DB_TRACE;
TRACE_LOG(mLogger) << "placeholder: " << placeholder << " type: " << val.type() << " paramType: " << paramType;
QSqlQuery::bindValue(placeholder, val, paramType);
}
void NSqlQuery::bindValue(int pos, const QVariant &val, QSql::ParamType paramType)
{
DB_TRACE;
TRACE_LOG(mLogger) << "pos: " << pos << " type: " << val.type() << " paramType: " << paramType;
QSqlQuery::bindValue(pos, val, paramType);
}
QVariant NSqlQuery::boundValue(const QString &placeholder) const
{
DB_TRACE
TRACE_LOG(mLogger) << "placeholder: " << placeholder;
return QSqlQuery::boundValue(placeholder);
}
QVariant NSqlQuery::boundValue(int pos) const
{
DB_TRACE
TRACE_LOG(mLogger) << "pos: " << pos;
return QSqlQuery::boundValue(pos);
}
QMap<QString, QVariant> NSqlQuery::boundValues() const
{
DB_TRACE
return QSqlQuery::boundValues();
}
void NSqlQuery::clear()
{
DB_TRACE
return QSqlQuery::clear();
}
const QSqlDriver *NSqlQuery::driver() const
{
DB_TRACE
return QSqlQuery::driver();
}
bool NSqlQuery::exec(const QString &query, bool bEmitMessageOnError)
{
DB_TRACE;
DEBUG_LOG(mLogger) << "query: " << query;
if (QSqlQuery::exec(query))
return true;
if (bEmitMessageOnError)
printLastSqlError();
return false;
}
bool NSqlQuery::exec(bool bEmitMessageOnError)
{
DB_TRACE
DEBUG_LOG(mLogger) << "query: " << lastQuery();
if (mLogger.isDebugEnabled())
{
const QMap<QString, QVariant> &boundValuesMap = boundValues();
for (auto it=boundValuesMap.begin(); it != boundValuesMap.end(); ++it)
{
if ( it.value().canConvert<QString>())
DEBUG_LOG(mLogger) << "key='" << it.key() << "' value='" << it.value().toString() << "'";
else
DEBUG_LOG(mLogger) << "key='" << it.key() << "' value cant Convert to string'";
}
}
if (QSqlQuery::exec())
return true;
if (bEmitMessageOnError)
printLastSqlError();
return false;
}
bool NSqlQuery::execAndFetch()
{
DB_TRACE
if (!exec())
return false;
return (next());
}
bool NSqlQuery::execAndFetch(const QString &query)
{
DB_TRACE
if (!exec(query))
return false;
return (next());
}
bool NSqlQuery::execBatch(BatchExecutionMode mode)
{
DB_TRACE2("mode: " << mode)
DEBUG_LOG(mLogger) << "mode: " << mode;
if (QSqlQuery::execBatch(mode))
return true;
printLastSqlError();
return false;
}
QString NSqlQuery::executedQuery() const
{
DB_TRACE
return QSqlQuery::executedQuery();
}
void NSqlQuery::finish()
{
DB_TRACE
QSqlQuery::finish();
}
bool NSqlQuery::first()
{
DB_TRACE
if (QSqlQuery::first())
return true;
printLastSqlError();
return false;
}
bool NSqlQuery::isActive() const
{
DB_TRACE
return QSqlQuery::isActive();
}
bool NSqlQuery::isForwardOnly() const
{
DB_TRACE
return QSqlQuery::isForwardOnly();
}
bool NSqlQuery::isNull(int field) const
{
DB_TRACE2("field: " << field)
return QSqlQuery::isNull(field);
}
bool NSqlQuery::isSelect() const
{
DB_TRACE
return QSqlQuery::isSelect();
}
bool NSqlQuery::isValid() const
{
DB_TRACE
return QSqlQuery::isValid();
}
bool NSqlQuery::last()
{
DB_TRACE
if (QSqlQuery::last())
return true;
printLastSqlError();
return false;
}
QSqlError NSqlQuery::lastError() const
{
DB_TRACE
return QSqlQuery::lastError();
}
QString NSqlQuery::sqlstate()
{
const QVariant resultHandle = this->result()->handle();
//sqlstate = (resultHandle.isValid())? "ok" : "false";
//return sqlstate;
if (resultHandle.isValid() && (qstrcmp(resultHandle.typeName(), "PGresult*") == 0))
{
// v.data() returns a pointer to the handle
const PGresult *pgresHandle = *static_cast<const PGresult * const *>(resultHandle.data());
if (pgresHandle != nullptr)
{
// check that it is not NULL
return QString::fromLocal8Bit(PQresultErrorField(pgresHandle, PG_DIAG_SQLSTATE));
}
}
/* only reached in case of error */
return QStringLiteral("58000");
}
QVariant NSqlQuery::lastInsertId()
{
DB_TRACE
QVariant ret;
if (this->driver()->hasFeature(QSqlDriver::LastInsertId))
ret = QSqlQuery::lastInsertId();
if (!ret.isValid())
{
NSqlQuery q(m_db);
if (q.execAndFetch(QLatin1String("SELECT LASTVAL()")))
ret = q.value(0);
}
return ret;
}
QString NSqlQuery::lastQuery() const
{
DB_TRACE
return QSqlQuery::lastQuery();
}
bool NSqlQuery::next()
{
DB_TRACE
return QSqlQuery::next();
}
bool NSqlQuery::nextResult()
{
DB_TRACE
if (QSqlQuery::nextResult())
return true;
printLastSqlError();
return false;
}
int NSqlQuery::numRowsAffected() const
{
DB_TRACE
return QSqlQuery::numRowsAffected();
}
QSql::NumericalPrecisionPolicy NSqlQuery::numericalPrecisionPolicy() const
{
DB_TRACE
return QSqlQuery::numericalPrecisionPolicy();
}
bool NSqlQuery::prepare(const QString &query)
{
DB_TRACE2("query: " << query)
if (QSqlQuery::prepare(query))
return true;
printLastSqlError();
return false;
}
bool NSqlQuery::previous()
{
DB_TRACE
if (QSqlQuery::previous())
return true;
printLastSqlError();
return false;
}
QSqlRecord NSqlQuery::record() const
{
DB_TRACE
return QSqlQuery::record();
}
const QSqlResult *NSqlQuery::result() const
{
DB_TRACE
return QSqlQuery::result();
}
bool NSqlQuery::seek(int index, bool relative)
{
DB_TRACE2("index: " << index << " relative: " << relative);
if (QSqlQuery::seek(index, relative))
return true;
printLastSqlError();
return false;
}
void NSqlQuery::setForwardOnly(bool forward)
{
DB_TRACE2("forward: " << forward);
QSqlQuery::setForwardOnly(forward);
}
void NSqlQuery::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
{
DB_TRACE2("precisionPolicy: " << precisionPolicy);
QSqlQuery::setNumericalPrecisionPolicy(precisionPolicy);
}
int NSqlQuery::size() const
{
DB_TRACE
return QSqlQuery::size();
}
QVariant NSqlQuery::value(int index) const
{
DB_TRACE2("index: " << index)
return QSqlQuery::value(index);
}
NSqlQuery &NSqlQuery::operator= (const NSqlQuery &other)
{
DB_TRACE
QSqlQuery::operator= (other);
return *this;
}
bool NSqlQuery::export2CSV(const QString &filename)
{
DB_TRACE2("export csv to file: " << filename)
QFile data(filename);
QTextStream output(&data);
if (data.open(QFile::WriteOnly | QFile::Truncate))
{
if (isSelect() && isActive())
{
bool isHeaderWritten = false;
while (next())
{
QSqlRecord rec = record();
if (!isHeaderWritten)
{
for (int i = 0; i < rec.count(); ++i)
output << QLatin1Char('\"') + rec.fieldName(i) + QLatin1String("\",");
output << QLatin1Char('\n');
isHeaderWritten = true;
}
for (int i = 0; i < rec.count(); ++i)
output << QLatin1Char('\"') + rec.value(i).toString() + QLatin1String("\",");
output << QLatin1Char('\n');
}
}
data.close();
return true;
}
return false;
}
QVariant NSqlQuery::qDateTimeToQVariant(const QDateTime &dt)
{
if (dt.isValid())
return dt.toMSecsSinceEpoch();
return QVariant();
}
QDateTime NSqlQuery::qVariantToQDateTime(const QVariant &var)
{
if (var.isNull())
return QDateTime();
return QDateTime::fromMSecsSinceEpoch(var.toLongLong());
}
QString NSqlQuery::qVariantToJsonString(const QVariant &value)
{
if (value.isNull())
return QStringLiteral("{}");
return value.toString();
}
QString NSqlQuery::jsonValueToJsonString(const QJsonValue &value)
{
if (value.isNull())
return QStringLiteral("{}");
return value.toString();
}
void NSqlQuery::printLastSqlError()
{
ERROR_LOG(mLogger) << getSqlErrorString(lastError()) << " " << lastQuery();
}
QString NSqlQuery::getLastSqlError()
{
return (getSqlErrorString(lastError()) + QLatin1Char(' ') + lastQuery());
}
+281
View File
@@ -0,0 +1,281 @@
/**
* @RDE_HEADER@
* Wrapper around QSqlQuery with enhanced logging functionality
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtSql/QSqlQuery>
#include "ngldb_export.h"
#include "dbcommon.h"
namespace NGL
{
class INGLLogger;
}
class QDateTime;
class QJsonValue;
/**
* Overloads QSqlQuery to output all error and warning messages
* into a common log4cxx logger. This makes the code more readable
* and consistent because you don't have to take care about error
* output anymore. Ir also adds some convienence functions for
* easier access with DBConnection::eDatabase
* Another difference is that QSqlQuery::isForwardOnly() is default
* true whilest QSqlQuery it's false by default.
*/
class NGLDB_EXPORT NSqlQuery final : public QSqlQuery
{
public:
/**
* Overload from QSqlQuery
*/
explicit NSqlQuery(const QSqlDatabase &db);
explicit NSqlQuery(const QSqlDatabase &db, NGL::INGLLogger &logger);
explicit NSqlQuery(const QString &query, const QSqlDatabase &db);
explicit NSqlQuery(const QString &query, const QSqlDatabase &db, NGL::INGLLogger &logger);
/**
* Overload from QSqlQuery
*/
NSqlQuery(const NSqlQuery &other) = default;
/**
* Overload from QSqlQuery
*/
~NSqlQuery() = default;
/**
* Overload from QSqlQuery
*/
void addBindValue(const QVariant &val, QSql::ParamType paramType = QSql::In);
/**
* Overload from QSqlQuery
*/
int at() const;
/**
* Overload from QSqlQuery
*/
void bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType = QSql::In);
/**
* Overload from QSqlQuery
*/
void bindValue(int pos, const QVariant &val, QSql::ParamType paramType = QSql::In);
/**
* Overload from QSqlQuery
*/
QVariant boundValue(const QString &placeholder) const;
/**
* Overload from QSqlQuery
*/
QVariant boundValue(int pos) const;
/**
* Overload from QSqlQuery
*/
QMap<QString, QVariant> boundValues() const;
/**
* Overload from QSqlQuery
*/
void clear();
/**
* Overload from QSqlQuery
*/
const QSqlDriver *driver() const;
/**
* Overload from QSqlQuery
*/
bool exec(const QString &query, bool bEmitMessageOnError = true);
/**
* Overload from QSqlQuery
*/
bool exec(bool bEmitMessageOnError = true);
/**
* Convenience function for exec() && next()
*/
bool execAndFetch();
/**
* Convenience function for exec() && next()
*/
bool execAndFetch(const QString &query);
/**
* Overload from QSqlQuery
*/
bool execBatch(BatchExecutionMode mode = ValuesAsRows);
/**
* Overload from QSqlQuery
*/
QString executedQuery() const;
/**
* Overload from QSqlQuery
*/
void finish();
/**
* Overload from QSqlQuery
*/
bool first();
/**
* Overload from QSqlQuery
*/
bool isActive() const;
/**
* Overload from QSqlQuery
*/
bool isForwardOnly() const;
/**
* Overload from QSqlQuery
*/
bool isNull(int field) const;
/**
* Overload from QSqlQuery
*/
bool isSelect() const;
/**
* Overload from QSqlQuery
*/
bool isValid() const;
/**
* Overload from QSqlQuery
*/
bool last();
/**
* Overload from QSqlQuery
*/
QSqlError lastError() const;
QString sqlstate();
/**
* Overload from QSqlQuery
*/
QVariant lastInsertId();
/**
* Overload from QSqlQuery
*/
QString lastQuery() const;
/**
* Overload from QSqlQuery
*/
bool next();
/**
* Overload from QSqlQuery
*/
bool nextResult();
/**
* Overload from QSqlQuery
*/
int numRowsAffected() const;
/**
* Overload from QSqlQuery
*/
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
/**
* Overload from QSqlQuery
*/
bool prepare(const QString &query);
/**
* Overload from QSqlQuery
*/
bool previous();
/**
* Overload from QSqlQuery
*/
QSqlRecord record() const;
/**
* Overload from QSqlQuery
*/
const QSqlResult *result() const;
/**
* Overload from QSqlQuery
*/
bool seek(int index, bool relative = false);
/**
* Overload from QSqlQuery
*/
void setForwardOnly(bool forward);
/**
* Overload from QSqlQuery
*/
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
/**
* Overload from QSqlQuery
*/
int size() const;
/**
* Overload from QSqlQuery
*/
QVariant value(int index) const;
/**
* Overload from QSqlQuery
*/
NSqlQuery &operator= (const NSqlQuery &other);
bool export2CSV(const QString &filename);
/**
* convert a QDateTime to a QVariant (qint64 - msec since epoch).
* When QDateTime is invalid, an empty QVariant is returned
*/
static QVariant qDateTimeToQVariant(const QDateTime &dt);
/**
* convert a QVariant (qint64 - msec since epoch) into a QDateTime
* When QVariant is invalid, an invalid QDateTime is returned
*/
static QDateTime qVariantToQDateTime(const QVariant &var);
/** To handle possible NULL-values. */
static QString qVariantToJsonString(const QVariant &value);
/** To handle possible NULL-values. */
static QString jsonValueToJsonString(const QJsonValue &value);
static inline QString fixupEmptyJsonString(const QString &str) { return str.isEmpty() ? QLatin1String("{}") : str; }
QString getLastSqlError();
private:
void printLastSqlError();
QSqlDatabase m_db;
NGL::INGLLogger &mLogger;
};
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* SqlQueryJanitor
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLSE, 2019-01-16
*/
#include "sql_query_janitor.h"
#include "nsqlquery.h"
#include <QtGlobal>
SqlQueryJanitor::SqlQueryJanitor(NSqlQuery *query)
: m_query(query)
{
Q_ASSERT(m_query);
Q_ASSERT(!m_query->isActive());
}
SqlQueryJanitor::SqlQueryJanitor(const std::unique_ptr<NSqlQuery> &query)
: SqlQueryJanitor(query.get())
{
}
SqlQueryJanitor::~SqlQueryJanitor()
{
m_query->finish();
}
@@ -0,0 +1,32 @@
/**
* @RDE_HEADER@
* SqlQueryJanitor
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLSE, 2019-01-16
*/
#pragma once
#include "ngldb_export.h"
#include <memory>
class NSqlQuery;
/**
* Janitor that makes sure that the query is not active when entering the scope
* and that the query will be finished when leaving the scope.
*
* @author Christian Fröbel
*/
class NGLDB_EXPORT SqlQueryJanitor
{
public:
explicit SqlQueryJanitor(NSqlQuery *query);
explicit SqlQueryJanitor(const std::unique_ptr<NSqlQuery> &query);
~SqlQueryJanitor();
private:
NSqlQuery *m_query;
};
@@ -0,0 +1,32 @@
#
# CMake Script für nglsettings
# $Id$
# $HeadURL$
# $Author$
#
SET(nglsettings_SRCS
nglsettings_connections.cpp
nglsettings_settings.cpp
)
SET(nglsettings_HDRS
nglsettings_connections.h
nglsettings_export.h
nglsettings_settings.h
)
NGL_ADD_LIBRARY(ALL nglsettings SHARED ${nglsettings_SRCS} ${nglsettings_HDRS})
NGL_TARGET_LINK_LIBRARIES(nglsettings
PRIVATE
ngltools
Qt5::Network
PUBLIC
Qt5::Core
)
NGL_TARGET_INCLUDE_DIRECTORIES(nglsettings
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_INSTALL_TARGET(nglsettings)
@@ -0,0 +1,180 @@
/**
* @RDE_HEADER@
* hold all TCP and UDP connection informations
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglsettings_connections.h"
#include <QCoreApplication>
#include <QMap>
#include <QPair>
#include <QSettings>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QHostInfo>
#include <QtNetwork/QNetworkInterface>
namespace NGL
{
namespace Connections
{
enum class eHostConfig
{
public_local,
localhost,
server,
server_avs
};
struct configStruct
{
eHostConfig host;
unsigned short port;
QString name;
};
static QMap<eConnection, configStruct> *s_config = nullptr;
static QSettings *s_settings = nullptr;
static unsigned short s_portOffset = 9000;
static QString *s_serverHostname = nullptr;
static void cleanupSettings()
{
delete s_settings;
s_settings = nullptr;
delete s_serverHostname;
s_serverHostname = nullptr;
delete s_config;
s_config = nullptr;
}
static void insertConfig(eConnection conn, eHostConfig host, unsigned short port, const char *name)
{
if (!s_config)
s_config = new QMap<eConnection, configStruct>();
configStruct s;
s.host = host;
s.port = port;
s.name = QString::fromLatin1(name);
s_config->insert(conn, s);
}
static void initConfig()
{
if (s_config && !s_config->isEmpty())
return;
insertConfig(eConnection::AVS_WORKSTATION, eHostConfig::localhost, 6370, "AVS_WORKSTATION");
insertConfig(eConnection::AVS_WORKSTATION_VD, eHostConfig::localhost, 6380, "AVS_WORKSTATION_VD");
insertConfig(eConnection::AVS_ROOT, eHostConfig::server_avs, 6350, "AVS_ROOT");
insertConfig(eConnection::AVS_FM, eHostConfig::server_avs, 6360, "AVS_FM");
insertConfig(eConnection::AVS_MOTION_RECORDER, eHostConfig::server_avs, 6390, "AVS_MOTION_RECORDER");
insertConfig(eConnection::AVS_AVA, eHostConfig::server_avs, 6391, "AVS_AVA");
insertConfig(eConnection::PWS_WEBSOCKET, eHostConfig::server, 5701, "PWS_WEBSOCKET");
insertConfig(eConnection::SCM_WEBSOCKET, eHostConfig::server, 7300, "SCM_WEBSOCKET");
insertConfig(eConnection::ISM_WEBSOCKET, eHostConfig::server, 2080, "ISM_WEBSOCKET"); // see ICD
insertConfig(eConnection::FLM_THP_SERVER, eHostConfig::server, 2090, "FLM_THP_SERVER");
insertConfig(eConnection::FLM_PDF_SERVER, eHostConfig::server, 3000, "FLM_PDF_SERVER"); // TODO: verify port with team
insertConfig(eConnection::LVS, eHostConfig::server, 94, "LVS");
insertConfig(eConnection::ZWLVSV, eHostConfig::server, 95, "ZWLVSV");
insertConfig(eConnection::ZWLVWCS, eHostConfig::server, 97, "ZWLVWCS");
insertConfig(eConnection::ZWLVWMS, eHostConfig::server, 98, "ZWLVWMS");
insertConfig(eConnection::ZSLV, eHostConfig::server, 99, "ZSLV");
}
void setIniFile(const QString &iniFileName)
{
if (!s_settings)
qAddPostRoutine(cleanupSettings);
delete s_settings;
s_settings = new QSettings(iniFileName, QSettings::IniFormat);
}
QString iniFile()
{
return s_settings ? s_settings->fileName() : QString();
}
unsigned short portOffset()
{
return s_portOffset;
}
void setPortOffset(unsigned short portOffset)
{
s_portOffset = portOffset;
}
unsigned short port(eConnection connection)
{
initConfig();
unsigned short port = s_config->value(connection).port;
if (s_settings)
{
bool bOk;
QString key = s_config->value(connection).name + QLatin1String("/port");
unsigned short port2 = s_settings->value(key, port).toString().toUShort(&bOk);
if (bOk)
port = port2;
}
if (port < 100)
return portOffset() + port;
return port;
}
QString hostName(eConnection connection)
{
initConfig();
QString host;
switch (s_config->value(connection).host)
{
case eHostConfig::public_local:
host = QString::fromLocal8Bit(qgetenv("HOST"));
break;
case eHostConfig::localhost:
host = QLatin1String("127.0.0.1");
break;
case eHostConfig::server:
if (s_serverHostname)
host = *s_serverHostname;
if (host.isEmpty())
host = QLatin1String("EXCTDS01");
break;
case eHostConfig::server_avs:
host = QStringLiteral("EXCAVS01");
break;
}
if (s_settings)
{
QString key = s_config->value(connection).name + QLatin1String("/host");
QString host2 = s_settings->value(key, host).toString();
if (!host2.isEmpty())
host = host2;
}
return host;
}
void setServerHostname(const QString &serverHostName)
{
if (!s_serverHostname)
s_serverHostname = new QString(serverHostName);
else
*s_serverHostname = serverHostName;
}
QString connectionName(eConnection connection)
{
if (s_config)
{
auto it = s_config->constFind(connection);
if (it != s_config->constEnd())
return it.value().name;
}
return QString::number((int)connection);
}
} // namespace Connections
} // namespace NGL
@@ -0,0 +1,92 @@
/**
* @RDE_HEADER@
* hold all TCP and UDP connection informations
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QString>
#include "nglsettings_export.h"
namespace NGL
{
/**
* Handle ports and hostnames for all connections between
* TDS Server and Workstation processes
*/
namespace Connections
{
/**
* All connections used in TDS
*/
enum class eConnection
{
UNKNOWN = 0, //!< not defined
AVS_WORKSTATION, //!< Audio/Video Workstation
AVS_WORKSTATION_VD, //!< Audio/Video Workstation exporter
AVS_ROOT, //!< Root process on server
AVS_FM, //!< FM process on server
AVS_MOTION_RECORDER, //!< MotionRecorder
AVS_AVA, //!< stripped AVA - Interface (provided by MotionRecorder)
ZWLVSV, //!< Port for Warehouse-Server
ZSLV, //!< Schnittstelle zwischen WMS und ECC
ZWLVWCS, //!< Schnittstelle WMS -> WCS (Unitechnik)
ZWLVWMS, //!< Schnittstelle WCS -> WMS
PWS_WEBSOCKET,//!< WebSocket Schnittstelle Projektions Workstation
SCM_WEBSOCKET,//!< WebSocket Schnittstelle ServiceManagement
ISM_WEBSOCKET,//!< WebSocket Schnittstelle InfrastructureManagemen
FLM_THP_SERVER, //!< Tcp Server for THP up/download
FLM_PDF_SERVER, //!< Tcp Server for PDF download
LVS , //!< Websocket Schnittstelle zwischen WarehouseGuez und LVS (neues Lagerververwaltungsystem)
};
/**
* Set the ini file (gfs_ws.ini or gfs_sv.ini or a custom one) to
* read the ports and hostnames from there. The section name must
* be the name of the connection (e.g. [ZWKOTP]). The port offset
* is then read from the key 'port' and the hostname from the key
* 'host'. If the given port is below 100 the portOffset() is added
* to the port.
* When there's not entry for a specified port, the hardcoeded
* default values are used. This should be the default use case.
* This function should not be called directly because
* NGL::Settings() does it for you.
* @param iniFileName the full path to the ini file
*/
NGLSETTINGS_EXPORT void setIniFile(const QString &iniFileName);
/**
* Retrieve the currently used config file
* @return the current config file
*/
NGLSETTINGS_EXPORT QString iniFile();
/**
* The port offset is set via setPortOffset()
*/
NGLSETTINGS_EXPORT unsigned short portOffset();
void setPortOffset(unsigned short portOffset);
/**
* Retrieve the port for a given connection
* @param connection the connection to get the port for
* @return the port for the given connection
*/
NGLSETTINGS_EXPORT unsigned short port(eConnection connection);
/**
* Retrieve the hostname for a given connection
* @param connection the connection to get the hostname for
* @return the hostname for the given connection
*/
NGLSETTINGS_EXPORT QString hostName(eConnection connection);
void setServerHostname(const QString &serverHostName);
/**
* Retrieve the connection name for a given connection. This
* name is equal to the ini section name and can be used
* for debug or error output.
* @param connection the connection to get the name for
* @return the name for the given connection
*/
NGLSETTINGS_EXPORT QString connectionName(eConnection connection);
} // namespace Connections
} // namespace NGL
@@ -0,0 +1,21 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef NGLSETTINGS_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLSETTINGS_EXPORT
# else
# ifdef MAKE_NGLSETTINGS_LIB
# define NGLSETTINGS_EXPORT Q_DECL_EXPORT
# else
# define NGLSETTINGS_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
@@ -0,0 +1,325 @@
/**
* @RDE_HEADER@
* Base settings class for all nglsettings
* $Id$
* $HeadURL$
* $Author$
*/
#include "nglsettings_settings.h"
#include "nglsettings_connections.h"
#include <ngltools/ngltools_filesystem.h>
#include <QCoreApplication>
#include <QDir>
#include <QSettings>
#include <QSize>
#include <QStandardPaths>
namespace NGL
{
QSettings *Settings::s_globalSettings = nullptr;
Settings::Settings(const QString &iniFile_)
: m_settings(nullptr)
{
QString iniFile = iniFile_;
if(iniFile == QLatin1String("gfs_ws.ini")) {
const QByteArray defUser = qgetenv("USER");
if( defUser == "ctc_aar" || defUser == "ctc_rbf" ) {
QByteArray home = qgetenv("HOME");
if(!home.isEmpty()) {
QString fn = QString::fromLocal8Bit(home) +
QLatin1String("/gfs_") +
QString::fromLocal8Bit(defUser.mid(4)) +
QLatin1String(".ini");
QFileInfo fi(fn);
if(fi.exists() && fi.isFile() && fi.isReadable()) {
iniFile = fn;
}
}
}
}
initializeGlobalSettings();
initPre();
if(!iniFile.isEmpty()) {
if(QFileInfo(iniFile).isAbsolute())
m_settings = new QSettings(iniFile, QSettings::IniFormat);
else
m_settings = new QSettings(basePath() + iniFile, QSettings::IniFormat);
initPost();
}
if (!m_settings)
m_settings = new QSettings(QLatin1String("RDE"));
}
Settings::Settings(const QString &organization, const QString &application)
: m_settings(new QSettings(organization, application))
{
initPre();
initPost();
}
Settings::~Settings()
{
delete m_settings;
}
void Settings::initializeGlobalSettings()
{
if (s_globalSettings)
return;
if (!s_globalSettings)
{
QString globalSettingsFile = NGL::findProjectConfigFile();
//std::cerr << "Using global settings file '" << qPrintable(globalSettingsFile)
// << "'" << std::endl;
if (!globalSettingsFile.isEmpty())
s_globalSettings = new QSettings(globalSettingsFile, QSettings::IniFormat);
}
if (!s_globalSettings)
s_globalSettings = new QSettings(QLatin1String("RDE"), QLatin1String("LTS-CC"));
Connections::setPortOffset(portOffset());
Connections::setServerHostname(serverHostname());
}
QString Settings::globalSectionName()
{
QString secName = QLatin1String("Global");
static const char envGlobSecName[] = "LTS_CONF_GLOBAL_SECTION_NAME";
if (qEnvironmentVariableIsSet(envGlobSecName))
secName = QString::fromLocal8Bit(qgetenv(envGlobSecName));
return secName;
}
QString Settings::basePath() const
{
return m_paths["GFS_PATH"];
}
QString Settings::tempPath() const
{
return m_paths["TMP_PATH"];
}
QString Settings::printPath()
{
return getDirectory("PDF", tempPath());
}
QString Settings::logoProject()
{
return QLatin1String(":project/logo.png");
}
QString Settings::bitmapPath()
{
return getDirectory("BITMAPS", basePath() + QLatin1String("DATA"));
}
QString Settings::zsks_rxPath()
{
return getDirectory("ZSKS_RX", tempPath());
}
QString Settings::zsks_txPath()
{
return getDirectory("ZSKS_TX", tempPath());
}
QString Settings::aarServerPath(int exerciseId)
{
return getDirectory(QByteArray::number(exerciseId), QString::fromLocal8Bit("/data/aar/"));
}
bool Settings::isDatabaseConnectionLocal()
{
return (databaseHostname() == QStringLiteral("localhost"));
}
QString Settings::databaseName()
{
initializeGlobalSettings();
//IO 12.12.2016 only here read from env variable
return s_globalSettings->value(globalSectionName()+ QLatin1String("/DatabaseName"), QLatin1String("lts_ets_pro")).toString();
}
QString Settings::databaseHostname()
{
initializeGlobalSettings();
return s_globalSettings->value(QLatin1String("Global/DatabaseHostname"), QLatin1String("EXCDBS01")).toString();
}
QString Settings::databaseUser()
{
#ifdef Q_OS_WIN
QByteArray defUser = qgetenv("USERNAME");
#else
QByteArray defUser = qgetenv("USER");
#endif
QString ret = m_settings->value(QLatin1String("db/user"), QString::fromLocal8Bit(defUser)).toString();
return ret;
}
QString Settings::databasePassword(const QString &databaseUser)
{
QString defaultPw = QStringLiteral("ctc11de");
if (!databaseUser.isEmpty())
{
const QVector<QStringRef> &sl = databaseUser.splitRef(QLatin1Char('_'));
if (sl.size() > 1)
defaultPw = sl.at(0).toString() + QStringLiteral("11de");
}
return m_settings->value(QLatin1String("db/passwd"), defaultPw).toString();
}
QString Settings::databaseDriver()
{
return m_settings->value(QLatin1String("db/driver"), QLatin1String("QPSQL")).toString();
}
int Settings::avsKeepAliveTimeout()
{
return m_settings->value(QLatin1String("avs/keepalivetimeout"), 20000).toInt();
}
QString Settings::avsServerHost()
{
return m_settings->value(QLatin1String("avs/serverhost"), QLatin1String("EXCAVS01")).toString();
}
quint16 Settings::avsServerPortAVE()
{
static const quint16 defaultPort = 6350;
bool bOk;
quint16 ret = m_settings->value(QLatin1String("avs/serverport_ave"), defaultPort).toUInt(&bOk);
return bOk ? ret : defaultPort;
}
QSettings *Settings::settings()
{
return m_settings;
}
const QSettings *Settings::settings() const
{
return m_settings;
}
QString Settings::fixupPath(const QString &_path) const
{
QString path = QDir::fromNativeSeparators(_path);
if(!QDir::isAbsolutePath(path))
path = basePath() + path;
path = QDir::cleanPath(path);
if(!path.endsWith(QLatin1Char('/')))
path += QLatin1Char('/');
return path;
}
QString Settings::getDirectory(const QByteArray &_dir, const QString &defPrefix, bool bPathLowercase)
{
if(m_paths[_dir].isEmpty()) {
const QString lowerDir = QString::fromLatin1(_dir.toLower());
const QString dir = bPathLowercase ? lowerDir : QString::fromLatin1(_dir);
QString def = defPrefix + QLatin1Char('/') + dir + QLatin1Char('/');
m_paths[_dir] = fixupPath(m_settings->value(QLatin1String("paths/") + lowerDir, def).toString());
QDir d(m_paths[_dir]);
if(!d.exists())
d.mkpath(d.absolutePath());
}
return m_paths[_dir];
}
void Settings::initPre()
{
#ifdef WIN32
QString path = QString::fromLocal8Bit(qgetenv("GFS_PATH"));
if(path.isEmpty())
path = QCoreApplication::applicationDirPath();
m_paths["GFS_PATH"] = fixupPath(path);
#else
QByteArray path = qgetenv("GFS_PATH");
if(path.isEmpty())
path = qgetenv("HOME");
m_paths["GFS_PATH"] = fixupPath(QString::fromLocal8Bit(path));
#endif
QByteArray tmppath = qgetenv("TMP_PATH");
if(tmppath.isEmpty())
tmppath = qgetenv("TMP");
if (tmppath.isEmpty())
tmppath = QDir::tempPath().toLocal8Bit();
m_paths["TMP_PATH"] = fixupPath(QString::fromLocal8Bit(tmppath));
}
void Settings::initPost()
{
NGL::Connections::setIniFile(m_settings->fileName());
}
int Settings::getInteger(const QString &key, int defVal) const
{
bool bOk;
int ret = m_settings->value(key, defVal).toInt(&bOk);
return bOk ? ret : defVal;
}
float Settings::getFloat(const QString &key, float defVal) const
{
bool bOk;
float ret = m_settings->value(key, defVal).toFloat(&bOk);
return bOk ? ret : defVal;
}
double Settings::getDouble(const QString &key, double defVal) const
{
bool bOk;
double ret = m_settings->value(key, defVal).toDouble(&bOk);
return bOk ? ret : defVal;
}
bool Settings::getBoolean(const QString &key, bool defVal) const
{
return m_settings->value(key, defVal).toBool();
}
QString Settings::getString(const QString &key, const QString &defVal) const
{
return m_settings->value(key, defVal).toString();
}
unsigned short Settings::domainId()
{
initializeGlobalSettings();
return s_globalSettings->value(QLatin1String("Global/DomainId"), 0).toUInt();
}
unsigned short Settings::portOffset()
{
initializeGlobalSettings();
return s_globalSettings->value(QLatin1String("Global/PortOffset"), 9000).toUInt();
}
QString Settings::serverHostname()
{
initializeGlobalSettings();
return s_globalSettings->value(QLatin1String("Global/ServerHostname"), QLatin1String("EXCTDS01")).toString();
}
QString Settings::logPath()
{
initializeGlobalSettings();
#ifdef WIN32
return s_globalSettings->value(QLatin1String("Global/LogPath"), QStandardPaths::writableLocation(QStandardPaths::TempLocation)).toString();
#else
return s_globalSettings->value(QLatin1String("Global/LogPath"), QLatin1String("/shd/CTC/LOG")).toString();
#endif
}
} // namespace NGL
@@ -0,0 +1,159 @@
/**
* @RDE_HEADER@
* Base settings class for all nglsettings
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QString>
#include <QtCore/QHash>
#include "nglsettings_export.h"
class QSettings;
namespace NGL {
/**
* A base settings class to retrieve informations
* from the global ini file. All programs which need
* a config should derive from this class to have
* consistent settings handling in TDS
*/
class NGLSETTINGS_EXPORT Settings {
public:
/**
* ctor. The ini file should be either 'gfs_ws.ini' or
* 'gfs_sv.ini'
* @param iniFile 'gfs_ws.ini' for workstation processes and
* 'gfs_sv.ini' for server processes
*/
explicit Settings(const QString &iniFile);
/**
* ctor. see QSettings ctor
*/
explicit Settings(const QString &organization, const QString &application);
// no copy allowed
Settings(const Settings&) = delete;
Settings &operator=(const Settings&) = delete;
/**
* dtor
*/
virtual ~Settings();
//!< initialize global settings (db host, name, logpath, server name)
static void initializeGlobalSettings();
//!< Returns the base path ($GFS_PATH)
QString basePath() const;
//!< Returns the path for temporary files ($TMP_PATH)
QString tempPath() const;
//!< Return the path for PDF printing
QString printPath();
//!< Return project logo path
QString logoProject();
//!< Return the path for the bitmaps ($GFS_PATH/DATA/BITMAPS)
QString bitmapPath();
// Server
//!< Return the path for ZSKS_RX temp dir
QString zsks_rxPath();
//!< Return the path for ZSKS_TX temp dir
QString zsks_txPath();
// Database connection
//!< The database name (legatus), key: db/name
static QString databaseName();
//!< The database host (EXCDBS01), key: db/host
static QString databaseHostname();
//!< The user used to connect to the db (ctc_sv/ctc_ws), key: db/user
QString databaseUser();
//!< The password for dbUser(), key: db/passwd
QString databasePassword(const QString &databaseUser = QString());
//!< The Qt database driver name (QPSQL, QSQLITE), key: db/driver
QString databaseDriver();
// Server AAR Path
//!< Return the path for downloadable After Action Reviews ("/data/aar/%EXERCISEID%")
QString aarServerPath(int exerciseId);
bool isDatabaseConnectionLocal();
// AVS-Configuration
int avsKeepAliveTimeout();
QString avsServerHost();
quint16 avsServerPortAVE();
//!< Return the pointer to the QSettings object
QSettings *settings();
//!< Return the const pointer to the QSettings object
const QSettings *settings() const;
//!< Convenience function for settings()->value([int], [def]).toInt()
int getInteger(const QString &key, int defVal) const;
//!< Convenience function for settings()->value([int], [def]).toInt()
int getInteger(const QString &group, const QString &key, int defVal) const
{
return getInteger(group + QLatin1Char('/') + key, defVal);
}
//!< Convenience function for settings()->value([int], [def]).toFloat()
float getFloat(const QString &key, float defVal) const;
//!< Convenience function for settings()->value([int], [def]).toFloat()
float getFloat(const QString &group, const QString &key, float defVal) const
{
return getFloat(group + QLatin1Char('/') + key, defVal);
}
//!< Convenience function for settings()->value([int], [def]).toDouble()
double getDouble(const QString &key, double defVal) const;
//!< Convenience function for settings()->value([int], [def]).toDouble()
double getDouble(const QString &group, const QString &key, double defVal) const
{
return getDouble(group + QLatin1Char('/') + key, defVal);
}
//!< Convenience function for settings()->value([int], [def]).toBool()
bool getBoolean(const QString &key, bool defVal) const;
//!< Convenience function for settings()->value([int], [def]).toBool()
bool getBoolean(const QString &group, const QString &key, bool defVal) const
{
return getBoolean(group + QLatin1Char('/') + key, defVal);
}
//!< Convenience function for settings()->value([int], [def]).toString()
QString getString(const QString &key, const QString &defVal) const;
//!< Convenience function for settings()->value([int], [def]).toString()
QString getString(const QString &group, const QString &key, const QString &defVal) const
{
return getString(group + QLatin1Char('/') + key, defVal);
}
static unsigned short portOffset();
static unsigned short domainId();
static QString serverHostname();
static QString logPath();
static QString globalSectionName();
private:
//!< fixup the path (make absoulte, make sure it ends with '/')
QString fixupPath(const QString &path) const;
/** read dir from iniFile if not already done. If it's not in the
* ini file build it from <defPrefix>/<dir>
* The entry in the ini file must be paths/<dir.toLower()>
*/
QString getDirectory(const QByteArray &dir, const QString &defPrefix, bool bPathLowercase = false);
private:
void initPre();
void initPost();
QSettings *m_settings;
static QSettings *s_globalSettings;
QHash<QByteArray, QString> m_paths;
};
} // namespace NGL
@@ -0,0 +1,34 @@
#
# CMake Script für ngltools
# $Id$
# $HeadURL$
# $Author$
#
SET(ngltools_SRCS
ngltools_bitset.h
ngltools_convert.cpp
ngltools_convert.h
ngltools_dtg.cpp
ngltools_dtg.h
ngltools_export.h
ngltools_filesystem.cpp
ngltools_filesystem.h
ngltools_helpevent.cpp
ngltools_helpevent.h
)
NGL_ADD_LIBRARY(ALL ngltools SHARED ${ngltools_SRCS})
NGL_TARGET_LINK_LIBRARIES(ngltools
PUBLIC
Qt5::Core
)
NGL_TARGET_COMPILE_DEFINITIONS(ngltools PUBLIC BUILD_BASE_PATH="${CMAKE_BINARY_DIR}")
NGL_TARGET_COMPILE_DEFINITIONS(ngltools PUBLIC INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}")
NGL_TARGET_INCLUDE_DIRECTORIES(ngltools
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_INSTALL_TARGET(ngltools)
@@ -0,0 +1,105 @@
/**
* @RDE_HEADER@
* Kleine Klasse zum einfacheren Handling von BitSets
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
namespace NGL {
template<class T>
class BitSet {
public:
BitSet(T bitset = T())
: mBitSet(bitset)
, mSize(sizeof(T)*8)
{}
BitSet(const BitSet<T> &other)
: mBitSet(other.mBitSet)
, mSize(other.mSize)
{}
BitSet &operator=(const BitSet<T> &other)
{
if(this == &other)
return *this;
mBitSet = other.mBitSet;
mSize = other.mSize;
return *this;
}
bool operator==(const BitSet<T> &other) const
{
return (mBitSet == other.mBitSet && mSize == other.mSize);
}
bool setBit(unsigned int bitNum)
{
if(bitNum >= mSize)
return false;
mBitSet |= getBit(bitNum);
return true;
}
bool clearBit(unsigned int bitNum)
{
if(bitNum >= mSize)
return false;
mBitSet &= ~(getBit(bitNum));
return true;
}
bool at(unsigned int bitNum) const
{
if(bitNum >= sizeof(T) * 8)
return false;
T compVal = getBit(bitNum);
return ((mBitSet & compVal) == compVal);
}
bool operator[] (unsigned int bitNum) const
{
return at(bitNum);
}
size_t size() const
{
return mSize;
}
bool resize(size_t newSize)
{
if(newSize >= sizeof(T) * 8)
return false;
for(unsigned int i = mSize; i < newSize; ++i)
clearBit(i);
mSize = newSize;
return true;
}
void clear()
{
fill(false);
}
void fill(bool bBitsSet)
{
if(bBitsSet)
mBitSet = ~T();
else
mBitSet = T();
}
T operator()() const { return mBitSet; }
protected:
static T getBit(unsigned int bitNum_)
{
T bitNum = bitNum_;
const T one = 1;
return (one << bitNum);
}
T mBitSet;
size_t mSize;
};
} // namesapce NGL
@@ -0,0 +1,91 @@
#include "ngltools_convert.h"
#include <QVector>
namespace NGL
{
QByteArray quoteForTelnet(const QVector<QString> &sl)
{
QVector<QByteArray> tmp;
tmp.reserve(sl.size());
for (const QString &s : sl)
tmp += s.toUtf8();
return quoteForTelnet(tmp);
}
QByteArray quoteForTelnet(const QVector<QByteArray> &sl)
{
QByteArray cmd;
for (QByteArray s : sl)
{
s.replace('\"', "\\\"");
if (s.contains(' '))
s = '"' + s + '"';
if (s.isEmpty())
s = "\"\"";
cmd += s + ' ';
}
cmd += '\n';
return cmd;
}
QVector<QByteArray> parseFromTelnet(const QByteArray &ba, const int iStart)
{
QVector<QByteArray> ret;
const char *p = ba.constData() + iStart;
const int iLen = ba.length();
const char *p_end = ba.constData() + iLen;
if (iLen <= iStart)
return ret;
char quoteEndChar = '"';
while (p < p_end && *p)
{
while (isspace(*p))
++p;
if (*p && p < p_end)
{
bool escaped = false;
bool bQuoted = (*p == '\"') || (*p == '{');
if (bQuoted)
{
quoteEndChar = (*p == '\"') ? '\"' : '}';
++p;
}
const char *start = p;
while (true)
{
while (p < p_end && *p != (bQuoted ? quoteEndChar : ' '))
++p;
if (bQuoted)
{
// escaped '\"' ?
if (* (p - 1) == '\\')
{
++p;
escaped = true;
continue;
}
}
QByteArray result = QByteArray(start, p - start).trimmed();
if (escaped)
{
if (quoteEndChar == '}')
{
result = result.replace("\\{", "{");
result = result.replace("\\}", "}");
}
else
result = result.replace("\\\"", "\"");
}
ret += result;
++p;
break;
}
}
}
return ret;
}
} // namespace NGL;
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* <short description>
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "ngltools_export.h"
#include <QByteArray>
#include <QString>
#include <QVector>
namespace NGL
{
NGLTOOLS_EXPORT QByteArray quoteForTelnet(const QVector<QString> &sl);
NGLTOOLS_EXPORT QByteArray quoteForTelnet(const QVector<QByteArray> &sl);
/**
* splits a bytearray into args separated by space. Takes care for quoted
* arguments
*/
NGLTOOLS_EXPORT QVector<QByteArray> parseFromTelnet(const QByteArray &ba, const int iStart = 0);
}
@@ -0,0 +1,372 @@
#include "ngltools_dtg.h"
#include <QString>
#include <QDateTime>
namespace DTG
{
static char s_timezone = 'Z';
static char s_userDefinedTimezone = s_timezone;
static char s_exerciseDefaultTimezone = s_timezone;
int timezone2Hours(char tz, bool *bOk)
{
if (!isTimezoneValid(tz))
{
if (bOk)
*bOk = false;
return 0;
}
if (bOk)
*bOk = true;
if (tz < 'J')
return tz - 'A' + 1;
if (tz < 'N')
return tz - 'A';
if (tz < 'Z')
return 'Z' - tz - 13;
return 0;
}
int timezone2Secs(char tz, bool *bOk)
{
return 3600 * timezone2Hours(tz, bOk) ;
}
bool setTimezone(char tz, bool bUserDefinedZone)
{
if (!isTimezoneValid(tz))
{
// allow to reset user defined timezone
if (!(tz == 0 && bUserDefinedZone))
return false;
}
if (bUserDefinedZone)
s_userDefinedTimezone = tz;
else
s_exerciseDefaultTimezone = tz;
s_timezone = s_userDefinedTimezone != 0 ? s_userDefinedTimezone : s_exerciseDefaultTimezone;
return true;
}
char timezone()
{
return s_timezone;
}
char timezoneUserDefined()
{
return s_userDefinedTimezone;
}
char timezoneExerciseDefault()
{
return s_exerciseDefaultTimezone;
}
bool isTimezoneValid(char tz)
{
tz = toupper(tz);
return !(tz < 'A' || tz == 'J' || tz > 'Z');
}
// Static:
static DateTimeType s_dateTimeType = DDMMYYYY_Z_HHMMSS;
static DisplayFormat s_defaultDisplayFormat = Long;
void setDateTimeType(DateTimeType dtType)
{
s_dateTimeType = dtType;
}
DateTimeType dateTimeType()
{
return s_dateTimeType;
}
void setDefaultDisplayFormat(DisplayFormat dtFormat)
{
s_defaultDisplayFormat = dtFormat;
}
DisplayFormat defaultDisplayFormat()
{
return s_defaultDisplayFormat;
}
QString toString(const QDateTime &dt, DisplayFormat format, DateTimeType type)
{
if (format == Default)
format = s_defaultDisplayFormat;
static const QDateTime dtNull = QDateTime::fromSecsSinceEpoch(0);
if (!dt.isValid() || dt == dtNull)
return QString();
const QDateTime dateTime = dt.toUTC().addSecs(timezone2Hours(s_timezone) * 3600);
QString ret;
switch (type)
{
case DTG:
{
///////////////////////
// DTG
// (GUEZ & TES-UAE)
QString str1;
if (format == Long)
str1 = dateTime.toString(QLatin1String("dd hhmmss"));
else if (format == TurboLong)
str1 = dateTime.toString(QLatin1String("dd hhmmss.z"));
else
{
ret = dateTime.toString(QLatin1String("ddhhmm")) + QLatin1Char(s_timezone);
break;
}
const int month = dateTime.date().month() - 1;
const int year = dateTime.date().year() - 2000;
ret = QStringLiteral("%1 %2 %3 %4")
.arg(str1)
.arg(QLatin1Char(s_timezone))
.arg(months().at(month))
.arg(year, 2, 10, QLatin1Char('0'));
}
break;
case DDMMYYYY_HHMMSS_Z:
{
if (format == Long)
ret = dateTime.toString(QLatin1String("dd.MM.yyyy HH:mm:ss")) + QLatin1Char(s_timezone);
else
ret = dateTime.toString(QLatin1String("dd.MM HH:mm")) + QLatin1Char(s_timezone);
}
break;
case DDMMYYYY_Z_HHMMSS:
if (format == Long)
ret = dateTime.toString(QLatin1String("dd.MM.yyyy "))
+ QLatin1Char(s_timezone)
+ dateTime.toString(QLatin1String(" HH:mm:ss"));
else
ret = dateTime.toString(QLatin1String("dd.MM "))
+ QLatin1Char(s_timezone)
+ dateTime.toString(QLatin1String(" HH:mm"));
break;
} // switch
return ret;
}
QString toStringMSec(qint64 msecSinceEpoch, DisplayFormat format)
{
if (msecSinceEpoch <= 0)
return QString();
return toString(QDateTime::fromMSecsSinceEpoch(msecSinceEpoch), format);
}
static bool check24(const QChar *input, int *output)
{
const int i1 = input[0].unicode() - '0';
const int i2 = input[1].unicode() - '0';
if (i1 > 2)
return false;
if (i1 == 2 && i2 > 5)
return false;
if (output)
*output = i1 * 10 + i2;
return true;
}
static bool check31(const QChar *input, int *output = nullptr)
{
const int i1 = input[0].unicode() - '0';
const int i2 = input[1].unicode() - '0';
if (i1 > 3)
return false;
if (i1 == 3 && i2 > 1)
return false;
if (output)
*output = i1 * 10 + i2;
return true;
}
static bool check60(const QChar *input, int *output)
{
const int i1 = input[0].unicode() - '0';
const int i2 = input[1].unicode() - '0';
if (i1 > 5)
return false;
if (output)
*output = i1 * 10 + i2;
return true;
}
static DTGValidation validate18(const QString &input, QDateTime &dt)
{
int hh, mm, ss;
// dd
for (int i = 0; i < 2; ++i)
{
if (!input[i].isDigit())
return Invalid;
}
if (!check31(&input.data() [0]))
return Invalid;
if (input[2] != QLatin1Char(' '))
return Invalid;
// hhmmss
if (input.length() == 7)
{
for (int i = 3; i < 7; ++i)
{
if (!input[i].isDigit())
return Invalid;
}
return Intermediate;
}
for (int i = 3; i < 9; ++i)
{
if (!input[i].isDigit())
return Invalid;
}
if (!check24(&input.data() [3], &hh))
return Invalid;
if (!check60(&input.data() [5], &mm))
return Invalid;
if (!check60(&input.data() [7], &ss))
return Invalid;
if (input[9] != QLatin1Char(' '))
return Invalid;
// z
const QChar c = input[10];
if (c < QLatin1Char('A') || c > QLatin1Char('Z'))
return Invalid;
if (c == QLatin1Char('J'))
{
//qDebug ( "Invalid z!" );
return Invalid;
}
// mon
const QString mon = input.mid(12, 3);
int month = months().indexOf(mon);
if (month < 0)
{
//qDebug ( "Invalid mon!" );
return Invalid;
}
// yy
for (int i = 16; i < 18; ++i)
{
if (!input[i].isDigit())
return Invalid;
}
// complete
const int day = input.leftRef(2).toInt();
const int year = input.midRef(16, 2).toInt() + 2000;
dt = QDateTime(QDate(year, month + 1, day), QTime(hh, mm, ss), Qt::UTC);
if (!dt.isValid())
{
//qDebug ( "Invalid date (%d, %d, %d)!", year, month + 1, day );
return Invalid;
}
dt = dt.addSecs(-timezone2Hours(c.toLatin1()) * 3600);
//qDebug ( "Match!" );
return Acceptable;
}
static DTGValidation validate7(const QString &input, QDateTime &dt)
{
int hh, mm;
// ddhhmm
for (int i = 0; i < 6; ++i)
{
if (!input[i].isDigit())
return Invalid;
}
if (!check31(&input.data() [0]))
return Invalid;
if (!check24(&input.data() [2], &hh))
return Invalid;
if (!check60(&input.data() [4], &mm))
return Invalid;
// z
const QChar c = input[6];
if (c < QLatin1Char('A') || c > QLatin1Char('Z'))
return Invalid;
if (c == QLatin1Char('J'))
{
//qDebug ( "Invalid z!" );
return Invalid;
}
// complete
const int day = input.leftRef(2).toInt();
const QDate curDate = QDate::currentDate();
dt = QDateTime(QDate(curDate.year(), curDate.month(), day), QTime(hh, mm), Qt::UTC);
if (!dt.isValid())
{
//qDebug ( "Invalid day!" );
return Invalid;
}
dt = dt.addSecs(-timezone2Hours(c.toLatin1()) * 3600);
//qDebug ( "Match!" );
return Acceptable;
}
QDateTime fromDTGString(const QString &str, bool *bOk)
{
if (bOk)
*bOk = false;
QDateTime dt;
if (str.length() == 7)
{
DTGValidation state = validate7(str, dt);
if (state == Acceptable && bOk)
*bOk = true;
}
else if (str.length() == 18)
{
DTGValidation state = validate18(str, dt);
if (state == Acceptable && bOk)
*bOk = true;
}
return dt;
}
DTGValidation validateString(const QString &str, QDateTime &dt)
{
const int len = str.length();
if (len == 7 || len == 18)
{
// first check for Intermediate for length == 18
if (len == 18 || (str[2] == QLatin1Char(' ')))
return validate18(str, dt);
return validate7(str, dt);
}
return Invalid;
}
QStringList months()
{
return {
QLatin1String("jan"), QLatin1String("feb"), QLatin1String("mar"),
QLatin1String("apr"), QLatin1String("may"), QLatin1String("jun"),
QLatin1String("jul"), QLatin1String("aug"), QLatin1String("sep"),
QLatin1String("oct"), QLatin1String("nov"), QLatin1String("dec")
};
}
} // namespace DTG
@@ -0,0 +1,129 @@
#pragma once
#include <QStringList>
#include "ngltools_export.h"
class QDateTime;
/**
* This namespace handles conversions to and from DTG-strings.
*/
namespace DTG
{
/**
* The type of the DateTime string
*/
enum DateTimeType
{
DTG = 1, // GUEZ, TES-UAE
DDMMYYYY_HHMMSS_Z = 2, // provided for RATC, but not within
DDMMYYYY_Z_HHMMSS = 4 // RATC
};
/**
* The format of the DTG string
*/
enum DisplayFormat //!< DateTimeType = DTG / DDMMYYYY_HHMMSS_Z / DDMMYYYY_Z_HHMMSS
{
Short, //!< display date/time in format ddhhmmz / dd.MM HH:mmZ / dd.MM Z HH:mm
Long, //!< display date/time in format dd hhmmss z mon yy / dd.MM.yyyy HH:mm:ssZ / dd.MM.yyyy Z HH:mm:ss
TurboLong,
Default //!< use the (user locale) default setting for the format
};
enum DTGValidation
{
Invalid,
Intermediate,
Acceptable
};
/**
* Set DateTime type
* @param DateTime type to use
*/
NGLTOOLS_EXPORT void setDateTimeType(DateTimeType dtType);
/**
* Get DateTime type
* @return DateTime type
*/
NGLTOOLS_EXPORT DateTimeType dateTimeType();
/**
* Set DefaultDisplayFormat type
* @param DefaultDisplayFormat type to use
*/
NGLTOOLS_EXPORT void setDefaultDisplayFormat(DisplayFormat dtFormat);
/**
* Get DefaultDisplayFormat type
* @return DefaultDisplayFormat type
*/
NGLTOOLS_EXPORT DisplayFormat defaultDisplayFormat();
/**
* Convert a QDateTime into a DTG-string
* @param dt the time to convert
* @param format the DisplayFormat to use
* @return DTG-string
*/
NGLTOOLS_EXPORT QString toString(const QDateTime &dt, DisplayFormat format = Default, DateTimeType = dateTimeType());
/**
* Convert a time_t value into a DTG-string
* @param msecSinceEpoch the time in msec to convert
* @param format the DisplayFormat to use
* @return DTG-string
*/
NGLTOOLS_EXPORT QString toStringMSec(qint64 msecSinceEpoch, DisplayFormat format = Default);
/**
* Tries to convert a given DTG-string into a QDateTime
* @param str the DTG string to convert
* @param bOk Pointer to check if the conversion was successful
* @return The converted time
*/
NGLTOOLS_EXPORT QDateTime fromDTGString(const QString &str, bool *bOk = nullptr);
/**
* Check if the given string is a valid DTG-string
* @param str the string to check
* @param dt the converted time (if conversion was successful)
* @return a QValidator state
*/
NGLTOOLS_EXPORT DTGValidation validateString(const QString &str, QDateTime &dt);
/**
* Set the timezone to use. This information should come from the betriebsdaten_shm
* @param tz the timezone identifier to use ('A' ... 'I' and 'K' ... 'Z')
* @param bUserDefinedZone if set, the timezone was user-defined, then tz can be 0 to use (exercise) default timezone
* @return True on success
*/
NGLTOOLS_EXPORT bool setTimezone(char tz, bool bUserDefinedZone);
/**
* Return the currently used timezone
* @return the currently used timezone
*/
NGLTOOLS_EXPORT char timezone();
NGLTOOLS_EXPORT char timezoneUserDefined();
NGLTOOLS_EXPORT char timezoneExerciseDefault();
NGLTOOLS_EXPORT bool isTimezoneValid(char tz);
/**
* Convert a given timezone into the correct hour offset
* @param tz the timezone identifier to convert
* @param bOk Pointer to check if the conversion was successful
* @return The hour difference between utc and the given timezone
*/
NGLTOOLS_EXPORT int timezone2Hours(char tz, bool *bOk = nullptr);
/**
* Convert a given timezone into the correct seconds offset
* @param tz the timezone identifier to convert
* @param bOk Pointer to check if the conversion was successful
* @return The seconds difference between utc and the given timezone
*/
NGLTOOLS_EXPORT int timezone2Secs(char tz, bool *bOk = nullptr);
/**
* Return the dtg month names
*/
NGLTOOLS_EXPORT QStringList months();
} // namespace DTG
@@ -0,0 +1,23 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#ifndef NGLTOOLS_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define NGLTOOLS_EXPORT
# else
# ifdef WIN32
# ifdef MAKE_NGLTOOLS_LIB
# define NGLTOOLS_EXPORT __declspec(dllexport)
# else
# define NGLTOOLS_EXPORT __declspec(dllimport)
# endif
# else
# define NGLTOOLS_EXPORT __attribute__((visibility("default")))
# endif
# endif
#endif
@@ -0,0 +1,294 @@
/**
* @RDE_HEADER@
* Tools for working on Filesystem
* $Id$
* $HeadURL$
* $Author$
*/
#include "ngltools_filesystem.h"
#include <QCoreApplication>
#include <QDir>
#include <QSettings>
namespace NGL
{
bool removeDirContentsRecursively(const QString &d, bool bAlsoDeleteBaseDir)
{
// DEBUG_LOG(m_logger) << LOGFUNCTION << " dir= '" << d << "'" ;
QDir dir(d);
if (!dir.exists())
return false;
bool success = true;
const QFileInfoList list = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries);
for (const QFileInfo &fi : list)
{
bool ret = false;
if (fi.isDir())
{
ret = removeDirContentsRecursively(fi.absoluteFilePath());
if (!ret)
{
// ERROR_LOG(m_logger) << "Can't remove DirContents: " << fi.absoluteFilePath() << " (write-protect?)" ;
}
else
{
ret = dir.rmdir(fi.absoluteFilePath());
if (!ret)
{
// ERROR_LOG(m_logger) << "Can't remove Dir: " << fi.absoluteFilePath() << " (write-protect?)" ;
}
}
}
else if (fi.isFile() || fi.isSymLink())
{
ret = dir.remove(fi.fileName());
if (!ret)
{
// ERROR_LOG(m_logger) << "Can't remove File: " << fi.absoluteFilePath() << " (write-protect?)" ;
}
}
success &= ret;
}
if (bAlsoDeleteBaseDir)
success &= dir.rmpath(d);
return success;
}
bool copyDirContentsToDir(const QString &source, const QString &destination, bool sourceIsRelative)
{
QString srcPath(source);
if (sourceIsRelative)
{
QVector<QString> pathsToSearch = directories(FileType::ConfigFile);
pathsToSearch.append(directories(FileType::ProjectConfigFile));
for (const QString &basePath : qAsConst(pathsToSearch))
{
QString absolutePath = basePath + QLatin1Char('/') + source;
if (QDir(absolutePath).exists())
{
srcPath = absolutePath;
break;
}
}
if (srcPath.isEmpty())
return false;
}
QDir srcDir(srcPath);
QDir dstDir(destination);
if (!dstDir.exists())
{
bool succ = dstDir.mkdir(destination);
if (!succ)
return false;
}
const QFileInfoList dirList = srcDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot);
for (const QFileInfo &fi : dirList)
{
// Check, if directory already exist
if (!dstDir.exists())
{
bool succ = dstDir.mkdir(fi.fileName());
if (!succ)
return false;
}
bool succ = copyDirContentsToDir(fi.filePath(), dstDir.absolutePath() + QLatin1Char('/') + fi.fileName());
if (!succ)
return false;
}
const QFileInfoList fileList = srcDir.entryInfoList(QDir::Files | QDir::Hidden);
for (const QFileInfo &fi : fileList)
{
QString targetFileName = dstDir.absolutePath() + QLatin1Char('/') + fi.fileName();
QFile targetFile(targetFileName);
if (targetFile.exists())
targetFile.remove();
bool succ = QFile::copy(fi.absoluteFilePath(), targetFileName);
if (!succ)
return false;
}
return true;
}
qint64 getDirectorySize(const QString &dir)
{
QDir d(dir);
qint64 ret = QFileInfo(dir).size();
const QFileInfoList dirList = d.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot);
const QFileInfoList fileList = d.entryInfoList(QDir::Files | QDir::Hidden);
for (const QFileInfo &fi : dirList)
ret += getDirectorySize(fi.absoluteFilePath());
for (const QFileInfo &fi : fileList)
ret += fi.size();
return ret;
}
bool isAppInBuildBasePath()
{
bool ret = false;
#ifdef BUILD_BASE_PATH
const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH));
if (!bbp.isEmpty())
ret = QCoreApplication::applicationDirPath().startsWith(bbp);
#endif
return ret;
}
QString projectConfigFileName()
{
return QLatin1String("lts-cc.conf");
}
QString findProjectConfigFile()
{
return findFile(FileType::ProjectConfigFile, projectConfigFileName());
}
static QString searchFileInDir(const QString &path, const QString &filename, bool bRecursive)
{
if (QFile::exists(path + QLatin1Char('/') + filename))
return path + QLatin1Char('/') + filename;
if (!bRecursive)
return QString();
const QDir d(path);
const QStringList entryList = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
for (const QString &entry : entryList)
{
const QString foundPath = searchFileInDir(path + QLatin1Char('/') + entry, filename, bRecursive);
if (!foundPath.isEmpty())
return foundPath;
}
return QString();
}
QString findFile(FileType fileType, const QString &filename)
{
const QFileInfo fi(filename);
if (fi.isAbsolute())
return fi.exists() ? filename : QString();
const bool bRecursive = (fileType == FileType::ConfigFile);
const QVector<QString> pathsToSearch = directories(fileType);
for (const QString &path : pathsToSearch)
{
const QString foundPath = searchFileInDir(path, filename, bRecursive);
if (!foundPath.isEmpty())
return foundPath;
}
return QString();
}
QVector<QString> directories(FileType fileType)
{
QVector<QString> pathsToSearch;
switch (fileType)
{
case FileType::ProjectConfigFile:
{
#ifdef BUILD_BASE_PATH
const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH));
if (!bbp.isEmpty())
{
// this path should only be used when not installed,
// so we have to check it somehow. The idea is to check if the
// applicationDirPath() matches to BUILD_BASE_PATH + some stuff
if (QCoreApplication::applicationDirPath().startsWith(bbp))
pathsToSearch += bbp;
}
#endif
pathsToSearch += QDir::homePath();
#ifdef Q_OS_UNIX
pathsToSearch += QLatin1String("/etc");
#else
pathsToSearch += QStringLiteral("C:/Rheinmetall/Lts/"); // TODO: use registry
pathsToSearch += QCoreApplication::applicationDirPath();
#endif
break;
}
case FileType::ConfigFile:
{
#ifdef BUILD_BASE_PATH
const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH));
if (!bbp.isEmpty())
{
// this path should only be used when not installed,
// so we have to check it somehow. The idea is to check if the
// applicationDirPath() matches to BUILD_BASE_PATH + some stuff
if (QCoreApplication::applicationDirPath().startsWith(bbp))
pathsToSearch += bbp + QLatin1String("/share/Lts");
}
#endif
pathsToSearch += QCoreApplication::applicationDirPath() + QLatin1String("/share/Lts");
pathsToSearch += QCoreApplication::applicationDirPath() + QLatin1String("/../share/Lts");
pathsToSearch += QDir::homePath() + QLatin1String("/share/Lts");
#ifdef INSTALL_PREFIX
pathsToSearch += QString::fromLocal8Bit(INSTALL_PREFIX) + QLatin1String("/share/Lts");
#endif
break;
}
}
return pathsToSearch;
}
QString findServiceXmlFile(const QString &serviceShortName)
{
return findFile(FileType::ConfigFile, serviceShortName + QLatin1String(".xml"));
}
QString directory(FileType fileType, const QString &subdir)
{
const QVector<QString> pathsToSearch = directories(fileType);
QFileInfo fi;
for (const QString &path : pathsToSearch)
{
fi.setFile(path + QLatin1Char('/') + subdir);
if (fi.isDir() && fi.exists() && fi.isReadable())
return fi.absoluteFilePath() + QLatin1Char('/');
}
return QString();
}
QString postgresExecutablePath(const QString &psqlProgram, QString &errStr)
{
errStr.clear();
#ifdef Q_OS_LINUX
return QStringLiteral("/usr/bin/") + psqlProgram;
#else
static QString s_postgresBinariesPath;
if (s_postgresBinariesPath.isEmpty())
{
QSettings s(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\PostgreSQL\\Installations"), QSettings::NativeFormat);
const QStringList installations = s.childGroups();
if (installations.isEmpty())
{
errStr = QStringLiteral("Could not find a valid PostgreSQL windows installation...");
return psqlProgram;
}
if (installations.size() > 1)
errStr = QStringLiteral("More than one PostgreSQL windows installation found - using the first one: %1").arg(installations.first());
s.beginGroup(installations.first());
const QString baseDir = s.value(QStringLiteral("Base Directory")).toString();
if (baseDir.isEmpty() || !QDir(baseDir).exists())
{
errStr = QStringLiteral("Could not find a valid PostgreSQL windows installation... - Base Directory is empty or does not exist (%1)").arg(baseDir);
return psqlProgram;
}
s_postgresBinariesPath = baseDir + QStringLiteral("/bin/");
}
return s_postgresBinariesPath + psqlProgram + QStringLiteral(".exe");
#endif
}
} // Namespace NGL
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Tools for working on Filesystem
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "ngltools_export.h"
#include <QtCore/QString>
#include <QtCore/QVector>
namespace NGL
{
NGLTOOLS_EXPORT bool removeDirContentsRecursively(const QString &d, bool bAlsoDeleteBaseDir = false);
NGLTOOLS_EXPORT bool copyDirContentsToDir(const QString &source, const QString &destination, bool sourceIsRelative = false);
NGLTOOLS_EXPORT qint64 getDirectorySize(const QString &dir);
/**
* The filetype to search
* ProjectConfigFile -> ${CMAKE_BINARY_PATH}, ~/, /etc/ (non-recursive)
* ConfigFile ../share/, ~/share/, INSTALL_PREFIX/share/ (recursive)
*/
enum class FileType
{
ProjectConfigFile,
ConfigFile
};
NGLTOOLS_EXPORT bool isAppInBuildBasePath();
NGLTOOLS_EXPORT QString projectConfigFileName();
NGLTOOLS_EXPORT QString findProjectConfigFile();
NGLTOOLS_EXPORT QString findFile(FileType fileType, const QString &filename);
/**
* Search for <serviceShortName>.xml
*/
NGLTOOLS_EXPORT QString findServiceXmlFile(const QString &serviceShortName);
// return all possible subdirs for fileType
NGLTOOLS_EXPORT QVector<QString> directories(FileType fileType);
// search the subdir in directories for fileType, return the first one found
NGLTOOLS_EXPORT QString directory(FileType fileType, const QString &subdir);
// find the postgres executable path for the given executable
NGLTOOLS_EXPORT QString postgresExecutablePath(const QString &psqlProgram, QString &errStr);
}
@@ -0,0 +1,25 @@
/**
* @RDE_HEADER@
* An event which is send to QCoreApplication to invoke the
* help viewer with the given context
* $Id$
* $HeadURL$
* $Author$
*/
#include "ngltools_helpevent.h"
#include <QtCore/QCoreApplication>
QEvent::Type NGLHelpEvent::sHelpEventId = (QEvent::Type)(-1);
void NGLHelpEvent::sendHelpEvent(const QString &helpContext)
{
NGLHelpEvent he(helpContext);
QCoreApplication::sendEvent(qApp, &he);
}
QEvent::Type NGLHelpEvent::helpEventId()
{
if(sHelpEventId < 0)
sHelpEventId = (QEvent::Type)(QEvent::registerEventType());
return sHelpEventId;
}
@@ -0,0 +1,67 @@
/**
* @RDE_HEADER@
* An event which is send to QCoreApplication to invoke the
* help viewer with the given context
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/QEvent>
#include <QtCore/QString>
#include "ngltools_export.h"
/**
* A custom event to propagate a request to invoke the
* help viewer with the given helpContext
* The event is send to QCoreApplication where it can
* be retrieved with an eventfilter:
*
* qApp->installEventFilter(this);
* ...
* bool Foo::eventFilter(QObject *obj, QEvent *event)
* {
* if(obj == qApp) {
* if(event->type() == NGLHelpEvent::helpEventId()) {
* NGLHelpEvent *e = static_cast<NGLHelpEvent*>(event);
* onInvokeHelp(e->helpContext());
* e->accept();
* return true;
* }
* return false;
* }
* return Foo::eventFilter(obj,event);
* }
*/
class NGLTOOLS_EXPORT NGLHelpEvent : public QEvent
{
protected:
/**
* Constructs a new NGLHelpEvent
* This should not be called directly. Use
* NGLHelpEvent::sendHelpEvent() instead!
*/
explicit NGLHelpEvent(const QString &helpContext)
: QEvent(helpEventId())
, mHelpContext(helpContext)
{}
public:
/**
* Returns the given help context
*/
QString helpContext() const { return mHelpContext; }
/**
* Creates a new NGLHelpEvent with the given
* help context and sends it to QCoreApplication
*/
static void sendHelpEvent(const QString &helpContext);
/**
* Return the event type for the custom NGLHelpEvent
*/
static QEvent::Type helpEventId();
protected:
QString mHelpContext;
static QEvent::Type sHelpEventId;
};
@@ -0,0 +1,22 @@
#
# ngltranslator lib
# $Id$
# $HeadURL$
# $Author$
#
SET(my_SRCS
ngltranslator.cpp
ngltranslator.h
ngltranslator_export.h
)
NGL_ADD_LIBRARY(ALL ngltranslator SHARED ${my_SRCS})
NGL_TARGET_LINK_LIBRARIES(ngltranslator
PUBLIC
Qt5::Core
)
NGL_TARGET_INCLUDE_DIRECTORIES(ngltranslator
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/..
)
NGL_INSTALL_TARGET(ngltranslator)
Loaded 100 of 18662 files, more files were not shown because too many files have changed in this diff. Show more