File indexing completed on 2024-05-12 03:54:30

0001 /*
0002     This file is part of the KDE libraries
0003 
0004     SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org>
0005     SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
0006     SPDX-FileCopyrightText: 2003 Zack Rusin <zack@kde.org>
0007     SPDX-FileCopyrightText: 2006 Michaƫl Larouche <michael.larouche@kdemail.net>
0008     SPDX-FileCopyrightText: 2008 Allen Winter <winter@kde.org>
0009     SPDX-FileCopyrightText: 2020 Tomaz Cananbrava <tcanabrava@kde.org>
0010 
0011     SPDX-License-Identifier: LGPL-2.0-or-later
0012 */
0013 
0014 #include "KConfigSourceGenerator.h"
0015 
0016 #include <QRegularExpression>
0017 
0018 KConfigSourceGenerator::KConfigSourceGenerator(const QString &inputFile, const QString &baseDir, const KConfigParameters &cfg, ParseResult &parseResult)
0019     : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1String(".cpp"), cfg, parseResult)
0020 {
0021 }
0022 
0023 void KConfigSourceGenerator::start()
0024 {
0025     KConfigCodeGeneratorBase::start();
0026     stream() << '\n';
0027     createHeaders();
0028 
0029     if (!cfg().nameSpace.isEmpty()) {
0030         stream() << "using namespace " << cfg().nameSpace << ";";
0031         stream() << "\n\n";
0032     }
0033 
0034     createPrivateDPointerImplementation();
0035     createSingletonImplementation();
0036     createPreamble();
0037     doConstructor();
0038     doGetterSetterDPointerMode();
0039     createDefaultValueGetterSetter();
0040     createDestructor();
0041     createNonModifyingSignalsHelper();
0042     createSignalFlagsHandler();
0043     includeMoc();
0044 }
0045 
0046 void KConfigSourceGenerator::createHeaders()
0047 {
0048     QString headerName = cfg().baseName + QLatin1Char('.') + cfg().headerExtension;
0049 
0050     // TODO: Make addQuotes return a string instead of replacing it inplace.
0051     addQuotes(headerName);
0052 
0053     addHeaders({headerName});
0054     stream() << '\n';
0055 
0056     addHeaders(cfg().sourceIncludes);
0057     if (cfg().setUserTexts && cfg().translationSystem == KConfigParameters::KdeTranslation) {
0058         addHeaders({QStringLiteral("klocalizedstring.h")});
0059         stream() << '\n';
0060     }
0061 
0062     // Header required by singleton implementation
0063     if (cfg().singleton) {
0064         addHeaders({QStringLiteral("qglobal.h"), QStringLiteral("QFile")});
0065 
0066         // HACK: Add single line to fix test.
0067         if (cfg().singleton && parseResult.cfgFileNameArg) {
0068             stream() << '\n';
0069         }
0070     }
0071 
0072     if (cfg().singleton && parseResult.cfgFileNameArg) {
0073         addHeaders({QStringLiteral("QDebug")});
0074     }
0075 
0076     if (cfg().dpointer && parseResult.hasNonModifySignals) {
0077         addHeaders({QStringLiteral("QSet")});
0078     }
0079 
0080     if (cfg().singleton) {
0081         stream() << '\n';
0082     }
0083 }
0084 
0085 void KConfigSourceGenerator::createPrivateDPointerImplementation()
0086 {
0087     // private class implementation
0088     if (!cfg().dpointer) {
0089         return;
0090     }
0091 
0092     QString group;
0093     beginNamespaces();
0094     stream() << "class " << cfg().className << "Private\n";
0095     stream() << "{\n";
0096     stream() << "  public:\n";
0097 
0098     // Create Members
0099     for (const auto *entry : std::as_const(parseResult.entries)) {
0100         if (entry->group != group) {
0101             group = entry->group;
0102             stream() << '\n';
0103             stream() << "    // " << group << '\n';
0104         }
0105         stream() << "    " << cppType(entry->type) << " " << varName(entry->name, cfg());
0106         if (!entry->param.isEmpty()) {
0107             stream() << QStringLiteral("[%1]").arg(entry->paramMax + 1);
0108         }
0109         stream() << ";\n";
0110     }
0111     stream() << "\n    // items\n";
0112 
0113     // Create Items.
0114     for (const auto *entry : std::as_const(parseResult.entries)) {
0115         const QString declType = entry->signalList.isEmpty() ? QString(cfg().inherits + QStringLiteral("::Item") + itemType(entry->type))
0116                                                              : QStringLiteral("KConfigCompilerSignallingItem");
0117 
0118         stream() << "    " << declType << " *" << itemVar(entry, cfg());
0119         if (!entry->param.isEmpty()) {
0120             stream() << QStringLiteral("[%1]").arg(entry->paramMax + 1);
0121         }
0122         stream() << ";\n";
0123     }
0124 
0125     if (parseResult.hasNonModifySignals) {
0126         stream() << "    QSet<quint64> " << varName(QStringLiteral("settingsChanged"), cfg()) << ";\n";
0127     }
0128 
0129     stream() << "};\n\n";
0130     endNamespaces();
0131 }
0132 
0133 void KConfigSourceGenerator::createSingletonImplementation()
0134 {
0135     // Singleton implementation
0136     if (!cfg().singleton) {
0137         return;
0138     }
0139 
0140     beginNamespaces();
0141     stream() << "class " << cfg().className << "Helper\n";
0142     stream() << '{' << '\n';
0143     stream() << "  public:\n";
0144     stream() << "    " << cfg().className << "Helper() : q(nullptr) {}\n";
0145     stream() << "    ~" << cfg().className << "Helper() { delete q; q = nullptr; }\n";
0146     stream() << "    " << cfg().className << "Helper(const " << cfg().className << "Helper&) = delete;\n";
0147     stream() << "    " << cfg().className << "Helper& operator=(const " << cfg().className << "Helper&) = delete;\n";
0148     stream() << "    " << cfg().className << " *q;\n";
0149     stream() << "};\n";
0150     endNamespaces();
0151 
0152     stream() << "Q_GLOBAL_STATIC(" << cfg().className << "Helper, s_global" << cfg().className << ")\n";
0153 
0154     stream() << cfg().className << " *" << cfg().className << "::self()\n";
0155     stream() << "{\n";
0156     if (parseResult.cfgFileNameArg) {
0157         stream() << "  if (!s_global" << cfg().className << "()->q)\n";
0158         stream() << "     qFatal(\"you need to call " << cfg().className << "::instance before using\");\n";
0159     } else {
0160         stream() << "  if (!s_global" << cfg().className << "()->q) {\n";
0161         stream() << "    new " << cfg().className << ';' << '\n';
0162         stream() << "    s_global" << cfg().className << "()->q->read();\n";
0163         stream() << "  }\n\n";
0164     }
0165     stream() << "  return s_global" << cfg().className << "()->q;\n";
0166     stream() << "}\n\n";
0167 
0168     if (parseResult.cfgFileNameArg) {
0169         auto instance = [this](const QString &type, const QString &arg, bool isString) {
0170             stream() << "void " << cfg().className << "::instance(" << type << " " << arg << ")\n";
0171             stream() << "{\n";
0172             stream() << "  if (s_global" << cfg().className << "()->q) {\n";
0173             stream() << "     qDebug() << \"" << cfg().className << "::instance called after the first use - ignoring\";\n";
0174             stream() << "     return;\n";
0175             stream() << "  }\n";
0176             stream() << "  new " << cfg().className << "(";
0177             if (parseResult.cfgStateConfig) {
0178                 stream() << "KSharedConfig::openStateConfig(" << arg << ")";
0179             } else if (isString) {
0180                 stream() << "KSharedConfig::openConfig(" << arg << ")";
0181             } else {
0182                 stream() << "std::move(" << arg << ")";
0183             }
0184             stream() << ");\n";
0185             stream() << "  s_global" << cfg().className << "()->q->read();\n";
0186             stream() << "}\n\n";
0187         };
0188         instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true);
0189         instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false);
0190     }
0191 }
0192 
0193 void KConfigSourceGenerator::createPreamble()
0194 {
0195     QString cppPreamble;
0196     for (const auto *entry : std::as_const(parseResult.entries)) {
0197         if (entry->paramValues.isEmpty()) {
0198             continue;
0199         }
0200 
0201         cppPreamble += QStringLiteral("const char* const ") + cfg().className + QStringLiteral("::") + enumName(entry->param);
0202         cppPreamble += cfg().globalEnums
0203             ? QStringLiteral("ToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n")
0204             : QStringLiteral("::enumToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n");
0205     }
0206 
0207     if (!cppPreamble.isEmpty()) {
0208         stream() << cppPreamble << '\n';
0209     }
0210 }
0211 
0212 void KConfigSourceGenerator::createConstructorParameterList()
0213 {
0214     if (parseResult.cfgFileNameArg) {
0215         if (!cfg().forceStringFilename) {
0216             stream() << " KSharedConfig::Ptr config";
0217         } else {
0218             stream() << " const QString& config";
0219         }
0220         stream() << (parseResult.parameters.isEmpty() ? "" : ",");
0221     }
0222 
0223     for (auto it = parseResult.parameters.cbegin(); it != parseResult.parameters.cend(); ++it) {
0224         if (it != parseResult.parameters.cbegin()) {
0225             stream() << ",";
0226         }
0227         stream() << " " << param((*it).type) << " " << (*it).name;
0228     }
0229 
0230     if (cfg().parentInConstructor) {
0231         if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) {
0232             stream() << ",";
0233         }
0234         stream() << " QObject *parent";
0235     }
0236 }
0237 
0238 void KConfigSourceGenerator::createParentConstructorCall()
0239 {
0240     stream() << cfg().inherits << "(";
0241     if (parseResult.cfgStateConfig) {
0242         stream() << " KSharedConfig::openStateConfig(QStringLiteral( \"" << parseResult.cfgFileName << "\") ";
0243     } else if (!parseResult.cfgFileName.isEmpty()) {
0244         stream() << " QStringLiteral( \"" << parseResult.cfgFileName << "\" ";
0245     }
0246     if (parseResult.cfgFileNameArg) {
0247         if (!cfg().forceStringFilename) {
0248             stream() << " std::move( config ) ";
0249         } else {
0250             stream() << " config ";
0251         }
0252     }
0253     if (!parseResult.cfgFileName.isEmpty()) {
0254         stream() << ") ";
0255     }
0256     stream() << ")\n";
0257 }
0258 
0259 void KConfigSourceGenerator::createInitializerList()
0260 {
0261     for (const auto &parameter : std::as_const(parseResult.parameters)) {
0262         stream() << "  , mParam" << parameter.name << "(" << parameter.name << ")\n";
0263     }
0264 }
0265 
0266 void KConfigSourceGenerator::createEnums(const CfgEntry *entry)
0267 {
0268     if (entry->type != QLatin1String("Enum")) {
0269         return;
0270     }
0271     stream() << "  QList<" << cfg().inherits << "::ItemEnum::Choice> values" << entry->name << ";\n";
0272 
0273     for (const auto &choice : std::as_const(entry->choices.choices)) {
0274         stream() << "  {\n";
0275         stream() << "    " << cfg().inherits << "::ItemEnum::Choice choice;\n";
0276         stream() << "    choice.name = QStringLiteral(\"" << choice.name << "\");\n";
0277         if (cfg().setUserTexts) {
0278             if (!choice.label.isEmpty()) {
0279                 stream() << "    choice.label = " << translatedString(cfg(), choice.label, choice.context) << ";\n";
0280             }
0281             if (!choice.toolTip.isEmpty()) {
0282                 stream() << "    choice.toolTip = " << translatedString(cfg(), choice.toolTip, choice.context) << ";\n";
0283             }
0284             if (!choice.whatsThis.isEmpty()) {
0285                 stream() << "    choice.whatsThis = " << translatedString(cfg(), choice.whatsThis, choice.context) << ";\n";
0286             }
0287         }
0288         stream() << "    values" << entry->name << ".append( choice );\n";
0289         stream() << "  }\n";
0290     }
0291 }
0292 
0293 void KConfigSourceGenerator::createNormalEntry(const CfgEntry *entry, const QString &key)
0294 {
0295     const QString itemVarStr = itemPath(entry, cfg());
0296     const QString innerItemVarStr = innerItemVar(entry, cfg());
0297     if (!entry->signalList.isEmpty()) {
0298         stream() << "  " << innerItemVarStr << " = " << newInnerItem(entry, key, entry->defaultValue, cfg()) << '\n';
0299     }
0300 
0301     stream() << "  " << itemVarStr << " = " << newItem(entry, key, entry->defaultValue, cfg()) << '\n';
0302 
0303     if (!entry->min.isEmpty()) {
0304         stream() << "  " << innerItemVarStr << "->setMinValue(" << entry->min << ");\n";
0305     }
0306 
0307     if (!entry->max.isEmpty()) {
0308         stream() << "  " << innerItemVarStr << "->setMaxValue(" << entry->max << ");\n";
0309     }
0310 
0311     if (cfg().setUserTexts) {
0312         stream() << userTextsFunctions(entry, cfg());
0313     }
0314 
0315     if (cfg().allNotifiers || cfg().notifiers.contains(entry->name)) {
0316         stream() << "  " << itemVarStr << "->setWriteFlags(KConfigBase::Notify);\n";
0317     }
0318 
0319     for (const CfgEntry::Choice &choice : std::as_const(entry->choices.choices)) {
0320         if (!choice.val.isEmpty()) {
0321             stream() << "  " << innerItemVarStr << "->setValueForChoice(QStringLiteral( \"" << choice.name << "\" ), QStringLiteral( \"" << choice.val
0322                      << "\" ));\n";
0323         }
0324     }
0325 
0326     if (!entry->parentGroup.isEmpty()) {
0327         stream() << "  " << itemVarStr << "->setGroup(cg" << QString(entry->group).remove(QRegularExpression(QStringLiteral("\\W"))) << ");\n";
0328     }
0329 
0330     stream() << "  addItem( " << itemVarStr;
0331     QString quotedName = entry->name;
0332     addQuotes(quotedName);
0333     if (quotedName != key) {
0334         stream() << ", QStringLiteral( \"" << entry->name << "\" )";
0335     }
0336     stream() << " );\n";
0337 }
0338 
0339 // TODO : Some compiler option won't work or generate bogus settings file.
0340 // * Does not manage properly Notifiers=true kcfgc option for parameterized entries :
0341 // ** KConfigCompilerSignallingItem generated with wrong userData parameter (4th one).
0342 // ** setWriteFlags() is missing.
0343 // * Q_PROPERTY signal won't work
0344 void KConfigSourceGenerator::createIndexedEntry(const CfgEntry *entry, const QString &key)
0345 {
0346     for (int i = 0; i <= entry->paramMax; i++) {
0347         const QString argBracket = QStringLiteral("[%1]").arg(i);
0348         const QString innerItemVarStr = innerItemVar(entry, cfg()) + argBracket;
0349 
0350         const QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i]
0351             : !entry->defaultValue.isEmpty()                               ? paramString(entry->defaultValue, entry, i)
0352                                                                            : defaultValue(entry->type);
0353 
0354         if (!entry->signalList.isEmpty()) {
0355             stream() << "  " << innerItemVarStr << " = " << newInnerItem(entry, paramString(key, entry, i), defaultStr, cfg(), argBracket) << '\n';
0356         }
0357 
0358         const QString itemVarStr = itemPath(entry, cfg()) + argBracket;
0359 
0360         stream() << "  " << itemVarStr << " = " << newItem(entry, paramString(key, entry, i), defaultStr, cfg(), argBracket) << '\n';
0361 
0362         if (!entry->min.isEmpty()) {
0363             stream() << "  " << innerItemVarStr << "->setMinValue(" << entry->min << ");\n";
0364         }
0365         if (!entry->max.isEmpty()) {
0366             stream() << "  " << innerItemVarStr << "->setMaxValue(" << entry->max << ");\n";
0367         }
0368 
0369         for (const CfgEntry::Choice &choice : std::as_const(entry->choices.choices)) {
0370             if (!choice.val.isEmpty()) {
0371                 stream() << "  " << innerItemVarStr << "->setValueForChoice(QStringLiteral( \"" << choice.name << "\" ), QStringLiteral( \"" << choice.val
0372                          << "\" ));\n";
0373             }
0374         }
0375 
0376         if (cfg().setUserTexts) {
0377             stream() << userTextsFunctions(entry, cfg(), itemVarStr, entry->paramName);
0378         }
0379 
0380         // Make mutators for enum parameters work by adding them with $(..) replaced by the
0381         // param name. The check for isImmutable in the set* functions doesn't have the param
0382         // name available, just the corresponding enum value (int), so we need to store the
0383         // param names in a separate static list!.
0384         const bool isEnum = entry->paramType == QLatin1String("Enum");
0385         const QString arg = isEnum ? entry->paramValues[i] : QString::number(i);
0386 
0387         QString paramName = entry->paramName;
0388 
0389         stream() << "  addItem( " << itemVarStr << ", QStringLiteral( \"";
0390         stream() << paramName.replace(QStringLiteral("$(") + entry->param + QLatin1Char(')'), QLatin1String("%1")).arg(arg);
0391         stream() << "\" ) );\n";
0392     }
0393 }
0394 
0395 void KConfigSourceGenerator::handleCurrentGroupChange(const CfgEntry *entry)
0396 {
0397     if (entry->group == mCurrentGroup) {
0398         return;
0399     }
0400 
0401     // HACK: This fixes one spacing line in the diff. Remove this in the future and adapt the testcases.
0402     static bool first = true;
0403     if (!entry->group.isEmpty()) {
0404         if (!first) {
0405             stream() << '\n';
0406         }
0407         first = false;
0408     }
0409 
0410     mCurrentGroup = entry->group;
0411 
0412     if (!entry->parentGroup.isEmpty()) {
0413         QString parentGroup = QString(entry->parentGroup).remove(QRegularExpression(QStringLiteral("\\W")));
0414         if (!mConfigGroupList.contains(parentGroup)) {
0415             stream() << "  KConfigGroup cg" << parentGroup << "(this->config(), " << paramString(entry->parentGroup, parseResult.parameters) << ");\n";
0416             mConfigGroupList << parentGroup;
0417         }
0418         QString currentGroup = QString(mCurrentGroup).remove(QRegularExpression(QStringLiteral("\\W")));
0419         if (!mConfigGroupList.contains(currentGroup)) {
0420             stream() << "  KConfigGroup cg" << currentGroup << " = cg" << QString(entry->parentGroup).remove(QRegularExpression(QStringLiteral("\\W")))
0421                      << ".group(" << paramString(mCurrentGroup, parseResult.parameters) << ");\n";
0422             mConfigGroupList << currentGroup;
0423         }
0424     } else {
0425         stream() << "  setCurrentGroup( " << paramString(mCurrentGroup, parseResult.parameters) << " );";
0426         stream() << "\n\n";
0427     }
0428 }
0429 
0430 void KConfigSourceGenerator::doConstructor()
0431 {
0432     // Constructor
0433     stream() << cfg().className << "::" << cfg().className << "(";
0434     createConstructorParameterList();
0435     stream() << " )\n";
0436     stream() << "  : ";
0437     createParentConstructorCall();
0438     createInitializerList();
0439 
0440     stream() << "{\n";
0441 
0442     if (cfg().parentInConstructor) {
0443         stream() << "  setParent(parent);\n";
0444     }
0445 
0446     if (cfg().dpointer) {
0447         stream() << "  d = new " << cfg().className << "Private;\n";
0448     }
0449 
0450     // Needed in case the singleton class is used as baseclass for
0451     // another singleton.
0452     if (cfg().singleton) {
0453         stream() << "  Q_ASSERT(!s_global" << cfg().className << "()->q);\n";
0454         stream() << "  s_global" << cfg().className << "()->q = this;\n";
0455     }
0456 
0457     if (!parseResult.signalList.isEmpty()) {
0458         // this cast to base-class pointer-to-member is valid C++
0459         // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/
0460         stream() << "  KConfigCompilerSignallingItem::NotifyFunction notifyFunction ="
0461                  << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&" << cfg().className << "::itemChanged);\n";
0462 
0463         stream() << '\n';
0464     }
0465 
0466     for (const auto *entry : std::as_const(parseResult.entries)) {
0467         handleCurrentGroupChange(entry);
0468 
0469         const QString key = paramString(entry->key, parseResult.parameters);
0470         if (!entry->code.isEmpty()) {
0471             stream() << entry->code << '\n';
0472         }
0473         createEnums(entry);
0474 
0475         stream() << itemDeclaration(entry, cfg());
0476 
0477         if (entry->param.isEmpty()) {
0478             createNormalEntry(entry, key);
0479         } else {
0480             createIndexedEntry(entry, key);
0481         }
0482     }
0483 
0484     stream() << "}\n\n";
0485 }
0486 
0487 void KConfigSourceGenerator::createGetterDPointerMode(const CfgEntry *entry)
0488 {
0489     // Accessor
0490     if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
0491         stream() << enumType(entry, cfg().globalEnums);
0492     } else {
0493         stream() << cppType(entry->type);
0494     }
0495 
0496     stream() << " " << getFunction(entry->name, cfg().className) << "(";
0497     if (!entry->param.isEmpty()) {
0498         stream() << " " << cppType(entry->paramType) << " i ";
0499     }
0500     stream() << ")" << Const() << '\n';
0501 
0502     // function body inline only if not using dpointer
0503     // for BC mode
0504     startScope();
0505     // HACK: Fix memberAccessorBody
0506     stream() << "  " << memberAccessorBody(entry, cfg().globalEnums);
0507     endScope();
0508     stream() << '\n';
0509 }
0510 
0511 void KConfigSourceGenerator::createImmutableGetterDPointerMode(const CfgEntry *entry)
0512 {
0513     stream() << whitespace() << "";
0514     stream() << "bool "
0515              << " " << immutableFunction(entry->name, cfg().className) << "(";
0516     if (!entry->param.isEmpty()) {
0517         stream() << " " << cppType(entry->paramType) << " i ";
0518     }
0519     stream() << ")" << Const() << '\n';
0520     startScope();
0521     memberImmutableBody(entry, cfg().globalEnums);
0522     endScope();
0523     stream() << '\n';
0524 }
0525 
0526 void KConfigSourceGenerator::createSetterDPointerMode(const CfgEntry *entry)
0527 {
0528     // Manipulator
0529     if (!(cfg().allMutators || cfg().mutators.contains(entry->name))) {
0530         return;
0531     }
0532 
0533     stream() << "void " << setFunction(entry->name, cfg().className) << "( ";
0534     if (!entry->param.isEmpty()) {
0535         stream() << cppType(entry->paramType) << " i, ";
0536     }
0537 
0538     if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
0539         stream() << enumType(entry, cfg().globalEnums);
0540     } else {
0541         stream() << param(entry->type);
0542     }
0543     stream() << " v )\n";
0544 
0545     // function body inline only if not using dpointer
0546     // for BC mode
0547     startScope();
0548     memberMutatorBody(entry);
0549     endScope();
0550     stream() << '\n';
0551 }
0552 
0553 void KConfigSourceGenerator::createItemGetterDPointerMode(const CfgEntry *entry)
0554 {
0555     // Item accessor
0556     if (!cfg().itemAccessors) {
0557         return;
0558     }
0559     stream() << '\n';
0560     stream() << cfg().inherits << "::Item" << itemType(entry->type) << " *" << getFunction(entry->name, cfg().className) << "Item(";
0561     if (!entry->param.isEmpty()) {
0562         stream() << " " << cppType(entry->paramType) << " i ";
0563     }
0564     stream() << ")\n";
0565     startScope();
0566     stream() << "  " << itemAccessorBody(entry, cfg());
0567     endScope();
0568 }
0569 
0570 void KConfigSourceGenerator::doGetterSetterDPointerMode()
0571 {
0572     if (!cfg().dpointer) {
0573         return;
0574     }
0575 
0576     // setters and getters go in Cpp if in dpointer mode
0577     for (const auto *entry : std::as_const(parseResult.entries)) {
0578         createSetterDPointerMode(entry);
0579         createGetterDPointerMode(entry);
0580         createImmutableGetterDPointerMode(entry);
0581         createItemGetterDPointerMode(entry);
0582         stream() << '\n';
0583     }
0584 }
0585 
0586 void KConfigSourceGenerator::createDefaultValueGetterSetter()
0587 {
0588     // default value getters always go in Cpp
0589     for (const auto *entry : std::as_const(parseResult.entries)) {
0590         QString n = entry->name;
0591         QString t = entry->type;
0592 
0593         // Default value Accessor, as "helper" function
0594         if ((cfg().allDefaultGetters || cfg().defaultGetters.contains(n)) && !entry->defaultValue.isEmpty()) {
0595             stream() << cppType(t) << " " << getDefaultFunction(n, cfg().className) << "_helper(";
0596             if (!entry->param.isEmpty()) {
0597                 stream() << " " << cppType(entry->paramType) << " i ";
0598             }
0599             stream() << ")" << Const() << '\n';
0600             startScope();
0601             stream() << memberGetDefaultBody(entry) << '\n';
0602             endScope();
0603             stream() << '\n';
0604         }
0605     }
0606 }
0607 
0608 void KConfigSourceGenerator::createDestructor()
0609 {
0610     stream() << cfg().className << "::~" << cfg().className << "()\n";
0611     startScope();
0612     if (cfg().dpointer) {
0613         stream() << "  delete d;\n";
0614     }
0615     if (cfg().singleton) {
0616         const QString qgs = QLatin1String("s_global") + cfg().className;
0617         stream() << "  if (" << qgs << ".exists() && !" << qgs << ".isDestroyed()) {\n";
0618         stream() << "    " << qgs << "()->q = nullptr;\n";
0619         stream() << "  }\n";
0620     }
0621     endScope();
0622     stream() << '\n';
0623 }
0624 
0625 void KConfigSourceGenerator::createNonModifyingSignalsHelper()
0626 {
0627     if (!parseResult.hasNonModifySignals) {
0628         return;
0629     }
0630     stream() << "bool " << cfg().className << "::"
0631              << "usrSave()\n";
0632     startScope();
0633     stream() << "  const bool res = " << cfg().inherits << "::usrSave();\n";
0634     stream() << "  if (!res) return false;\n\n";
0635     for (const Signal &signal : std::as_const(parseResult.signalList)) {
0636         if (signal.modify) {
0637             continue;
0638         }
0639 
0640         stream() << "  if (" << varPath(QStringLiteral("settingsChanged"), cfg()) << ".contains(" << signalEnumName(signal.name) << "))\n";
0641         stream() << "    Q_EMIT " << signal.name << "(";
0642         auto it = signal.arguments.cbegin();
0643         const auto itEnd = signal.arguments.cend();
0644         while (it != itEnd) {
0645             Param argument = *it;
0646             bool cast = false;
0647             if (cfg().useEnumTypes && argument.type == QLatin1String("Enum")) {
0648                 for (int i = 0, end = parseResult.entries.count(); i < end; ++i) {
0649                     if (parseResult.entries.at(i)->name == argument.name) {
0650                         stream() << "static_cast<" << enumType(parseResult.entries.at(i), cfg().globalEnums) << ">(";
0651                         cast = true;
0652                         break;
0653                     }
0654                 }
0655             }
0656             stream() << varPath(argument.name, cfg());
0657             if (cast) {
0658                 stream() << ")";
0659             }
0660             if (++it != itEnd) {
0661                 stream() << ", ";
0662             }
0663         }
0664 
0665         stream() << ");\n";
0666     }
0667 
0668     stream() << "  " << varPath(QStringLiteral("settingsChanged"), cfg()) << ".clear();\n";
0669     stream() << "  return true;\n";
0670     endScope();
0671 }
0672 
0673 void KConfigSourceGenerator::createSignalFlagsHandler()
0674 {
0675     if (parseResult.signalList.isEmpty()) {
0676         return;
0677     }
0678 
0679     stream() << '\n';
0680     stream() << "void " << cfg().className << "::"
0681              << "itemChanged(quint64 signalFlag) {\n";
0682     if (parseResult.hasNonModifySignals) {
0683         stream() << "  " << varPath(QStringLiteral("settingsChanged"), cfg()) << ".insert(signalFlag);\n";
0684     }
0685 
0686     if (!parseResult.signalList.isEmpty()) {
0687         stream() << '\n';
0688     }
0689 
0690     bool modifySignalsWritten = false;
0691     for (const Signal &signal : std::as_const(parseResult.signalList)) {
0692         if (signal.modify) {
0693             if (!modifySignalsWritten) {
0694                 stream() << "  switch (signalFlag) {\n";
0695                 modifySignalsWritten = true;
0696             }
0697             stream() << "  case " << signalEnumName(signal.name) << ":\n";
0698             stream() << "    Q_EMIT " << signal.name << "();\n";
0699             stream() << "    break;\n";
0700         }
0701     }
0702     if (modifySignalsWritten) {
0703         stream() << "  }\n";
0704     }
0705 
0706     stream() << "}\n";
0707 }
0708 
0709 void KConfigSourceGenerator::includeMoc()
0710 {
0711     const QString mocFileName = cfg().baseName + QStringLiteral(".moc");
0712 
0713     if (parseResult.signalList.count() || cfg().generateProperties) {
0714         // Add includemoc if they are signals defined.
0715         stream() << '\n';
0716         stream() << "#include \"" << mocFileName << "\"\n";
0717         stream() << '\n';
0718     }
0719 }