14#include "KConfigXmlParser.h"
28static void preProcessDefault(
QString &defaultValue,
31 const CfgEntry::Choices &cfgChoices,
36 defaultValue = literalString(defaultValue);
39 defaultValue = literalString(defaultValue);
42 defaultValue =
QLatin1String(
"QUrl::fromUserInput( %1)").arg(literalString(defaultValue));
50 cpp <<
" QList<QUrl> default" <<
name <<
";\n";
52 cpp <<
" QStringList default" <<
name <<
";\n";
55 for (
const auto &val : defaults) {
56 cpp <<
" default" <<
name <<
".append( ";
58 cpp <<
"QUrl::fromUserInput(";
60 cpp <<
"QString::fromUtf8( \"" << val <<
"\" ) ";
71 if (colorRe.match(defaultValue).hasMatch()) {
72 defaultValue =
QLatin1String(
"QColor( %1 )").arg(defaultValue);
74 defaultValue =
QLatin1String(
"QColor( \"%1\" )").arg(defaultValue);
78 for (
const auto &choice : cfgChoices.choices) {
79 if (choice.name == defaultValue) {
80 if (cfg.globalEnums && cfgChoices.name().
isEmpty()) {
81 defaultValue.
prepend(cfgChoices.prefix);
83 defaultValue.
prepend(enumTypeQualifier(name, cfgChoices) + cfgChoices.prefix);
95 cpp <<
" QList<int> default" <<
name <<
";\n";
98 for (
const auto &defaultVal : defaults) {
99 cpp <<
" default" <<
name <<
".append( " << defaultVal <<
" );\n";
119void KConfigXmlParser::readParameterFromEntry(CfgEntry &readEntry,
const QDomElement &e)
121 readEntry.param = e.
attribute(QStringLiteral(
"name"));
122 readEntry.paramType = e.
attribute(QStringLiteral(
"type"));
124 if (readEntry.param.
isEmpty()) {
125 std::cerr <<
"Parameter must have a name: " << qPrintable(dumpNode(e)) << std::endl;
129 if (readEntry.paramType.
isEmpty()) {
130 std::cerr <<
"Parameter must have a type: " << qPrintable(dumpNode(e)) << std::endl;
136 readEntry.paramMax = e.
attribute(QStringLiteral(
"max")).
toInt(&ok);
138 std::cerr <<
"Integer parameter must have a maximum (e.g. max=\"0\"): " << qPrintable(dumpNode(e)) << std::endl;
146 readEntry.paramValues.
append(e3.text());
152 if (readEntry.paramValues.
isEmpty()) {
153 std::cerr <<
"No values specified for parameter '" << qPrintable(readEntry.param) <<
"'." << std::endl;
156 readEntry.paramMax = readEntry.paramValues.
count() - 1;
158 std::cerr <<
"Parameter '" << qPrintable(readEntry.param) <<
"' has type " << qPrintable(readEntry.paramType)
159 <<
" but must be of type int, uint or Enum." << std::endl;
164bool KConfigXmlParser::hasDefaultCode(CfgEntry &readEntry,
const QDomElement &element)
169 if (e.
attribute(QStringLiteral(
"param")).isEmpty()) {
178void KConfigXmlParser::readChoicesFromEntry(CfgEntry &readEntry,
const QDomElement &e)
187 CfgEntry::Choice choice;
188 choice.name = e2.attribute(QStringLiteral(
"name"));
190 std::cerr <<
"Tag <choice> requires attribute 'name'." << std::endl;
191 }
else if (!choiceNameRegex.match(choice.name).hasMatch()) {
192 std::cerr <<
"Tag <choice> attribute 'name' must be compatible with Enum naming. name was '" << qPrintable(choice.name)
193 <<
"'. You can use attribute 'value' to pass any string as the choice value." << std::endl;
195 choice.val = e2.attribute(QStringLiteral(
"value"));
198 choice.label = e3.text();
199 choice.context = e3.attribute(QStringLiteral(
"context"));
202 choice.toolTip = e3.text();
203 choice.context = e3.attribute(QStringLiteral(
"context"));
206 choice.whatsThis = e3.text();
207 choice.context = e3.attribute(QStringLiteral(
"context"));
216 readEntry.choices = CfgEntry::Choices(chlist, name, prefix);
219void KConfigXmlParser::readGroupElements(CfgEntry &readEntry,
const QDomElement &element)
224 readEntry.label = e.
text();
225 readEntry.labelContext = e.
attribute(QStringLiteral(
"context"));
227 readEntry.toolTip = e.
text();
228 readEntry.toolTipContext = e.
attribute(QStringLiteral(
"context"));
230 readEntry.whatsThis = e.
text();
231 readEntry.whatsThisContext = e.
attribute(QStringLiteral(
"context"));
233 readEntry.min = e.
text();
235 readEntry.max = e.
text();
237 readEntry.code = e.
text();
239 readParameterFromEntry(readEntry, e);
241 if (e.
attribute(QStringLiteral(
"param")).isEmpty()) {
242 readEntry.defaultValue = e.
text();
245 readChoicesFromEntry(readEntry, e);
248 signal.name = e.
attribute(QStringLiteral(
"signal"));
249 readEntry.signalList.
append(signal);
254void KConfigXmlParser::createChangedSignal(CfgEntry &readEntry)
256 if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.
contains(readEntry.name))) {
258 s.name = changeSignalName(readEntry.name);
260 readEntry.signalList.
append(s);
264void KConfigXmlParser::validateNameAndKey(CfgEntry &readEntry,
const QDomElement &element)
266 bool nameIsEmpty = readEntry.name.
isEmpty();
267 if (nameIsEmpty && readEntry.key.
isEmpty()) {
268 std::cerr <<
"Entry must have a name or a key: " << qPrintable(dumpNode(element)) << std::endl;
273 readEntry.key = readEntry.name;
277 readEntry.name = readEntry.key;
280 std::cout <<
"Entry '" << qPrintable(readEntry.name) <<
"' contains spaces! <name> elements can not contain spaces!" << std::endl;
284 if (readEntry.name.
contains(QStringLiteral(
"$("))) {
285 if (readEntry.param.
isEmpty()) {
286 std::cerr <<
"Name may not be parameterized: " << qPrintable(readEntry.name) << std::endl;
290 if (!readEntry.param.
isEmpty()) {
291 std::cerr <<
"Name must contain '$(" << qPrintable(readEntry.param) <<
")': " << qPrintable(readEntry.name) << std::endl;
297void KConfigXmlParser::readParamDefaultValues(CfgEntry &readEntry,
const QDomElement &element)
299 if (readEntry.param.
isEmpty()) {
303 readEntry.paramName = readEntry.name;
305 readEntry.name.
remove(QStringLiteral(
"$(") + readEntry.param +
QLatin1Char(
')'));
307 for (
int i = 0; i <= readEntry.paramMax; i++) {
322 int i = index.
toInt(&ok);
324 i = readEntry.paramValues.
indexOf(index);
326 std::cerr <<
"Index '" << qPrintable(index) <<
"' for default value is unknown." << std::endl;
331 if ((i < 0) || (i > readEntry.paramMax)) {
332 std::cerr <<
"Index '" << i <<
"' for default value is out of range [0, " << readEntry.paramMax <<
"]." << std::endl;
339 preProcessDefault(tmpDefaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg);
342 readEntry.paramDefaultValues[i] = tmpDefaultValue;
349 readEntry.type = element.
attribute(QStringLiteral(
"type"));
350 readEntry.name = element.
attribute(QStringLiteral(
"name"));
351 readEntry.key = element.
attribute(QStringLiteral(
"key"));
354 readEntry.group = group;
355 readEntry.parentGroup = parentGroup;
357 const bool nameIsEmpty = readEntry.name.
isEmpty();
359 readGroupElements(readEntry, element);
361 validateNameAndKey(readEntry, element);
363 if (readEntry.label.
isEmpty()) {
364 readEntry.label = readEntry.key;
367 if (readEntry.type.
isEmpty()) {
368 readEntry.type = QStringLiteral(
"String");
371 readParamDefaultValues(readEntry, element);
375 std::cerr <<
"The key '" << qPrintable(readEntry.key)
376 <<
"' can not be used as name for the entry because "
377 "it is not a valid name. You need to specify a valid name for this entry."
380 std::cerr <<
"The name '" << qPrintable(readEntry.name) <<
"' is not a valid name for an entry." << std::endl;
385 if (mAllNames.
contains(readEntry.name)) {
387 std::cerr <<
"The key '" << qPrintable(readEntry.key)
388 <<
"' can not be used as name for the entry because "
389 "it does not result in a unique name. You need to specify a unique name for this entry."
392 std::cerr <<
"The name '" << qPrintable(readEntry.name) <<
"' is not unique." << std::endl;
397 mAllNames.
append(readEntry.name);
399 if (!hasDefaultCode(readEntry, element)) {
401 preProcessDefault(readEntry.defaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg);
406 CfgEntry *result =
new CfgEntry();
407 result->group = readEntry.group;
408 result->parentGroup = readEntry.parentGroup;
409 result->type = readEntry.type;
410 result->key = readEntry.key;
411 result->name = readEntry.name;
412 result->labelContext = readEntry.labelContext;
413 result->label = readEntry.label;
414 result->toolTipContext = readEntry.toolTipContext;
415 result->toolTip = readEntry.toolTip;
416 result->whatsThisContext = readEntry.whatsThisContext;
417 result->whatsThis = readEntry.whatsThis;
418 result->code = readEntry.code;
419 result->defaultValue = readEntry.defaultValue;
420 result->choices = readEntry.choices;
421 result->signalList = readEntry.signalList;
422 result->hidden = readEntry.hidden;
424 if (!readEntry.param.
isEmpty()) {
425 result->param = readEntry.param;
426 result->paramName = readEntry.paramName;
427 result->paramType = readEntry.paramType;
428 result->paramValues = readEntry.paramValues;
429 result->paramDefaultValues = readEntry.paramDefaultValues;
430 result->paramMax = readEntry.paramMax;
432 result->min = readEntry.min;
433 result->max = readEntry.max;
434 createChangedSignal(*result);
442 , mInputFileName(inputFileName)
447void KConfigXmlParser::start()
449 QFile input(mInputFileName);
451 qFatal(
"Could not open input file: %s", qUtf8Printable(mInputFileName));
456 std::cerr <<
"Unable to load document." << std::endl;
457 std::cerr <<
"Parse error in " << qPrintable(mInputFileName) <<
", line " << parseResult.errorLine <<
", col " << parseResult.errorColumn <<
": "
458 << qPrintable(parseResult.errorMessage) << std::endl;
463 if (cfgElement.
isNull()) {
464 std::cerr <<
"No document in kcfg file" << std::endl;
472 readIncludeTag(element);
474 readKcfgfileTag(element);
476 readGroupTag(element);
478 readSignalTag(element);
483ParseResult KConfigXmlParser::getParseResult()
const
488void KConfigXmlParser::readIncludeTag(
const QDomElement &e)
492 mParseResult.includes.
append(includeFile);
496void KConfigXmlParser::readGroupTag(
const QDomElement &e)
500 std::cerr <<
"Group without name" << std::endl;
510 CfgEntry *entry = parseEntry(group, parentGroup, e2);
512 mParseResult.entries.
append(entry);
514 std::cerr <<
"Can not parse entry." << std::endl;
520void KConfigXmlParser::readKcfgfileTag(
const QDomElement &e)
522 mParseResult.cfgFileName = e.
attribute(QStringLiteral(
"name"));
528 p.name = e2.attribute(QStringLiteral(
"name"));
529 p.type = e2.attribute(QStringLiteral(
"type"));
531 p.type = QStringLiteral(
"String");
533 mParseResult.parameters.
append(p);
538void KConfigXmlParser::readSignalTag(
const QDomElement &e)
542 std::cerr <<
"Signal without name." << std::endl;
546 theSignal.name = signalName;
551 argument.type = e2.attribute(QStringLiteral(
"type"));
553 std::cerr <<
"Signal argument without type." << std::endl;
556 argument.name = e2.text();
557 theSignal.arguments.
append(argument);
559 theSignal.label = e2.text();
563 mParseResult.signalList.
append(theSignal);
Configuration Compiler Configuration.
QString name(GameStandardAction id)
QDomElement documentElement() const const
ParseResult setContent(QAnyStringView text, ParseOptions options)
QString attribute(const QString &name, const QString &defValue) const const
QString tagName() const const
QString text() const const
QDomElement firstChildElement(const QString &tagName, const QString &namespaceURI) const const
bool isNull() const const
QDomElement nextSiblingElement(const QString &tagName, const QString &namespaceURI) const const
void save(QTextStream &stream, int indent, EncodingPolicy encodingPolicy) const const
void append(QList< T > &&value)
qsizetype count() const const
bool isEmpty() const const
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
QString anchoredPattern(QStringView expression)
bool hasMatch() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString & prepend(QChar ch)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString simplified() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QString toLower() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const