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