14#include "KConfigXmlParser.h"
28static void preProcessDefault(
QString &defaultValue,
31 const CfgEntry::Choices &cfgChoices,
35 if (type ==
QLatin1String(
"String") && !defaultValue.isEmpty()) {
36 defaultValue = literalString(defaultValue);
38 }
else if (type ==
QLatin1String(
"Path") && !defaultValue.isEmpty()) {
39 defaultValue = literalString(defaultValue);
40 }
else if (type ==
QLatin1String(
"Url") && !defaultValue.isEmpty()) {
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 <<
"\" ) ";
68 }
else if (type ==
QLatin1String(
"Color") && !defaultValue.isEmpty()) {
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";
96 if (!defaultValue.isEmpty()) {
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;
134 if ((readEntry.paramType == QLatin1String(
"Int")) || (readEntry.paramType == QLatin1String(
"UInt"))) {
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;
141 }
else if (readEntry.paramType == QLatin1String(
"Enum")) {
143 if (e2.tagName() == QLatin1String(
"values")) {
144 for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) {
145 if (e3.tagName() == QLatin1String(
"value")) {
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()) {
170 if (e.
attribute(QStringLiteral(
"code")) == QLatin1String(
"true")) {
178void KConfigXmlParser::readChoicesFromEntry(CfgEntry &readEntry,
const QDomElement &e)
180 QList<CfgEntry::Choice> chlist;
181 const auto choiceNameRegex = QRegularExpression(QStringLiteral(
"\\w+"));
184 if (e2.tagName() != QLatin1String(
"choice")) {
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"));
196 for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) {
197 if (e3.tagName() == QLatin1String(
"label")) {
198 choice.label = e3.text();
199 choice.context = e3.attribute(QStringLiteral(
"context"));
201 if (e3.tagName() == QLatin1String(
"tooltip")) {
202 choice.toolTip = e3.text();
203 choice.context = e3.attribute(QStringLiteral(
"context"));
205 if (e3.tagName() == QLatin1String(
"whatsthis")) {
206 choice.whatsThis = e3.text();
207 choice.context = e3.attribute(QStringLiteral(
"context"));
214 QString prefix = e.
attribute(QStringLiteral(
"prefix"));
216 readEntry.choices = CfgEntry::Choices(chlist, name, prefix);
219void KConfigXmlParser::readGroupElements(CfgEntry &readEntry,
const QDomElement &element)
223 if (tag == QLatin1String(
"label")) {
224 readEntry.label = e.
text();
225 readEntry.labelContext = e.
attribute(QStringLiteral(
"context"));
226 }
else if (tag == QLatin1String(
"tooltip")) {
227 readEntry.toolTip = e.
text();
228 readEntry.toolTipContext = e.
attribute(QStringLiteral(
"context"));
229 }
else if (tag == QLatin1String(
"whatsthis")) {
230 readEntry.whatsThis = e.
text();
231 readEntry.whatsThisContext = e.
attribute(QStringLiteral(
"context"));
232 }
else if (tag == QLatin1String(
"min")) {
233 readEntry.min = e.
text();
234 }
else if (tag == QLatin1String(
"max")) {
235 readEntry.max = e.
text();
236 }
else if (tag == QLatin1String(
"code")) {
237 readEntry.code = e.
text();
238 }
else if (tag == QLatin1String(
"parameter")) {
239 readParameterFromEntry(readEntry, e);
240 }
else if (tag == QLatin1String(
"default")) {
241 if (e.
attribute(QStringLiteral(
"param")).isEmpty()) {
242 readEntry.defaultValue = e.
text();
244 }
else if (tag == QLatin1String(
"choices")) {
245 readChoicesFromEntry(readEntry, e);
246 }
else if (tag == QLatin1String(
"emit")) {
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;
278 readEntry.name.
remove(QLatin1Char(
' '));
279 }
else if (readEntry.name.
contains(QLatin1Char(
' '))) {
280 std::cout <<
"Entry '" << qPrintable(readEntry.name) <<
"' contains spaces! <name> elements can not contain spaces!" << std::endl;
281 readEntry.name.
remove(QLatin1Char(
' '));
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++) {
308 readEntry.paramDefaultValues.
append(QString());
313 if (tag != QLatin1String(
"default")) {
316 QString index = e.
attribute(QStringLiteral(
"param"));
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;
336 QString tmpDefaultValue = e.
text();
338 if (e.
attribute(QStringLiteral(
"code")) != QLatin1String(
"true")) {
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"));
352 readEntry.hidden = element.
attribute(QStringLiteral(
"hidden")) == QLatin1String(
"true");
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);
373 if (!mValidNameRegexp.match(readEntry.name).hasMatch()) {
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));
454 const QDomDocument::ParseResult parseResult = doc.
setContent(&input);
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;
469 QString tag = element.
tagName();
471 if (tag == QLatin1String(
"include")) {
472 readIncludeTag(element);
473 }
else if (tag == QLatin1String(
"kcfgfile")) {
474 readKcfgfileTag(element);
475 }
else if (tag == QLatin1String(
"group")) {
476 readGroupTag(element);
477 }
else if (tag == QLatin1String(
"signal")) {
478 readSignalTag(element);
483ParseResult KConfigXmlParser::getParseResult()
const
488void KConfigXmlParser::readIncludeTag(
const QDomElement &e)
490 QString includeFile = e.
text();
492 mParseResult.includes.append(includeFile);
496void KConfigXmlParser::readGroupTag(
const QDomElement &e)
498 QString group = e.
attribute(QStringLiteral(
"name"));
500 std::cerr <<
"Group without name" << std::endl;
504 const QString parentGroup = e.
attribute(QStringLiteral(
"parentGroupName"));
507 if (e2.tagName() != QLatin1String(
"entry")) {
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"));
523 mParseResult.cfgStateConfig = e.
attribute(QStringLiteral(
"stateConfig")).
toLower() == QLatin1String(
"true");
524 mParseResult.cfgFileNameArg = e.
attribute(QStringLiteral(
"arg")).
toLower() == QLatin1String(
"true");
526 if (e2.tagName() == QLatin1String(
"parameter")) {
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)
540 QString signalName = e.
attribute(QStringLiteral(
"name"));
542 std::cerr <<
"Signal without name." << std::endl;
546 theSignal.name = signalName;
549 if (e2.tagName() == QLatin1String(
"argument")) {
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);
558 }
else if (e2.tagName() == QLatin1String(
"label")) {
559 theSignal.label = e2.text();
563 mParseResult.signalList.
append(theSignal);
Configuration Compiler Configuration.
QString name(StandardAction 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
QString anchoredPattern(QStringView expression)
QString & append(QChar ch)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString simplified() const const
int toInt(bool *ok, int base) const const
QString toLower() const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const