479 lines
14 KiB
C++
Executable File
479 lines
14 KiB
C++
Executable File
/**
|
|
* @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
|