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