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

KDE's Doxygen guidelines are available online.