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 if (cfg().kConfigConstructor) {
195 stream() << arg << ")";
196 } else {
197 stream() << "std::move(" << arg << ")";
198 }
199 stream() << ");\n";
200 stream() << " s_global" << cfg().className << "()->q->read();\n";
201 stream() << "}\n\n";
202 };
203 instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true);
204 instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false);
205 }
206}
207
208void KConfigSourceGenerator::createPreamble()
209{
210 QString cppPreamble;
211 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
212 if (entry->paramValues.isEmpty()) {
213 continue;
214 }
215
216 cppPreamble += QStringLiteral("const char* const ") + cfg().className + QStringLiteral("::") + enumName(n: entry->param);
217 cppPreamble += cfg().globalEnums
218 ? QStringLiteral("ToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n")
219 : QStringLiteral("::enumToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n");
220 }
221
222 if (!cppPreamble.isEmpty()) {
223 stream() << cppPreamble << '\n';
224 }
225}
226
227void KConfigSourceGenerator::createConstructorParameterList()
228{
229 if (cfg().kConfigConstructor) {
230 stream() << " std::unique_ptr<KConfig> config" << (parseResult.parameters.isEmpty() ? "" : ",");
231 } else if (parseResult.cfgFileNameArg) {
232 if (!cfg().forceStringFilename) {
233 stream() << " KSharedConfig::Ptr config";
234 } else {
235 stream() << " const QString& config";
236 }
237 stream() << (parseResult.parameters.isEmpty() ? "" : ",");
238 }
239
240 for (auto it = parseResult.parameters.cbegin(); it != parseResult.parameters.cend(); ++it) {
241 if (it != parseResult.parameters.cbegin()) {
242 stream() << ",";
243 }
244 stream() << " " << param(t: (*it).type) << " " << (*it).name;
245 }
246
247 if (cfg().parentInConstructor) {
248 if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty() || cfg().kConfigConstructor) {
249 stream() << ",";
250 }
251 stream() << " QObject *parent";
252 }
253}
254
255void KConfigSourceGenerator::createParentConstructorCall()
256{
257 stream() << cfg().inherits << "(";
258 if (cfg().kConfigConstructor) {
259 stream() << "std::move(config), KCoreConfigSkeleton::DisambiguateConstructor::IsStdUniqPtr";
260 } else {
261 if (parseResult.cfgStateConfig) {
262 stream() << " KSharedConfig::openStateConfig(QStringLiteral( \"" << parseResult.cfgFileName << "\") ";
263 } else if (!parseResult.cfgFileName.isEmpty()) {
264 stream() << " QStringLiteral( \"" << parseResult.cfgFileName << "\" ";
265 } else if (parseResult.cfgFileNameArg && !cfg().kConfigConstructor) {
266 if (!cfg().forceStringFilename) {
267 stream() << " std::move( config ) ";
268 } else {
269 stream() << " config ";
270 }
271 }
272 if (parseResult.cfgStateConfig || !parseResult.cfgFileName.isEmpty()) {
273 stream() << ") ";
274 }
275 }
276 stream() << ")\n";
277}
278
279void KConfigSourceGenerator::createInitializerList()
280{
281 for (const auto &parameter : std::as_const(t&: parseResult.parameters)) {
282 stream() << " , mParam" << parameter.name << "(" << parameter.name << ")\n";
283 }
284}
285
286void KConfigSourceGenerator::createEnums(const CfgEntry *entry)
287{
288 if (entry->type != QLatin1String("Enum")) {
289 return;
290 }
291 stream() << " QList<" << cfg().inherits << "::ItemEnum::Choice> values" << entry->name << ";\n";
292
293 for (const auto &choice : std::as_const(t: entry->choices.choices)) {
294 stream() << " {\n";
295 stream() << " " << cfg().inherits << "::ItemEnum::Choice choice;\n";
296 stream() << " choice.name = QStringLiteral(\"" << choice.name << "\");\n";
297 if (cfg().setUserTexts) {
298 if (!choice.label.isEmpty()) {
299 stream() << " choice.label = " << translatedString(cfg: cfg(), string: choice.label, context: choice.context) << ";\n";
300 }
301 if (!choice.toolTip.isEmpty()) {
302 stream() << " choice.toolTip = " << translatedString(cfg: cfg(), string: choice.toolTip, context: choice.context) << ";\n";
303 }
304 if (!choice.whatsThis.isEmpty()) {
305 stream() << " choice.whatsThis = " << translatedString(cfg: cfg(), string: choice.whatsThis, context: choice.context) << ";\n";
306 }
307 }
308 stream() << " values" << entry->name << ".append( choice );\n";
309 stream() << " }\n";
310 }
311}
312
313void KConfigSourceGenerator::createNormalEntry(const CfgEntry *entry, const QString &key)
314{
315 const QString itemVarStr = itemPath(e: entry, cfg: cfg());
316 const QString innerItemVarStr = innerItemVar(e: entry, cfg: cfg());
317 if (!entry->signalList.isEmpty()) {
318 stream() << " " << innerItemVarStr << " = " << newInnerItem(entry, key, defaultValue: entry->defaultValue, cfg: cfg()) << '\n';
319 }
320
321 stream() << " " << itemVarStr << " = " << newItem(entry, key, defaultValue: entry->defaultValue, cfg: cfg()) << '\n';
322
323 if (!entry->min.isEmpty()) {
324 stream() << " " << innerItemVarStr << "->setMinValue(" << entry->min << ");\n";
325 }
326
327 if (!entry->max.isEmpty()) {
328 stream() << " " << innerItemVarStr << "->setMaxValue(" << entry->max << ");\n";
329 }
330
331 if (cfg().setUserTexts) {
332 stream() << userTextsFunctions(e: entry, cfg: cfg());
333 }
334
335 if (cfg().allNotifiers || cfg().notifiers.contains(str: entry->name)) {
336 stream() << " " << itemVarStr << "->setWriteFlags(KConfigBase::Notify);\n";
337 }
338
339 for (const CfgEntry::Choice &choice : std::as_const(t: entry->choices.choices)) {
340 if (!choice.val.isEmpty()) {
341 stream() << " " << innerItemVarStr << "->setValueForChoice(QStringLiteral( \"" << choice.name << "\" ), QStringLiteral( \"" << choice.val
342 << "\" ));\n";
343 }
344 }
345
346 if (!entry->parentGroup.isEmpty()) {
347 stream() << " " << itemVarStr << "->setGroup(cg" << QString(entry->group).remove(re: QRegularExpression(QStringLiteral("\\W"))) << ");\n";
348 }
349
350 stream() << " addItem( " << itemVarStr;
351 QString quotedName = entry->name;
352 addQuotes(s&: quotedName);
353 if (quotedName != key) {
354 stream() << ", QStringLiteral( \"" << entry->name << "\" )";
355 }
356 stream() << " );\n";
357}
358
359// TODO : Some compiler option won't work or generate bogus settings file.
360// * Does not manage properly Notifiers=true kcfgc option for parameterized entries :
361// ** KConfigCompilerSignallingItem generated with wrong userData parameter (4th one).
362// ** setWriteFlags() is missing.
363// * Q_PROPERTY signal won't work
364void KConfigSourceGenerator::createIndexedEntry(const CfgEntry *entry, const QString &key)
365{
366 for (int i = 0; i <= entry->paramMax; i++) {
367 const QString argBracket = QStringLiteral("[%1]").arg(a: i);
368 const QString innerItemVarStr = innerItemVar(e: entry, cfg: cfg()) + argBracket;
369
370 const QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i]
371 : !entry->defaultValue.isEmpty() ? paramString(s: entry->defaultValue, e: entry, i)
372 : defaultValue(t: entry->type);
373
374 if (!entry->signalList.isEmpty()) {
375 stream() << " " << innerItemVarStr << " = " << newInnerItem(entry, key: paramString(s: key, e: entry, i), defaultValue: defaultStr, cfg: cfg(), param: argBracket) << '\n';
376 }
377
378 const QString itemVarStr = itemPath(e: entry, cfg: cfg()) + argBracket;
379
380 stream() << " " << itemVarStr << " = " << newItem(entry, key: paramString(s: key, e: entry, i), defaultValue: defaultStr, cfg: cfg(), param: argBracket) << '\n';
381
382 if (!entry->min.isEmpty()) {
383 stream() << " " << innerItemVarStr << "->setMinValue(" << entry->min << ");\n";
384 }
385 if (!entry->max.isEmpty()) {
386 stream() << " " << innerItemVarStr << "->setMaxValue(" << entry->max << ");\n";
387 }
388
389 for (const CfgEntry::Choice &choice : std::as_const(t: entry->choices.choices)) {
390 if (!choice.val.isEmpty()) {
391 stream() << " " << innerItemVarStr << "->setValueForChoice(QStringLiteral( \"" << choice.name << "\" ), QStringLiteral( \"" << choice.val
392 << "\" ));\n";
393 }
394 }
395
396 if (cfg().setUserTexts) {
397 stream() << userTextsFunctions(e: entry, cfg: cfg(), itemVarStr, i: entry->paramName);
398 }
399
400 // Make mutators for enum parameters work by adding them with $(..) replaced by the
401 // param name. The check for isImmutable in the set* functions doesn't have the param
402 // name available, just the corresponding enum value (int), so we need to store the
403 // param names in a separate static list!.
404 const bool isEnum = entry->paramType == QLatin1String("Enum");
405 const QString arg = isEnum ? entry->paramValues[i] : QString::number(i);
406
407 QString paramName = entry->paramName;
408
409 stream() << " addItem( " << itemVarStr << ", QStringLiteral( \"";
410 stream() << paramName.replace(QStringLiteral("$(") + entry->param + QLatin1Char(')'), after: QLatin1String("%1")).arg(a: arg);
411 stream() << "\" ) );\n";
412 }
413}
414
415void KConfigSourceGenerator::handleCurrentGroupChange(const CfgEntry *entry)
416{
417 if (entry->group == mCurrentGroup) {
418 return;
419 }
420
421 // HACK: This fixes one spacing line in the diff. Remove this in the future and adapt the testcases.
422 static bool first = true;
423 if (!entry->group.isEmpty()) {
424 if (!first) {
425 stream() << '\n';
426 }
427 first = false;
428 }
429
430 mCurrentGroup = entry->group;
431
432 if (!entry->parentGroup.isEmpty()) {
433 QString parentGroup = QString(entry->parentGroup).remove(re: QRegularExpression(QStringLiteral("\\W")));
434 if (!mConfigGroupList.contains(str: parentGroup)) {
435 stream() << " KConfigGroup cg" << parentGroup << "(this->config(), " << paramString(group: entry->parentGroup, parameters: parseResult.parameters) << ");\n";
436 mConfigGroupList << parentGroup;
437 }
438 QString currentGroup = QString(mCurrentGroup).remove(re: QRegularExpression(QStringLiteral("\\W")));
439 if (!mConfigGroupList.contains(str: currentGroup)) {
440 stream() << " KConfigGroup cg" << currentGroup << " = cg" << QString(entry->parentGroup).remove(re: QRegularExpression(QStringLiteral("\\W")))
441 << ".group(" << paramString(group: mCurrentGroup, parameters: parseResult.parameters) << ");\n";
442 mConfigGroupList << currentGroup;
443 }
444 } else {
445 stream() << " setCurrentGroup( " << paramString(group: mCurrentGroup, parameters: parseResult.parameters) << " );";
446 stream() << "\n\n";
447 }
448}
449
450void KConfigSourceGenerator::doConstructor()
451{
452 // Constructor
453 stream() << cfg().className << "::" << cfg().className << "(";
454 createConstructorParameterList();
455 stream() << " )\n";
456 stream() << " : ";
457 createParentConstructorCall();
458 createInitializerList();
459
460 stream() << "{\n";
461
462 if (cfg().parentInConstructor) {
463 stream() << " setParent(parent);\n";
464 }
465
466 if (cfg().dpointer) {
467 stream() << " d = new " << cfg().className << "Private;\n";
468 }
469
470 // Needed in case the singleton class is used as baseclass for
471 // another singleton.
472 if (cfg().singleton) {
473 stream() << " Q_ASSERT(!s_global" << cfg().className << "()->q);\n";
474 stream() << " s_global" << cfg().className << "()->q = this;\n";
475 }
476
477 if (!parseResult.signalList.isEmpty()) {
478 // this cast to base-class pointer-to-member is valid C++
479 // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/
480 stream() << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction ="
481 << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&" << cfg().className << "::itemChanged);\n";
482
483 stream() << '\n';
484 }
485
486 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
487 handleCurrentGroupChange(entry);
488
489 const QString key = paramString(group: entry->key, parameters: parseResult.parameters);
490 if (!entry->code.isEmpty()) {
491 stream() << entry->code << '\n';
492 }
493 createEnums(entry);
494
495 stream() << itemDeclaration(e: entry, cfg: cfg());
496
497 if (entry->param.isEmpty()) {
498 createNormalEntry(entry, key);
499 } else {
500 createIndexedEntry(entry, key);
501 }
502 }
503
504 stream() << "}\n\n";
505}
506
507void KConfigSourceGenerator::createGetterDPointerMode(const CfgEntry *entry)
508{
509 // Accessor
510 if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
511 stream() << enumType(e: entry, globalEnums: cfg().globalEnums);
512 } else {
513 stream() << cppType(t: entry->type);
514 }
515
516 stream() << " " << getFunction(n: entry->name, className: cfg().className) << "(";
517 if (!entry->param.isEmpty()) {
518 stream() << " " << cppType(t: entry->paramType) << " i ";
519 }
520 stream() << ")" << Const() << '\n';
521
522 // function body inline only if not using dpointer
523 // for BC mode
524 startScope();
525 // HACK: Fix memberAccessorBody
526 stream() << " " << memberAccessorBody(e: entry, globalEnums: cfg().globalEnums);
527 endScope();
528 stream() << '\n';
529}
530
531void KConfigSourceGenerator::createImmutableGetterDPointerMode(const CfgEntry *entry)
532{
533 stream() << whitespace() << "";
534 stream() << "bool "
535 << " " << immutableFunction(n: entry->name, className: cfg().className) << "(";
536 if (!entry->param.isEmpty()) {
537 stream() << " " << cppType(t: entry->paramType) << " i ";
538 }
539 stream() << ")" << Const() << '\n';
540 startScope();
541 memberImmutableBody(e: entry, globalEnums: cfg().globalEnums);
542 endScope();
543 stream() << '\n';
544}
545
546void KConfigSourceGenerator::createSetterDPointerMode(const CfgEntry *entry)
547{
548 // Manipulator
549 if (!(cfg().allMutators || cfg().mutators.contains(str: entry->name))) {
550 return;
551 }
552
553 stream() << "void " << setFunction(n: entry->name, className: cfg().className) << "( ";
554 if (!entry->param.isEmpty()) {
555 stream() << cppType(t: entry->paramType) << " i, ";
556 }
557
558 if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
559 stream() << enumType(e: entry, globalEnums: cfg().globalEnums);
560 } else {
561 stream() << param(t: entry->type);
562 }
563 stream() << " v )\n";
564
565 // function body inline only if not using dpointer
566 // for BC mode
567 startScope();
568 memberMutatorBody(e: entry);
569 endScope();
570 stream() << '\n';
571}
572
573void KConfigSourceGenerator::createItemGetterDPointerMode(const CfgEntry *entry)
574{
575 // Item accessor
576 if (!cfg().itemAccessors) {
577 return;
578 }
579 stream() << '\n';
580 stream() << cfg().inherits << "::Item" << itemType(type: entry->type) << " *" << getFunction(n: entry->name, className: cfg().className) << "Item(";
581 if (!entry->param.isEmpty()) {
582 stream() << " " << cppType(t: entry->paramType) << " i ";
583 }
584 stream() << ")\n";
585 startScope();
586 stream() << " " << itemAccessorBody(e: entry, cfg: cfg());
587 endScope();
588}
589
590void KConfigSourceGenerator::doGetterSetterDPointerMode()
591{
592 if (!cfg().dpointer) {
593 return;
594 }
595
596 // setters and getters go in Cpp if in dpointer mode
597 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
598 createSetterDPointerMode(entry);
599 createGetterDPointerMode(entry);
600 createImmutableGetterDPointerMode(entry);
601 createItemGetterDPointerMode(entry);
602 stream() << '\n';
603 }
604}
605
606void KConfigSourceGenerator::createDefaultValueGetterSetter()
607{
608 // default value getters always go in Cpp
609 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
610 QString n = entry->name;
611 QString t = entry->type;
612
613 // Default value Accessor, as "helper" function
614 if ((cfg().allDefaultGetters || cfg().defaultGetters.contains(str: n)) && !entry->defaultValue.isEmpty()) {
615 stream() << cppType(t) << " " << getDefaultFunction(n, className: cfg().className) << "_helper(";
616 if (!entry->param.isEmpty()) {
617 stream() << " " << cppType(t: entry->paramType) << " i ";
618 }
619 stream() << ")" << Const() << '\n';
620 startScope();
621 stream() << memberGetDefaultBody(e: entry) << '\n';
622 endScope();
623 stream() << '\n';
624 }
625 }
626}
627
628void KConfigSourceGenerator::createDestructor()
629{
630 stream() << cfg().className << "::~" << cfg().className << "()\n";
631 startScope();
632 if (cfg().dpointer) {
633 stream() << " delete d;\n";
634 }
635 if (cfg().singleton) {
636 const QString qgs = QLatin1String("s_global") + cfg().className;
637 stream() << " if (" << qgs << ".exists() && !" << qgs << ".isDestroyed()) {\n";
638 stream() << " " << qgs << "()->q = nullptr;\n";
639 stream() << " }\n";
640 }
641 endScope();
642 stream() << '\n';
643}
644
645void KConfigSourceGenerator::createNonModifyingSignalsHelper()
646{
647 if (!parseResult.hasNonModifySignals) {
648 return;
649 }
650 stream() << "bool " << cfg().className << "::"
651 << "usrSave()\n";
652 startScope();
653 stream() << " const bool res = " << cfg().inherits << "::usrSave();\n";
654 stream() << " if (!res) return false;\n\n";
655 for (const Signal &signal : std::as_const(t&: parseResult.signalList)) {
656 if (signal.modify) {
657 continue;
658 }
659
660 stream() << " if (" << varPath(QStringLiteral("settingsChanged"), cfg: cfg()) << ".contains(" << signalEnumName(signalName: signal.name) << "))\n";
661 stream() << " Q_EMIT " << signal.name << "(";
662 auto it = signal.arguments.cbegin();
663 const auto itEnd = signal.arguments.cend();
664 while (it != itEnd) {
665 Param argument = *it;
666 bool cast = false;
667 if (cfg().useEnumTypes && argument.type == QLatin1String("Enum")) {
668 for (int i = 0, end = parseResult.entries.count(); i < end; ++i) {
669 if (parseResult.entries.at(i)->name == argument.name) {
670 stream() << "static_cast<" << enumType(e: parseResult.entries.at(i), globalEnums: cfg().globalEnums) << ">(";
671 cast = true;
672 break;
673 }
674 }
675 }
676 stream() << varPath(n: argument.name, cfg: cfg());
677 if (cast) {
678 stream() << ")";
679 }
680 if (++it != itEnd) {
681 stream() << ", ";
682 }
683 }
684
685 stream() << ");\n";
686 }
687
688 stream() << " " << varPath(QStringLiteral("settingsChanged"), cfg: cfg()) << ".clear();\n";
689 stream() << " return true;\n";
690 endScope();
691}
692
693void KConfigSourceGenerator::createSignalFlagsHandler()
694{
695 if (parseResult.signalList.isEmpty()) {
696 return;
697 }
698
699 stream() << '\n';
700 stream() << "void " << cfg().className << "::"
701 << "itemChanged(quint64 signalFlag) {\n";
702 if (parseResult.hasNonModifySignals) {
703 stream() << " " << varPath(QStringLiteral("settingsChanged"), cfg: cfg()) << ".insert(signalFlag);\n";
704 }
705
706 if (!parseResult.signalList.isEmpty()) {
707 stream() << '\n';
708 }
709
710 bool modifySignalsWritten = false;
711 for (const Signal &signal : std::as_const(t&: parseResult.signalList)) {
712 if (signal.modify) {
713 if (!modifySignalsWritten) {
714 stream() << " switch (signalFlag) {\n";
715 modifySignalsWritten = true;
716 }
717 stream() << " case " << signalEnumName(signalName: signal.name) << ":\n";
718 stream() << " Q_EMIT " << signal.name << "();\n";
719 stream() << " break;\n";
720 }
721 }
722 if (modifySignalsWritten) {
723 stream() << " }\n";
724 }
725
726 stream() << "}\n";
727}
728

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