Initial commit

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

No files matched your search

@@ -0,0 +1,478 @@
/**
* @RDE_HEADER@
* Xml Reader for Effect Configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLTE, 2021-06-02
*/
#include "xmlreader.h"
#include <QFile>
#include <QUrlQuery>
#include <QXmlStreamAttributes>
namespace BuildingControlUnit
{
XmlReader::XmlReader(QObject *parent)
: QObject(parent)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("XmlReader"))
{
}
bool XmlReader::init(const QString &effectConfigFile)
{
m_contents.effects.clear();
QFile file(effectConfigFile);
DEBUG_LOG(m_logger) << "open effectConfigFile: " << effectConfigFile;
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
WARNING_LOG(m_logger) << "Couldn't open EffectConfigFile: " << effectConfigFile;
return false;
}
QXmlStreamReader xml(file.readAll());
while (!xml.atEnd() && !xml.hasError())
{
QXmlStreamReader::TokenType token = xml.readNext();
if (token == QXmlStreamReader::StartDocument)
continue;
else if (token == QXmlStreamReader::StartElement)
{
if (xml.name() == QStringLiteral("effects"))
continue;
else if (xml.name() == QStringLiteral("backgroundSoundVolume"))
m_contents.bgSoundVolume = xml.readElementText().toInt();
else if (xml.name() == QStringLiteral("hitSoundVolume"))
m_contents.hitSoundVolume = xml.readElementText().toInt();
else if (xml.name() == QStringLiteral("password"))
m_contents.password = xml.readElementText();
else if (xml.name() == QStringLiteral("port"))
m_contents.port = xml.readElementText().toInt();
else if (xml.name() == QStringLiteral("username"))
m_contents.username = xml.readElementText();
else if (xml.name() == QStringLiteral("updateRelayState"))
m_contents.updateRelayState = xml.readElementText().toInt();
if (xml.name() == QStringLiteral("effect"))
{
Effect *e = this->parseEffect(xml);
if (e)
m_contents.effects.append(e);
}
}
}
if (xml.hasError())
{
ERROR_LOG(m_logger) << "Effect Config File had XML Errors:\n" << xml.errorString();
return false;
}
DEBUG_LOG(m_logger) << "Effect Config File Contents: " << m_contents.toString();
createHttpRequests();
return true;
}
Effect *XmlReader::parseEffect(QXmlStreamReader &xml)
{
DEBUG_LOG(m_logger) << "- parseEffect Start";
if (xml.tokenType() != QXmlStreamReader::StartElement ||
xml.name() != QStringLiteral("effect"))
return {};
Effect *e = new Effect();
QXmlStreamAttributes attributes = xml.attributes();
if (attributes.hasAttribute(QStringLiteral("type")))
{
QString typeString = attributes.value(QStringLiteral("type")).toString();
if (typeString == QStringLiteral("relayAction"))
e->effectType = ET_Relay;
else if (typeString == QStringLiteral("backgroundSoundAction"))
e->effectType = ET_BackgroundSound;
else if (typeString == QStringLiteral("bsmFlashAction"))
e->effectType = ET_BsmFlash;
}
xml.readNext();
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
xml.name() == QStringLiteral("effect")))
{
if (xml.tokenType() == QXmlStreamReader::StartElement)
{
if (xml.name() == QStringLiteral("id"))
{
QXmlStreamAttributes attributesName = xml.attributes();
if (attributesName.hasAttribute(QStringLiteral("name")))
{
e->name = attributesName.value(QStringLiteral("name")).toString();
}
e->id = xml.readElementText().toInt();
}
if (xml.name() == QStringLiteral("category"))
{
e->category = static_cast<Category>(xml.readElementText().toInt());
}
if (xml.name() == QStringLiteral("override"))
{
e->override = static_cast<EffectOverride>(xml.readElementText().toInt());
}
if (xml.name() == QStringLiteral("range"))
e->ranges.append(parseRange(xml));
}
xml.readNext();
}
DEBUG_LOG(m_logger) << "- parseEffect: Name: " << e->id
<< ", Type: " << e->effectType
<< ", Category: " << e->category
<< ", Name: " << e->name
<< ", override: " << e->override;
DEBUG_LOG(m_logger) << "- parseEffect End. It has " << e->ranges.size() << " ranges";
return e;
}
Range *XmlReader::parseRange(QXmlStreamReader &xml)
{
if (xml.tokenType() != QXmlStreamReader::StartElement ||
xml.name() != QStringLiteral("range"))
return {};
DEBUG_LOG(m_logger) << "-- parseRange Start";
Range *r = new Range();
QXmlStreamAttributes attributes = xml.attributes();
if (attributes.hasAttribute(QStringLiteral("min")))
r->min = attributes.value(QStringLiteral("min")).toInt();
if (attributes.hasAttribute(QStringLiteral("max")))
r->max = attributes.value(QStringLiteral("max")).toInt();
if (attributes.hasAttribute(QStringLiteral("restartOnChange")))
r->restartOnChange = attributes.value(QLatin1String("restartOnChange")).toString().toLower() == QLatin1String("true");
xml.readNext();
/*
* We're going to loop over the things because the order might change.
* We'll continue the loop until we hit an EndElement named person.
*/
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
xml.name() == QLatin1String("range")))
{
Action *a = parseAction(xml);
if (a && a->aclass != AC_Unset)
r->actions << a;
xml.readNext();
}
DEBUG_LOG(m_logger) << "-- parseRange: [" << r->min << "-" << r->max << "]"
<< ", restartOnChange: " <<r->restartOnChange
<< ", ActionCount: " << r->actions.count();
DEBUG_LOG(m_logger) << "-- parseRange End";
return r;
}
Action *XmlReader::parseAction(QXmlStreamReader &xml)
{
if (xml.tokenType() != QXmlStreamReader::StartElement)
return {};
if (xml.name() == QStringLiteral("action"))
return parseStandardAction(xml);;
if (xml.name() == QStringLiteral("pause"))
return parsePauseAction(xml);
if (xml.name() == QStringLiteral("repeat"))
return parseRepeatAction(xml);
if (xml.name() == QStringLiteral("bsm"))
return parseBsmAction(xml);
WARNING_LOG(m_logger) << "--- parseUnknownAction with name '" << xml.name().string() << "'cannot be handled.";
return {};
}
PauseAction *XmlReader::parsePauseAction(QXmlStreamReader &xml)
{
if (xml.tokenType() != QXmlStreamReader::StartElement ||
xml.name() != QLatin1String("pause"))
return {};
DEBUG_LOG(m_logger) << "--- parsePauseAction Start";
QXmlStreamAttributes attributes = xml.attributes();
PauseAction *p = new PauseAction();
p->atype = static_cast<ActionType>(attributes.value(QStringLiteral("type")).toInt());
if (attributes.hasAttribute(QStringLiteral("comment")))
p->comment = attributes.value(QStringLiteral("comment")).toString();
p->pause = xml.readElementText().toInt();
DEBUG_LOG(m_logger) << "--- parsePauseAction: "
<< " Pause: " << p->pause
<< ", Comment: " << p->comment;
DEBUG_LOG(m_logger) << "--- parsePauseAction End";
return p;
}
RepeatAction *XmlReader::parseRepeatAction(QXmlStreamReader &xml)
{
if (xml.tokenType() != QXmlStreamReader::StartElement ||
xml.name() != QStringLiteral("repeat"))
return {};
DEBUG_LOG(m_logger) << "--- parseRepeatAction Start";
RepeatAction *ra = new RepeatAction();
QXmlStreamAttributes attributes = xml.attributes();
if (attributes.hasAttribute(QStringLiteral("count")))
ra->count = attributes.value(QStringLiteral("count")).toInt();
if (attributes.hasAttribute(QStringLiteral("comment")))
ra->comment = attributes.value(QStringLiteral("comment")).toString();
if (ra->count == 0)
ra->count = -1;
xml.readNext();
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
xml.name() == QStringLiteral("repeat")))
{
Action *a = parseAction(xml);
if (a && a->aclass != AC_Unset)
ra->actions << a;
xml.readNext();
}
QString repetitions = QString::number(ra->count);
if (ra->count < 0)
repetitions = QLatin1String("Infinite");
DEBUG_LOG(m_logger) << "--- parseRepeatAction: Repetitions: " << repetitions << ", Comment: " << ra->comment;
DEBUG_LOG(m_logger) << "--- parseRepeatAction End";
return ra;
}
Action *XmlReader::parseStandardAction(QXmlStreamReader &xml)
{
if (xml.tokenType() != QXmlStreamReader::StartElement ||
xml.name() != QStringLiteral("action"))
return {};
DEBUG_LOG(m_logger) << "--- parseStandardAction Start";
QXmlStreamAttributes attributes = xml.attributes();
if (!attributes.hasAttribute(QStringLiteral("type")))
return {};
Action *a = new Action();
// set explicitely, as Action itself is "unset"
a->aclass = AC_Standard;
a->atype = static_cast<ActionType>(attributes.value(QStringLiteral("type")).toInt());
if (attributes.hasAttribute(QStringLiteral("comment")))
a->comment = attributes.value(QStringLiteral("comment")).toString();
DEBUG_LOG(m_logger) << "--- parseStandardAction: Type: " << a->atype
<< ", Comment: " << a->comment;
DEBUG_LOG(m_logger) << "--- parseStandardAction End";
return a;
}
BsmAction *XmlReader::parseBsmAction(QXmlStreamReader &xml)
{
QXmlStreamAttributes attributes = xml.attributes();
DEBUG_LOG(m_logger) << "--- parseBsmAction Start";
BsmAction *a = new BsmAction();
a->atype = static_cast<ActionType>(attributes.value(QStringLiteral("type")).toInt());
if (attributes.hasAttribute(QStringLiteral("comment")))
a->comment = attributes.value(QStringLiteral("comment")).toString();
xml.readNext();
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
xml.name() == QStringLiteral("bsm")))
{
// What about count?
if (xml.name() == QStringLiteral("pause"))
a->pause = xml.readElementText().toInt();
if (xml.name() == QStringLiteral("choplength"))
a->choplength = xml.readElementText().toInt();
if (xml.name() == QStringLiteral("pulses"))
a->pulses = xml.readElementText().toInt();
if (xml.name() == QStringLiteral("pulseduration"))
a->pulseduration = xml.readElementText().toInt();
xml.readNext();
}
DEBUG_LOG(m_logger) << "--- parseBsmAction: Type: " << a->atype
<< ", Pause: " << a->pause
<< ", Choplength: " << a->choplength
<< ", Count: " << a->count
<< ", Pulses: " << a->pulses
<< ", Pulseduration: " << a->pulseduration
<< ", Comment: " << a->comment;
DEBUG_LOG(m_logger) << "--- parseBsmAction End";
return a;
}
void XmlReader::createHttpRequests()
{
for (const Effect *e : m_contents.constEffects())
{
for (const Range *r : e->constRanges())
{
generateUrls(e, r->actions);
}
}
}
QUrl XmlReader::createPreparedUrl(const XmlContents &contents, const QString &hostname)
{
QUrl url;
url.setScheme(QStringLiteral("http"));
url.setUserName(contents.username);
url.setPassword(contents.password);
if (!hostname.isEmpty())
url.setHost(hostname);
url.setPort(contents.port);
return url;
}
void XmlReader::generateUrl(const Effect *e, Action *a)
{
switch (a->aclass)
{
case AC_Standard:
{
QUrl url = createPreparedUrl(m_contents);
QUrlQuery query;
switch (e->effectType)
{
case ET_Relay:
{
url.setPath(QStringLiteral("/relay.php"));
query.addQueryItem(QStringLiteral("state"), QString::number(a->atype));
query.addQueryItem(QStringLiteral("number"), QString::number(e->id));
break;
}
case ET_BackgroundSound:
{
url.setPath(QStringLiteral("/bgsound.php"));
query.addQueryItem(QStringLiteral("category"), categoryName(e->category));
query.addQueryItem(QStringLiteral("sound"), QString::number(e->id));
query.addQueryItem(QStringLiteral("vol"), QString::number(m_contents.bgSoundVolume));
switch (a->atype)
{
case AT_Off:
query.addQueryItem(QStringLiteral("control"), QStringLiteral("2"));
break;
case AT_On:
query.addQueryItem(QStringLiteral("control"), QStringLiteral("1"));
break;
case AT_Infinite:
query.addQueryItem(QStringLiteral("control"), QStringLiteral("3"));
break;
case AT_Flash:
default:
break;
}
break;
}
default:
break;
}
url.setQuery(query);
a->url = url;
DEBUG_LOG(m_logger) << "Effect " << e->name << ", Action '" << a->comment << "' now has URL: " << url.toString();
break;
}
case AC_Repeat:
{
const RepeatAction *ra = static_cast<const RepeatAction *>(a);
generateUrls(e, ra->actions);
break;
}
case AC_Unset:
case AC_Pause:
case AC_Bsm:
default:
DEBUG_LOG(m_logger) << "Effect " << e->name << ", Action '" << a->comment << "' of Type " << a->aclass << " needs no URL";
break;
}
}
void XmlReader::generateUrls(const Effect *e, const QVector<Action *> &actions)
{
for (Action *a : actions)
generateUrl(e,a);
}
//QVector<Action *> Effect::getActionsByRange(int damagePercent) const
//{
// for (const Range *r : ranges)
// {
// if (r->fits(damagePercent))
// return r->actions;
// }
// return {};
//}
Range* Effect::getRangeByDamagePercent(int damagePercent) const
{
for (Range *r : ranges)
{
if (r->fits(damagePercent))
return r;
}
return nullptr;
}
QString XmlReader::categoryName(Category c)
{
switch (c)
{
case CT_BGS_Bahnhof:
return QStringLiteral("bahnhof");
case CT_BGS_Personen:
return QStringLiteral("personen");
case CT_BGS_Sonstige:
return QStringLiteral("sonstige");
case CT_BGS_Stadt:
return QStringLiteral("stadt");
case CT_BGS_Testsounds:
return QStringLiteral("testsounds");
case CT_BGS_Aircrafts:
return QStringLiteral("Aircrafts");
case CT_BGS_Battlefields:
return QStringLiteral("Battlefields");
case CT_BGS_Boats:
return QStringLiteral("Boats");
case CT_BGS_Explosions:
return QStringLiteral("Explosions");
case CT_BGS_Helicopter:
return QStringLiteral("Helicopter");
case CT_BGS_Motors_and_urban_traffic:
return QStringLiteral("Motors_and_urban_traffic");
case CT_BGS_InsideBuildings:
return QStringLiteral("Inside_buildings");
case CT_BGS_Vehicles:
return QStringLiteral("Vehicles");
case CT_Default:
default:
return QStringLiteral("Default");
break;
}
}
} // BuildingControlUnit