KConfig

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

KDE's Doxygen guidelines are available online.