1 | /* |
2 | This file is part of the KDE libraries |
3 | |
4 | SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org> |
5 | SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org> |
6 | SPDX-FileCopyrightText: 2003 Zack Rusin <zack@kde.org> |
7 | SPDX-FileCopyrightText: 2006 Michaƫl Larouche <michael.larouche@kdemail.net> |
8 | SPDX-FileCopyrightText: 2008 Allen Winter <winter@kde.org> |
9 | SPDX-FileCopyrightText: 2020 Tomaz Cananbrava <tcanabrava@kde.org> |
10 | |
11 | SPDX-License-Identifier: LGPL-2.0-or-later |
12 | */ |
13 | |
14 | #include "KConfigXmlParser.h" |
15 | |
16 | #include <QDebug> |
17 | #include <QDomAttr> |
18 | #include <QDomElement> |
19 | #include <QDomNode> |
20 | #include <QFile> |
21 | #include <QList> |
22 | #include <QStringList> |
23 | #include <QTextStream> |
24 | #include <iostream> |
25 | // TODO: Move preprocessDefault to Header / CPP implementation. |
26 | // it makes no sense for a parser to process those values and generate code. |
27 | |
28 | static void preProcessDefault(QString &defaultValue, |
29 | const QString &name, |
30 | const QString &type, |
31 | const CfgEntry::Choices &cfgChoices, |
32 | QString &code, |
33 | const KConfigParameters &cfg) |
34 | { |
35 | if (type == QLatin1String("String" ) && !defaultValue.isEmpty()) { |
36 | defaultValue = literalString(s: defaultValue); |
37 | |
38 | } else if (type == QLatin1String("Path" ) && !defaultValue.isEmpty()) { |
39 | defaultValue = literalString(s: defaultValue); |
40 | } else if (type == QLatin1String("Url" ) && !defaultValue.isEmpty()) { |
41 | // Use fromUserInput in order to support absolute paths and absolute urls, like KDE4's KUrl(QString) did. |
42 | defaultValue = QLatin1String("QUrl::fromUserInput( %1)" ).arg(args: literalString(s: defaultValue)); |
43 | } else if ((type == QLatin1String("UrlList" ) || type == QLatin1String("StringList" ) || type == QLatin1String("PathList" )) && !defaultValue.isEmpty()) { |
44 | QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); |
45 | if (!code.isEmpty()) { |
46 | cpp << '\n'; |
47 | } |
48 | |
49 | if (type == QLatin1String("UrlList" )) { |
50 | cpp << " QList<QUrl> default" << name << ";\n" ; |
51 | } else { |
52 | cpp << " QStringList default" << name << ";\n" ; |
53 | } |
54 | const QStringList defaults = defaultValue.split(sep: QLatin1Char(',')); |
55 | for (const auto &val : defaults) { |
56 | cpp << " default" << name << ".append( " ; |
57 | if (type == QLatin1String("UrlList" )) { |
58 | cpp << "QUrl::fromUserInput(" ; |
59 | } |
60 | cpp << "QString::fromUtf8( \"" << val << "\" ) " ; |
61 | if (type == QLatin1String("UrlList" )) { |
62 | cpp << ") " ; |
63 | } |
64 | cpp << ");\n" ; |
65 | } |
66 | defaultValue = QLatin1String("default" ) + name; |
67 | |
68 | } else if (type == QLatin1String("Color" ) && !defaultValue.isEmpty()) { |
69 | static const QRegularExpression colorRe(QRegularExpression::anchoredPattern(QStringLiteral("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?" ))); |
70 | |
71 | if (colorRe.match(subject: defaultValue).hasMatch()) { |
72 | defaultValue = QLatin1String("QColor( %1 )" ).arg(args&: defaultValue); |
73 | } else { |
74 | defaultValue = QLatin1String("QColor( \"%1\" )" ).arg(args&: defaultValue); |
75 | } |
76 | |
77 | } else if (type == QLatin1String("Enum" )) { |
78 | for (const auto &choice : cfgChoices.choices) { |
79 | if (choice.name == defaultValue) { |
80 | if (cfg.globalEnums && cfgChoices.name().isEmpty()) { |
81 | defaultValue.prepend(s: cfgChoices.prefix); |
82 | } else { |
83 | defaultValue.prepend(s: enumTypeQualifier(n: name, c: cfgChoices) + cfgChoices.prefix); |
84 | } |
85 | break; |
86 | } |
87 | } |
88 | |
89 | } else if (type == QLatin1String("IntList" )) { |
90 | QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); |
91 | if (!code.isEmpty()) { |
92 | cpp << '\n'; |
93 | } |
94 | |
95 | cpp << " QList<int> default" << name << ";\n" ; |
96 | if (!defaultValue.isEmpty()) { |
97 | const QStringList defaults = defaultValue.split(sep: QLatin1Char(',')); |
98 | for (const auto &defaultVal : defaults) { |
99 | cpp << " default" << name << ".append( " << defaultVal << " );\n" ; |
100 | } |
101 | } |
102 | defaultValue = QLatin1String("default" ) + name; |
103 | } |
104 | } |
105 | |
106 | static QString dumpNode(const QDomNode &node) |
107 | { |
108 | QString msg; |
109 | QTextStream s(&msg, QIODevice::WriteOnly); |
110 | node.save(s, 0); |
111 | |
112 | msg = msg.simplified(); |
113 | if (msg.length() > 40) { |
114 | return msg.left(n: 37) + QLatin1String("..." ); |
115 | } |
116 | return msg; |
117 | } |
118 | |
119 | void KConfigXmlParser::readParameterFromEntry(CfgEntry &readEntry, const QDomElement &e) |
120 | { |
121 | readEntry.param = e.attribute(QStringLiteral("name" )); |
122 | readEntry.paramType = e.attribute(QStringLiteral("type" )); |
123 | |
124 | if (readEntry.param.isEmpty()) { |
125 | std::cerr << "Parameter must have a name: " << qPrintable(dumpNode(e)) << std::endl; |
126 | exit(status: 1); |
127 | } |
128 | |
129 | if (readEntry.paramType.isEmpty()) { |
130 | std::cerr << "Parameter must have a type: " << qPrintable(dumpNode(e)) << std::endl; |
131 | exit(status: 1); |
132 | } |
133 | |
134 | if ((readEntry.paramType == QLatin1String("Int" )) || (readEntry.paramType == QLatin1String("UInt" ))) { |
135 | bool ok; |
136 | readEntry.paramMax = e.attribute(QStringLiteral("max" )).toInt(ok: &ok); |
137 | if (!ok) { |
138 | std::cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): " << qPrintable(dumpNode(e)) << std::endl; |
139 | exit(status: 1); |
140 | } |
141 | } else if (readEntry.paramType == QLatin1String("Enum" )) { |
142 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { |
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(t: e3.text()); |
147 | } |
148 | } |
149 | break; |
150 | } |
151 | } |
152 | if (readEntry.paramValues.isEmpty()) { |
153 | std::cerr << "No values specified for parameter '" << qPrintable(readEntry.param) << "'." << std::endl; |
154 | exit(status: 1); |
155 | } |
156 | readEntry.paramMax = readEntry.paramValues.count() - 1; |
157 | } else { |
158 | std::cerr << "Parameter '" << qPrintable(readEntry.param) << "' has type " << qPrintable(readEntry.paramType) |
159 | << " but must be of type int, uint or Enum." << std::endl; |
160 | exit(status: 1); |
161 | } |
162 | } |
163 | |
164 | bool KConfigXmlParser::hasDefaultCode(CfgEntry &readEntry, const QDomElement &element) |
165 | { |
166 | Q_UNUSED(readEntry) |
167 | |
168 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { |
169 | if (e.attribute(QStringLiteral("param" )).isEmpty()) { |
170 | if (e.attribute(QStringLiteral("code" )) == QLatin1String("true" )) { |
171 | return true; |
172 | } |
173 | } |
174 | } |
175 | return false; |
176 | } |
177 | |
178 | void KConfigXmlParser::readChoicesFromEntry(CfgEntry &readEntry, const QDomElement &e) |
179 | { |
180 | QList<CfgEntry::Choice> chlist; |
181 | const auto choiceNameRegex = QRegularExpression(QStringLiteral("\\w+" )); |
182 | |
183 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { |
184 | if (e2.tagName() != QLatin1String("choice" )) { |
185 | continue; |
186 | } |
187 | CfgEntry::Choice choice; |
188 | choice.name = e2.attribute(QStringLiteral("name" )); |
189 | if (choice.name.isEmpty()) { |
190 | std::cerr << "Tag <choice> requires attribute 'name'." << std::endl; |
191 | } else if (!choiceNameRegex.match(subject: 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; |
194 | } |
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" )); |
200 | } |
201 | if (e3.tagName() == QLatin1String("tooltip" )) { |
202 | choice.toolTip = e3.text(); |
203 | choice.context = e3.attribute(QStringLiteral("context" )); |
204 | } |
205 | if (e3.tagName() == QLatin1String("whatsthis" )) { |
206 | choice.whatsThis = e3.text(); |
207 | choice.context = e3.attribute(QStringLiteral("context" )); |
208 | } |
209 | } |
210 | chlist.append(t: choice); |
211 | } |
212 | |
213 | QString name = e.attribute(QStringLiteral("name" )); |
214 | QString prefix = e.attribute(QStringLiteral("prefix" )); |
215 | |
216 | readEntry.choices = CfgEntry::Choices(chlist, name, prefix); |
217 | } |
218 | |
219 | void KConfigXmlParser::readGroupElements(CfgEntry &readEntry, const QDomElement &element) |
220 | { |
221 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { |
222 | QString tag = e.tagName(); |
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(); |
243 | } |
244 | } else if (tag == QLatin1String("choices" )) { |
245 | readChoicesFromEntry(readEntry, e); |
246 | } else if (tag == QLatin1String("emit" )) { |
247 | Signal signal; |
248 | signal.name = e.attribute(QStringLiteral("signal" )); |
249 | readEntry.signalList.append(t: signal); |
250 | } |
251 | } |
252 | } |
253 | |
254 | void KConfigXmlParser::createChangedSignal(CfgEntry &readEntry) |
255 | { |
256 | if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.contains(str: readEntry.name))) { |
257 | Signal s; |
258 | s.name = changeSignalName(n: readEntry.name); |
259 | s.modify = true; |
260 | readEntry.signalList.append(t: s); |
261 | } |
262 | } |
263 | |
264 | void KConfigXmlParser::validateNameAndKey(CfgEntry &readEntry, const QDomElement &element) |
265 | { |
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; |
269 | exit(status: 1); |
270 | } |
271 | |
272 | if (readEntry.key.isEmpty()) { |
273 | readEntry.key = readEntry.name; |
274 | } |
275 | |
276 | if (nameIsEmpty) { |
277 | readEntry.name = readEntry.key; |
278 | readEntry.name.remove(c: QLatin1Char(' ')); |
279 | } else if (readEntry.name.contains(c: QLatin1Char(' '))) { |
280 | std::cout << "Entry '" << qPrintable(readEntry.name) << "' contains spaces! <name> elements can not contain spaces!" << std::endl; |
281 | readEntry.name.remove(c: QLatin1Char(' ')); |
282 | } |
283 | |
284 | if (readEntry.name.contains(QStringLiteral("$(" ))) { |
285 | if (readEntry.param.isEmpty()) { |
286 | std::cerr << "Name may not be parameterized: " << qPrintable(readEntry.name) << std::endl; |
287 | exit(status: 1); |
288 | } |
289 | } else { |
290 | if (!readEntry.param.isEmpty()) { |
291 | std::cerr << "Name must contain '$(" << qPrintable(readEntry.param) << ")': " << qPrintable(readEntry.name) << std::endl; |
292 | exit(status: 1); |
293 | } |
294 | } |
295 | } |
296 | |
297 | void KConfigXmlParser::readParamDefaultValues(CfgEntry &readEntry, const QDomElement &element) |
298 | { |
299 | if (readEntry.param.isEmpty()) { |
300 | return; |
301 | } |
302 | // Adjust name |
303 | readEntry.paramName = readEntry.name; |
304 | |
305 | readEntry.name.remove(QStringLiteral("$(" ) + readEntry.param + QLatin1Char(')')); |
306 | // Lookup defaults for indexed entries |
307 | for (int i = 0; i <= readEntry.paramMax; i++) { |
308 | readEntry.paramDefaultValues.append(t: QString()); |
309 | } |
310 | |
311 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { |
312 | QString tag = e.tagName(); |
313 | if (tag != QLatin1String("default" )) { |
314 | continue; |
315 | } |
316 | QString index = e.attribute(QStringLiteral("param" )); |
317 | if (index.isEmpty()) { |
318 | continue; |
319 | } |
320 | |
321 | bool ok; |
322 | int i = index.toInt(ok: &ok); |
323 | if (!ok) { |
324 | i = readEntry.paramValues.indexOf(str: index); |
325 | if (i == -1) { |
326 | std::cerr << "Index '" << qPrintable(index) << "' for default value is unknown." << std::endl; |
327 | exit(status: 1); |
328 | } |
329 | } |
330 | |
331 | if ((i < 0) || (i > readEntry.paramMax)) { |
332 | std::cerr << "Index '" << i << "' for default value is out of range [0, " << readEntry.paramMax << "]." << std::endl; |
333 | exit(status: 1); |
334 | } |
335 | |
336 | QString tmpDefaultValue = e.text(); |
337 | |
338 | if (e.attribute(QStringLiteral("code" )) != QLatin1String("true" )) { |
339 | preProcessDefault(defaultValue&: tmpDefaultValue, name: readEntry.name, type: readEntry.type, cfgChoices: readEntry.choices, code&: readEntry.code, cfg); |
340 | } |
341 | |
342 | readEntry.paramDefaultValues[i] = tmpDefaultValue; |
343 | } |
344 | } |
345 | |
346 | CfgEntry *KConfigXmlParser::parseEntry(const QString &group, const QString &parentGroup, const QDomElement &element) |
347 | { |
348 | CfgEntry readEntry; |
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" ); |
353 | ; |
354 | readEntry.group = group; |
355 | readEntry.parentGroup = parentGroup; |
356 | |
357 | const bool nameIsEmpty = readEntry.name.isEmpty(); |
358 | |
359 | readGroupElements(readEntry, element); |
360 | |
361 | validateNameAndKey(readEntry, element); |
362 | |
363 | if (readEntry.label.isEmpty()) { |
364 | readEntry.label = readEntry.key; |
365 | } |
366 | |
367 | if (readEntry.type.isEmpty()) { |
368 | readEntry.type = QStringLiteral("String" ); // XXX : implicit type might be bad |
369 | } |
370 | |
371 | readParamDefaultValues(readEntry, element); |
372 | |
373 | if (!mValidNameRegexp.match(subject: readEntry.name).hasMatch()) { |
374 | if (nameIsEmpty) { |
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." |
378 | << std::endl; |
379 | } else { |
380 | std::cerr << "The name '" << qPrintable(readEntry.name) << "' is not a valid name for an entry." << std::endl; |
381 | } |
382 | exit(status: 1); |
383 | } |
384 | |
385 | if (mAllNames.contains(str: readEntry.name)) { |
386 | if (nameIsEmpty) { |
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." |
390 | << std::endl; |
391 | } else { |
392 | std::cerr << "The name '" << qPrintable(readEntry.name) << "' is not unique." << std::endl; |
393 | } |
394 | exit(status: 1); |
395 | } |
396 | |
397 | mAllNames.append(t: readEntry.name); |
398 | |
399 | if (!hasDefaultCode(readEntry, element)) { |
400 | // TODO: Move all the options to CfgEntry. |
401 | preProcessDefault(defaultValue&: readEntry.defaultValue, name: readEntry.name, type: readEntry.type, cfgChoices: readEntry.choices, code&: readEntry.code, cfg); |
402 | } |
403 | |
404 | // TODO: Try to Just return the CfgEntry we populated instead of |
405 | // creating another one to fill the code. |
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; |
423 | |
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; |
431 | } |
432 | result->min = readEntry.min; |
433 | result->max = readEntry.max; |
434 | createChangedSignal(readEntry&: *result); |
435 | |
436 | return result; |
437 | } |
438 | |
439 | // TODO: Change the name of the config variable. |
440 | KConfigXmlParser::KConfigXmlParser(const KConfigParameters &cfg, const QString &inputFileName) |
441 | : cfg(cfg) |
442 | , mInputFileName(inputFileName) |
443 | { |
444 | mValidNameRegexp.setPattern(QRegularExpression::anchoredPattern(QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*" ))); |
445 | } |
446 | |
447 | void KConfigXmlParser::start() |
448 | { |
449 | QFile input(mInputFileName); |
450 | if (!input.open(flags: QIODevice::ReadOnly)) { |
451 | qFatal(msg: "Could not open input file: %s" , qUtf8Printable(mInputFileName)); |
452 | } |
453 | QDomDocument doc; |
454 | const QDomDocument::ParseResult parseResult = doc.setContent(device: &input); |
455 | if (!parseResult) { |
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; |
459 | exit(status: 1); |
460 | } |
461 | |
462 | QDomElement cfgElement = doc.documentElement(); |
463 | if (cfgElement.isNull()) { |
464 | std::cerr << "No document in kcfg file" << std::endl; |
465 | exit(status: 1); |
466 | } |
467 | |
468 | for (QDomElement element = cfgElement.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) { |
469 | QString tag = element.tagName(); |
470 | |
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); |
479 | } |
480 | } |
481 | } |
482 | |
483 | ParseResult KConfigXmlParser::getParseResult() const |
484 | { |
485 | return mParseResult; |
486 | } |
487 | |
488 | void KConfigXmlParser::readIncludeTag(const QDomElement &e) |
489 | { |
490 | QString includeFile = e.text(); |
491 | if (!includeFile.isEmpty()) { |
492 | mParseResult.includes.append(t: includeFile); |
493 | } |
494 | } |
495 | |
496 | void KConfigXmlParser::readGroupTag(const QDomElement &e) |
497 | { |
498 | QString group = e.attribute(QStringLiteral("name" )); |
499 | if (group.isEmpty()) { |
500 | std::cerr << "Group without name" << std::endl; |
501 | exit(status: 1); |
502 | } |
503 | |
504 | const QString parentGroup = e.attribute(QStringLiteral("parentGroupName" )); |
505 | |
506 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { |
507 | if (e2.tagName() != QLatin1String("entry" )) { |
508 | continue; |
509 | } |
510 | CfgEntry *entry = parseEntry(group, parentGroup, element: e2); |
511 | if (entry) { |
512 | mParseResult.entries.append(t: entry); |
513 | } else { |
514 | std::cerr << "Can not parse entry." << std::endl; |
515 | exit(status: 1); |
516 | } |
517 | } |
518 | } |
519 | |
520 | void KConfigXmlParser::readKcfgfileTag(const QDomElement &e) |
521 | { |
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" ); |
525 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { |
526 | if (e2.tagName() == QLatin1String("parameter" )) { |
527 | Param p; |
528 | p.name = e2.attribute(QStringLiteral("name" )); |
529 | p.type = e2.attribute(QStringLiteral("type" )); |
530 | if (p.type.isEmpty()) { |
531 | p.type = QStringLiteral("String" ); |
532 | } |
533 | mParseResult.parameters.append(t: p); |
534 | } |
535 | } |
536 | } |
537 | |
538 | void KConfigXmlParser::readSignalTag(const QDomElement &e) |
539 | { |
540 | QString signalName = e.attribute(QStringLiteral("name" )); |
541 | if (signalName.isEmpty()) { |
542 | std::cerr << "Signal without name." << std::endl; |
543 | exit(status: 1); |
544 | } |
545 | Signal theSignal; |
546 | theSignal.name = signalName; |
547 | |
548 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { |
549 | if (e2.tagName() == QLatin1String("argument" )) { |
550 | Param argument; |
551 | argument.type = e2.attribute(QStringLiteral("type" )); |
552 | if (argument.type.isEmpty()) { |
553 | std::cerr << "Signal argument without type." << std::endl; |
554 | exit(status: 1); |
555 | } |
556 | argument.name = e2.text(); |
557 | theSignal.arguments.append(t: argument); |
558 | } else if (e2.tagName() == QLatin1String("label" )) { |
559 | theSignal.label = e2.text(); |
560 | } |
561 | } |
562 | |
563 | mParseResult.signalList.append(t: theSignal); |
564 | } |
565 | |