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

KDE's Doxygen guidelines are available online.