KConfig

KConfigSourceGenerator.cpp
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 "KConfigSourceGenerator.h"
15
16#include <QRegularExpression>
17
18KConfigSourceGenerator::KConfigSourceGenerator(const QString &inputFile, const QString &baseDir, const KConfigParameters &cfg, ParseResult &parseResult)
19 : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1String(".cpp"), cfg, parseResult)
20{
21}
22
23void KConfigSourceGenerator::start()
24{
25 KConfigCodeGeneratorBase::start();
26 stream() << '\n';
27 createHeaders();
28
29 if (!cfg().nameSpace.isEmpty()) {
30 stream() << "using namespace " << cfg().nameSpace << ";";
31 stream() << "\n\n";
32 }
33
34 createPrivateDPointerImplementation();
35 createSingletonImplementation();
36 createPreamble();
37 doConstructor();
38 doGetterSetterDPointerMode();
39 createDefaultValueGetterSetter();
40 createDestructor();
41 createNonModifyingSignalsHelper();
42 createSignalFlagsHandler();
43}
44
45void KConfigSourceGenerator::createHeaders()
46{
47 QString headerName = cfg().baseName + QLatin1Char('.') + cfg().headerExtension;
48
49 // TODO: Make addQuotes return a string instead of replacing it inplace.
50 addQuotes(headerName);
51
52 addHeaders({headerName});
53 stream() << '\n';
54
55 addHeaders(cfg().sourceIncludes);
56 if (cfg().setUserTexts && cfg().translationSystem == KConfigParameters::KdeTranslation) {
57 addHeaders({QStringLiteral("klocalizedstring.h")});
58 stream() << '\n';
59 }
60
61 // Header required by singleton implementation
62 if (cfg().singleton) {
63 addHeaders({QStringLiteral("qglobal.h"), QStringLiteral("QFile")});
64
65 // HACK: Add single line to fix test.
66 if (cfg().singleton && parseResult.cfgFileNameArg) {
67 stream() << '\n';
68 }
69 }
70
71 if (cfg().singleton && parseResult.cfgFileNameArg) {
72 addHeaders({QStringLiteral("QDebug")});
73 }
74
75 if (cfg().dpointer && parseResult.hasNonModifySignals) {
76 addHeaders({QStringLiteral("QSet")});
77 }
78
79 if (cfg().qmlRegistration && cfg().singleton) {
80 addHeaders({QStringLiteral("QQmlEngine")});
81 }
82
83 if (cfg().singleton) {
84 stream() << '\n';
85 }
86}
87
88void KConfigSourceGenerator::createPrivateDPointerImplementation()
89{
90 // private class implementation
91 if (!cfg().dpointer) {
92 return;
93 }
94
95 QString group;
96 beginNamespaces();
97 stream() << "class " << cfg().className << "Private\n";
98 stream() << "{\n";
99 stream() << " public:\n";
100
101 // Create Members
102 for (const auto *entry : std::as_const(parseResult.entries)) {
103 if (entry->group != group) {
104 group = entry->group;
105 stream() << '\n';
106 stream() << " // " << group << '\n';
107 }
108 stream() << " " << cppType(entry->type) << " " << varName(entry->name, cfg());
109 if (!entry->param.isEmpty()) {
110 stream() << QStringLiteral("[%1]").arg(entry->paramMax + 1);
111 }
112 stream() << ";\n";
113 }
114 stream() << "\n // items\n";
115
116 // Create Items.
117 for (const auto *entry : std::as_const(parseResult.entries)) {
118 const QString declType = entry->signalList.isEmpty() ? QString(cfg().inherits + QStringLiteral("::Item") + itemType(entry->type))
119 : QStringLiteral("KConfigCompilerSignallingItem");
120
121 stream() << " " << declType << " *" << itemVar(entry, cfg());
122 if (!entry->param.isEmpty()) {
123 stream() << QStringLiteral("[%1]").arg(entry->paramMax + 1);
124 }
125 stream() << ";\n";
126 }
127
128 if (parseResult.hasNonModifySignals) {
129 stream() << " QSet<quint64> " << varName(QStringLiteral("settingsChanged"), cfg()) << ";\n";
130 }
131
132 stream() << "};\n\n";
133 endNamespaces();
134}
135
136void KConfigSourceGenerator::createSingletonImplementation()
137{
138 // Singleton implementation
139 if (!cfg().singleton) {
140 return;
141 }
142
143 beginNamespaces();
144 stream() << "class " << cfg().className << "Helper\n";
145 stream() << '{' << '\n';
146 stream() << " public:\n";
147 stream() << " " << cfg().className << "Helper() : q(nullptr) {}\n";
148 stream() << " ~" << cfg().className << "Helper() { delete q; q = nullptr; }\n";
149 stream() << " " << cfg().className << "Helper(const " << cfg().className << "Helper&) = delete;\n";
150 stream() << " " << cfg().className << "Helper& operator=(const " << cfg().className << "Helper&) = delete;\n";
151 stream() << " " << cfg().className << " *q;\n";
152 stream() << "};\n";
153 endNamespaces();
154
155 stream() << "Q_GLOBAL_STATIC(" << cfg().className << "Helper, s_global" << cfg().className << ")\n";
156
157 stream() << cfg().className << " *" << cfg().className << "::self()\n";
158 stream() << "{\n";
159 if (parseResult.cfgFileNameArg) {
160 stream() << " if (!s_global" << cfg().className << "()->q)\n";
161 stream() << " qFatal(\"you need to call " << cfg().className << "::instance before using\");\n";
162 } else {
163 stream() << " if (!s_global" << cfg().className << "()->q) {\n";
164 stream() << " new " << cfg().className << ';' << '\n';
165 stream() << " s_global" << cfg().className << "()->q->read();\n";
166 stream() << " }\n\n";
167 }
168 stream() << " return s_global" << cfg().className << "()->q;\n";
169 stream() << "}\n\n";
170
171 if (cfg().qmlRegistration && cfg().singleton) {
172 stream() << cfg().className << " *" << cfg().className << "::create(QQmlEngine *, QJSEngine *)\n";
173 stream() << "{\n";
174 stream() << " QQmlEngine::setObjectOwnership(self(), QQmlEngine::CppOwnership);\n";
175 stream() << " return self();\n";
176 stream() << "}\n\n";
177 }
178
179 if (parseResult.cfgFileNameArg) {
180 auto instance = [this](const QString &type, const QString &arg, bool isString) {
181 stream() << "void " << cfg().className << "::instance(" << type << " " << arg << ")\n";
182 stream() << "{\n";
183 stream() << " if (s_global" << cfg().className << "()->q) {\n";
184 stream() << " qDebug() << \"" << cfg().className << "::instance called after the first use - ignoring\";\n";
185 stream() << " return;\n";
186 stream() << " }\n";
187 stream() << " new " << cfg().className << "(";
188 if (parseResult.cfgStateConfig) {
189 stream() << "KSharedConfig::openStateConfig(" << arg << ")";
190 } else if (isString) {
191 stream() << "KSharedConfig::openConfig(" << arg << ")";
192 } else {
193 stream() << "std::move(" << arg << ")";
194 }
195 stream() << ");\n";
196 stream() << " s_global" << cfg().className << "()->q->read();\n";
197 stream() << "}\n\n";
198 };
199 instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true);
200 instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false);
201 }
202}
203
204void KConfigSourceGenerator::createPreamble()
205{
206 QString cppPreamble;
207 for (const auto *entry : std::as_const(parseResult.entries)) {
208 if (entry->paramValues.isEmpty()) {
209 continue;
210 }
211
212 cppPreamble += QStringLiteral("const char* const ") + cfg().className + QStringLiteral("::") + enumName(entry->param);
213 cppPreamble += cfg().globalEnums
214 ? QStringLiteral("ToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n")
215 : QStringLiteral("::enumToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n");
216 }
217
218 if (!cppPreamble.isEmpty()) {
219 stream() << cppPreamble << '\n';
220 }
221}
222
223void KConfigSourceGenerator::createConstructorParameterList()
224{
225 if (parseResult.cfgFileNameArg) {
226 if (!cfg().forceStringFilename) {
227 stream() << " KSharedConfig::Ptr config";
228 } else {
229 stream() << " const QString& config";
230 }
231 stream() << (parseResult.parameters.isEmpty() ? "" : ",");
232 }
233
234 for (auto it = parseResult.parameters.cbegin(); it != parseResult.parameters.cend(); ++it) {
235 if (it != parseResult.parameters.cbegin()) {
236 stream() << ",";
237 }
238 stream() << " " << param((*it).type) << " " << (*it).name;
239 }
240
241 if (cfg().parentInConstructor) {
242 if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) {
243 stream() << ",";
244 }
245 stream() << " QObject *parent";
246 }
247}
248
249void KConfigSourceGenerator::createParentConstructorCall()
250{
251 stream() << cfg().inherits << "(";
252 if (parseResult.cfgStateConfig) {
253 stream() << " KSharedConfig::openStateConfig(QStringLiteral( \"" << parseResult.cfgFileName << "\") ";
254 } else if (!parseResult.cfgFileName.isEmpty()) {
255 stream() << " QStringLiteral( \"" << parseResult.cfgFileName << "\" ";
256 }
257 if (parseResult.cfgFileNameArg) {
258 if (!cfg().forceStringFilename) {
259 stream() << " std::move( config ) ";
260 } else {
261 stream() << " config ";
262 }
263 }
264 if (!parseResult.cfgFileName.isEmpty()) {
265 stream() << ") ";
266 }
267 stream() << ")\n";
268}
269
270void KConfigSourceGenerator::createInitializerList()
271{
272 for (const auto &parameter : std::as_const(parseResult.parameters)) {
273 stream() << " , mParam" << parameter.name << "(" << parameter.name << ")\n";
274 }
275}
276
277void KConfigSourceGenerator::createEnums(const CfgEntry *entry)
278{
279 if (entry->type != QLatin1String("Enum")) {
280 return;
281 }
282 stream() << " QList<" << cfg().inherits << "::ItemEnum::Choice> values" << entry->name << ";\n";
283
284 for (const auto &choice : std::as_const(entry->choices.choices)) {
285 stream() << " {\n";
286 stream() << " " << cfg().inherits << "::ItemEnum::Choice choice;\n";
287 stream() << " choice.name = QStringLiteral(\"" << choice.name << "\");\n";
288 if (cfg().setUserTexts) {
289 if (!choice.label.isEmpty()) {
290 stream() << " choice.label = " << translatedString(cfg(), choice.label, choice.context) << ";\n";
291 }
292 if (!choice.toolTip.isEmpty()) {
293 stream() << " choice.toolTip = " << translatedString(cfg(), choice.toolTip, choice.context) << ";\n";
294 }
295 if (!choice.whatsThis.isEmpty()) {
296 stream() << " choice.whatsThis = " << translatedString(cfg(), choice.whatsThis, choice.context) << ";\n";
297 }
298 }
299 stream() << " values" << entry->name << ".append( choice );\n";
300 stream() << " }\n";
301 }
302}
303
304void KConfigSourceGenerator::createNormalEntry(const CfgEntry *entry, const QString &key)
305{
306 const QString itemVarStr = itemPath(entry, cfg());
307 const QString innerItemVarStr = innerItemVar(entry, cfg());
308 if (!entry->signalList.isEmpty()) {
309 stream() << " " << innerItemVarStr << " = " << newInnerItem(entry, key, entry->defaultValue, cfg()) << '\n';
310 }
311
312 stream() << " " << itemVarStr << " = " << newItem(entry, key, entry->defaultValue, cfg()) << '\n';
313
314 if (!entry->min.isEmpty()) {
315 stream() << " " << innerItemVarStr << "->setMinValue(" << entry->min << ");\n";
316 }
317
318 if (!entry->max.isEmpty()) {
319 stream() << " " << innerItemVarStr << "->setMaxValue(" << entry->max << ");\n";
320 }
321
322 if (cfg().setUserTexts) {
323 stream() << userTextsFunctions(entry, cfg());
324 }
325
326 if (cfg().allNotifiers || cfg().notifiers.contains(entry->name)) {
327 stream() << " " << itemVarStr << "->setWriteFlags(KConfigBase::Notify);\n";
328 }
329
330 for (const CfgEntry::Choice &choice : std::as_const(entry->choices.choices)) {
331 if (!choice.val.isEmpty()) {
332 stream() << " " << innerItemVarStr << "->setValueForChoice(QStringLiteral( \"" << choice.name << "\" ), QStringLiteral( \"" << choice.val
333 << "\" ));\n";
334 }
335 }
336
337 if (!entry->parentGroup.isEmpty()) {
338 stream() << " " << itemVarStr << "->setGroup(cg" << QString(entry->group).remove(QRegularExpression(QStringLiteral("\\W"))) << ");\n";
339 }
340
341 stream() << " addItem( " << itemVarStr;
342 QString quotedName = entry->name;
343 addQuotes(quotedName);
344 if (quotedName != key) {
345 stream() << ", QStringLiteral( \"" << entry->name << "\" )";
346 }
347 stream() << " );\n";
348}
349
350// TODO : Some compiler option won't work or generate bogus settings file.
351// * Does not manage properly Notifiers=true kcfgc option for parameterized entries :
352// ** KConfigCompilerSignallingItem generated with wrong userData parameter (4th one).
353// ** setWriteFlags() is missing.
354// * Q_PROPERTY signal won't work
355void KConfigSourceGenerator::createIndexedEntry(const CfgEntry *entry, const QString &key)
356{
357 for (int i = 0; i <= entry->paramMax; i++) {
358 const QString argBracket = QStringLiteral("[%1]").arg(i);
359 const QString innerItemVarStr = innerItemVar(entry, cfg()) + argBracket;
360
361 const QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i]
362 : !entry->defaultValue.isEmpty() ? paramString(entry->defaultValue, entry, i)
363 : defaultValue(entry->type);
364
365 if (!entry->signalList.isEmpty()) {
366 stream() << " " << innerItemVarStr << " = " << newInnerItem(entry, paramString(key, entry, i), defaultStr, cfg(), argBracket) << '\n';
367 }
368
369 const QString itemVarStr = itemPath(entry, cfg()) + argBracket;
370
371 stream() << " " << itemVarStr << " = " << newItem(entry, paramString(key, entry, i), defaultStr, cfg(), argBracket) << '\n';
372
373 if (!entry->min.isEmpty()) {
374 stream() << " " << innerItemVarStr << "->setMinValue(" << entry->min << ");\n";
375 }
376 if (!entry->max.isEmpty()) {
377 stream() << " " << innerItemVarStr << "->setMaxValue(" << entry->max << ");\n";
378 }
379
380 for (const CfgEntry::Choice &choice : std::as_const(entry->choices.choices)) {
381 if (!choice.val.isEmpty()) {
382 stream() << " " << innerItemVarStr << "->setValueForChoice(QStringLiteral( \"" << choice.name << "\" ), QStringLiteral( \"" << choice.val
383 << "\" ));\n";
384 }
385 }
386
387 if (cfg().setUserTexts) {
388 stream() << userTextsFunctions(entry, cfg(), itemVarStr, entry->paramName);
389 }
390
391 // Make mutators for enum parameters work by adding them with $(..) replaced by the
392 // param name. The check for isImmutable in the set* functions doesn't have the param
393 // name available, just the corresponding enum value (int), so we need to store the
394 // param names in a separate static list!.
395 const bool isEnum = entry->paramType == QLatin1String("Enum");
396 const QString arg = isEnum ? entry->paramValues[i] : QString::number(i);
397
398 QString paramName = entry->paramName;
399
400 stream() << " addItem( " << itemVarStr << ", QStringLiteral( \"";
401 stream() << paramName.replace(QStringLiteral("$(") + entry->param + QLatin1Char(')'), QLatin1String("%1")).arg(arg);
402 stream() << "\" ) );\n";
403 }
404}
405
406void KConfigSourceGenerator::handleCurrentGroupChange(const CfgEntry *entry)
407{
408 if (entry->group == mCurrentGroup) {
409 return;
410 }
411
412 // HACK: This fixes one spacing line in the diff. Remove this in the future and adapt the testcases.
413 static bool first = true;
414 if (!entry->group.isEmpty()) {
415 if (!first) {
416 stream() << '\n';
417 }
418 first = false;
419 }
420
421 mCurrentGroup = entry->group;
422
423 if (!entry->parentGroup.isEmpty()) {
424 QString parentGroup = QString(entry->parentGroup).remove(QRegularExpression(QStringLiteral("\\W")));
425 if (!mConfigGroupList.contains(parentGroup)) {
426 stream() << " KConfigGroup cg" << parentGroup << "(this->config(), " << paramString(entry->parentGroup, parseResult.parameters) << ");\n";
427 mConfigGroupList << parentGroup;
428 }
429 QString currentGroup = QString(mCurrentGroup).remove(QRegularExpression(QStringLiteral("\\W")));
430 if (!mConfigGroupList.contains(currentGroup)) {
431 stream() << " KConfigGroup cg" << currentGroup << " = cg" << QString(entry->parentGroup).remove(QRegularExpression(QStringLiteral("\\W")))
432 << ".group(" << paramString(mCurrentGroup, parseResult.parameters) << ");\n";
433 mConfigGroupList << currentGroup;
434 }
435 } else {
436 stream() << " setCurrentGroup( " << paramString(mCurrentGroup, parseResult.parameters) << " );";
437 stream() << "\n\n";
438 }
439}
440
441void KConfigSourceGenerator::doConstructor()
442{
443 // Constructor
444 stream() << cfg().className << "::" << cfg().className << "(";
445 createConstructorParameterList();
446 stream() << " )\n";
447 stream() << " : ";
448 createParentConstructorCall();
449 createInitializerList();
450
451 stream() << "{\n";
452
453 if (cfg().parentInConstructor) {
454 stream() << " setParent(parent);\n";
455 }
456
457 if (cfg().dpointer) {
458 stream() << " d = new " << cfg().className << "Private;\n";
459 }
460
461 // Needed in case the singleton class is used as baseclass for
462 // another singleton.
463 if (cfg().singleton) {
464 stream() << " Q_ASSERT(!s_global" << cfg().className << "()->q);\n";
465 stream() << " s_global" << cfg().className << "()->q = this;\n";
466 }
467
468 if (!parseResult.signalList.isEmpty()) {
469 // this cast to base-class pointer-to-member is valid C++
470 // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/
471 stream() << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction ="
472 << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&" << cfg().className << "::itemChanged);\n";
473
474 stream() << '\n';
475 }
476
477 for (const auto *entry : std::as_const(parseResult.entries)) {
478 handleCurrentGroupChange(entry);
479
480 const QString key = paramString(entry->key, parseResult.parameters);
481 if (!entry->code.isEmpty()) {
482 stream() << entry->code << '\n';
483 }
484 createEnums(entry);
485
486 stream() << itemDeclaration(entry, cfg());
487
488 if (entry->param.isEmpty()) {
489 createNormalEntry(entry, key);
490 } else {
491 createIndexedEntry(entry, key);
492 }
493 }
494
495 stream() << "}\n\n";
496}
497
498void KConfigSourceGenerator::createGetterDPointerMode(const CfgEntry *entry)
499{
500 // Accessor
501 if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
502 stream() << enumType(entry, cfg().globalEnums);
503 } else {
504 stream() << cppType(entry->type);
505 }
506
507 stream() << " " << getFunction(entry->name, cfg().className) << "(";
508 if (!entry->param.isEmpty()) {
509 stream() << " " << cppType(entry->paramType) << " i ";
510 }
511 stream() << ")" << Const() << '\n';
512
513 // function body inline only if not using dpointer
514 // for BC mode
515 startScope();
516 // HACK: Fix memberAccessorBody
517 stream() << " " << memberAccessorBody(entry, cfg().globalEnums);
518 endScope();
519 stream() << '\n';
520}
521
522void KConfigSourceGenerator::createImmutableGetterDPointerMode(const CfgEntry *entry)
523{
524 stream() << whitespace() << "";
525 stream() << "bool "
526 << " " << immutableFunction(entry->name, cfg().className) << "(";
527 if (!entry->param.isEmpty()) {
528 stream() << " " << cppType(entry->paramType) << " i ";
529 }
530 stream() << ")" << Const() << '\n';
531 startScope();
532 memberImmutableBody(entry, cfg().globalEnums);
533 endScope();
534 stream() << '\n';
535}
536
537void KConfigSourceGenerator::createSetterDPointerMode(const CfgEntry *entry)
538{
539 // Manipulator
540 if (!(cfg().allMutators || cfg().mutators.contains(entry->name))) {
541 return;
542 }
543
544 stream() << "void " << setFunction(entry->name, cfg().className) << "( ";
545 if (!entry->param.isEmpty()) {
546 stream() << cppType(entry->paramType) << " i, ";
547 }
548
549 if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
550 stream() << enumType(entry, cfg().globalEnums);
551 } else {
552 stream() << param(entry->type);
553 }
554 stream() << " v )\n";
555
556 // function body inline only if not using dpointer
557 // for BC mode
558 startScope();
559 memberMutatorBody(entry);
560 endScope();
561 stream() << '\n';
562}
563
564void KConfigSourceGenerator::createItemGetterDPointerMode(const CfgEntry *entry)
565{
566 // Item accessor
567 if (!cfg().itemAccessors) {
568 return;
569 }
570 stream() << '\n';
571 stream() << cfg().inherits << "::Item" << itemType(entry->type) << " *" << getFunction(entry->name, cfg().className) << "Item(";
572 if (!entry->param.isEmpty()) {
573 stream() << " " << cppType(entry->paramType) << " i ";
574 }
575 stream() << ")\n";
576 startScope();
577 stream() << " " << itemAccessorBody(entry, cfg());
578 endScope();
579}
580
581void KConfigSourceGenerator::doGetterSetterDPointerMode()
582{
583 if (!cfg().dpointer) {
584 return;
585 }
586
587 // setters and getters go in Cpp if in dpointer mode
588 for (const auto *entry : std::as_const(parseResult.entries)) {
589 createSetterDPointerMode(entry);
590 createGetterDPointerMode(entry);
591 createImmutableGetterDPointerMode(entry);
592 createItemGetterDPointerMode(entry);
593 stream() << '\n';
594 }
595}
596
597void KConfigSourceGenerator::createDefaultValueGetterSetter()
598{
599 // default value getters always go in Cpp
600 for (const auto *entry : std::as_const(parseResult.entries)) {
601 QString n = entry->name;
602 QString t = entry->type;
603
604 // Default value Accessor, as "helper" function
605 if ((cfg().allDefaultGetters || cfg().defaultGetters.contains(n)) && !entry->defaultValue.isEmpty()) {
606 stream() << cppType(t) << " " << getDefaultFunction(n, cfg().className) << "_helper(";
607 if (!entry->param.isEmpty()) {
608 stream() << " " << cppType(entry->paramType) << " i ";
609 }
610 stream() << ")" << Const() << '\n';
611 startScope();
612 stream() << memberGetDefaultBody(entry) << '\n';
613 endScope();
614 stream() << '\n';
615 }
616 }
617}
618
619void KConfigSourceGenerator::createDestructor()
620{
621 stream() << cfg().className << "::~" << cfg().className << "()\n";
622 startScope();
623 if (cfg().dpointer) {
624 stream() << " delete d;\n";
625 }
626 if (cfg().singleton) {
627 const QString qgs = QLatin1String("s_global") + cfg().className;
628 stream() << " if (" << qgs << ".exists() && !" << qgs << ".isDestroyed()) {\n";
629 stream() << " " << qgs << "()->q = nullptr;\n";
630 stream() << " }\n";
631 }
632 endScope();
633 stream() << '\n';
634}
635
636void KConfigSourceGenerator::createNonModifyingSignalsHelper()
637{
638 if (!parseResult.hasNonModifySignals) {
639 return;
640 }
641 stream() << "bool " << cfg().className << "::"
642 << "usrSave()\n";
643 startScope();
644 stream() << " const bool res = " << cfg().inherits << "::usrSave();\n";
645 stream() << " if (!res) return false;\n\n";
646 for (const Signal &signal : std::as_const(parseResult.signalList)) {
647 if (signal.modify) {
648 continue;
649 }
650
651 stream() << " if (" << varPath(QStringLiteral("settingsChanged"), cfg()) << ".contains(" << signalEnumName(signal.name) << "))\n";
652 stream() << " Q_EMIT " << signal.name << "(";
653 auto it = signal.arguments.cbegin();
654 const auto itEnd = signal.arguments.cend();
655 while (it != itEnd) {
656 Param argument = *it;
657 bool cast = false;
658 if (cfg().useEnumTypes && argument.type == QLatin1String("Enum")) {
659 for (int i = 0, end = parseResult.entries.count(); i < end; ++i) {
660 if (parseResult.entries.at(i)->name == argument.name) {
661 stream() << "static_cast<" << enumType(parseResult.entries.at(i), cfg().globalEnums) << ">(";
662 cast = true;
663 break;
664 }
665 }
666 }
667 stream() << varPath(argument.name, cfg());
668 if (cast) {
669 stream() << ")";
670 }
671 if (++it != itEnd) {
672 stream() << ", ";
673 }
674 }
675
676 stream() << ");\n";
677 }
678
679 stream() << " " << varPath(QStringLiteral("settingsChanged"), cfg()) << ".clear();\n";
680 stream() << " return true;\n";
681 endScope();
682}
683
684void KConfigSourceGenerator::createSignalFlagsHandler()
685{
686 if (parseResult.signalList.isEmpty()) {
687 return;
688 }
689
690 stream() << '\n';
691 stream() << "void " << cfg().className << "::"
692 << "itemChanged(quint64 signalFlag) {\n";
693 if (parseResult.hasNonModifySignals) {
694 stream() << " " << varPath(QStringLiteral("settingsChanged"), cfg()) << ".insert(signalFlag);\n";
695 }
696
697 if (!parseResult.signalList.isEmpty()) {
698 stream() << '\n';
699 }
700
701 bool modifySignalsWritten = false;
702 for (const Signal &signal : std::as_const(parseResult.signalList)) {
703 if (signal.modify) {
704 if (!modifySignalsWritten) {
705 stream() << " switch (signalFlag) {\n";
706 modifySignalsWritten = true;
707 }
708 stream() << " case " << signalEnumName(signal.name) << ":\n";
709 stream() << " Q_EMIT " << signal.name << "();\n";
710 stream() << " break;\n";
711 }
712 }
713 if (modifySignalsWritten) {
714 stream() << " }\n";
715 }
716
717 stream() << "}\n";
718}
Configuration Compiler Configuration.
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
const_reference at(qsizetype i) const const
const_iterator cbegin() const const
const_iterator cend() const const
qsizetype count() const const
bool isEmpty() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 29 2024 11:49:07 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.