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

source code of kconfig/src/kconfig_compiler/KConfigSourceGenerator.cpp