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 | |
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::() |
47 | { |
48 | QString = cfg().baseName + QLatin1Char('.') + cfg().headerExtension; |
49 | |
50 | // TODO: Make addQuotes return a string instead of replacing it inplace. |
51 | addQuotes(s&: headerName); |
52 | |
53 | addHeaders(header: {headerName}); |
54 | stream() << '\n'; |
55 | |
56 | addHeaders(header: cfg().sourceIncludes); |
57 | if (cfg().setUserTexts && cfg().translationSystem == KConfigParameters::KdeTranslation) { |
58 | addHeaders(header: {QStringLiteral("klocalizedstring.h" )}); |
59 | stream() << '\n'; |
60 | } |
61 | |
62 | // Header required by singleton implementation |
63 | if (cfg().singleton) { |
64 | addHeaders(header: {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(header: {QStringLiteral("QDebug" )}); |
74 | } |
75 | |
76 | if (cfg().dpointer && parseResult.hasNonModifySignals) { |
77 | addHeaders(header: {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(t&: parseResult.entries)) { |
100 | if (entry->group != group) { |
101 | group = entry->group; |
102 | stream() << '\n'; |
103 | stream() << " // " << group << '\n'; |
104 | } |
105 | stream() << " " << cppType(t: entry->type) << " " << varName(n: entry->name, cfg: cfg()); |
106 | if (!entry->param.isEmpty()) { |
107 | stream() << QStringLiteral("[%1]" ).arg(a: 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(t&: parseResult.entries)) { |
115 | const QString declType = entry->signalList.isEmpty() ? QString(cfg().inherits + QStringLiteral("::Item" ) + itemType(type: entry->type)) |
116 | : QStringLiteral("KConfigCompilerSignallingItem" ); |
117 | |
118 | stream() << " " << declType << " *" << itemVar(e: entry, cfg: cfg()); |
119 | if (!entry->param.isEmpty()) { |
120 | stream() << QStringLiteral("[%1]" ).arg(a: entry->paramMax + 1); |
121 | } |
122 | stream() << ";\n" ; |
123 | } |
124 | |
125 | if (parseResult.hasNonModifySignals) { |
126 | stream() << " QSet<quint64> " << varName(QStringLiteral("settingsChanged" ), cfg: 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(t&: parseResult.entries)) { |
197 | if (entry->paramValues.isEmpty()) { |
198 | continue; |
199 | } |
200 | |
201 | cppPreamble += QStringLiteral("const char* const " ) + cfg().className + QStringLiteral("::" ) + enumName(n: 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(t: (*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 ¶meter : std::as_const(t&: 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(t: 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: cfg(), string: choice.label, context: choice.context) << ";\n" ; |
280 | } |
281 | if (!choice.toolTip.isEmpty()) { |
282 | stream() << " choice.toolTip = " << translatedString(cfg: cfg(), string: choice.toolTip, context: choice.context) << ";\n" ; |
283 | } |
284 | if (!choice.whatsThis.isEmpty()) { |
285 | stream() << " choice.whatsThis = " << translatedString(cfg: cfg(), string: choice.whatsThis, context: 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(e: entry, cfg: cfg()); |
296 | const QString innerItemVarStr = innerItemVar(e: entry, cfg: cfg()); |
297 | if (!entry->signalList.isEmpty()) { |
298 | stream() << " " << innerItemVarStr << " = " << newInnerItem(entry, key, defaultValue: entry->defaultValue, cfg: cfg()) << '\n'; |
299 | } |
300 | |
301 | stream() << " " << itemVarStr << " = " << newItem(entry, key, defaultValue: entry->defaultValue, cfg: 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(e: entry, cfg: cfg()); |
313 | } |
314 | |
315 | if (cfg().allNotifiers || cfg().notifiers.contains(str: entry->name)) { |
316 | stream() << " " << itemVarStr << "->setWriteFlags(KConfigBase::Notify);\n" ; |
317 | } |
318 | |
319 | for (const CfgEntry::Choice &choice : std::as_const(t: 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(re: QRegularExpression(QStringLiteral("\\W" ))) << ");\n" ; |
328 | } |
329 | |
330 | stream() << " addItem( " << itemVarStr; |
331 | QString quotedName = entry->name; |
332 | addQuotes(s&: 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(a: i); |
348 | const QString innerItemVarStr = innerItemVar(e: entry, cfg: cfg()) + argBracket; |
349 | |
350 | const QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i] |
351 | : !entry->defaultValue.isEmpty() ? paramString(s: entry->defaultValue, e: entry, i) |
352 | : defaultValue(t: entry->type); |
353 | |
354 | if (!entry->signalList.isEmpty()) { |
355 | stream() << " " << innerItemVarStr << " = " << newInnerItem(entry, key: paramString(s: key, e: entry, i), defaultValue: defaultStr, cfg: cfg(), param: argBracket) << '\n'; |
356 | } |
357 | |
358 | const QString itemVarStr = itemPath(e: entry, cfg: cfg()) + argBracket; |
359 | |
360 | stream() << " " << itemVarStr << " = " << newItem(entry, key: paramString(s: key, e: entry, i), defaultValue: defaultStr, cfg: cfg(), param: 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(t: 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(e: entry, cfg: cfg(), itemVarStr, i: 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(')'), after: QLatin1String("%1" )).arg(a: 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(re: QRegularExpression(QStringLiteral("\\W" ))); |
414 | if (!mConfigGroupList.contains(str: parentGroup)) { |
415 | stream() << " KConfigGroup cg" << parentGroup << "(this->config(), " << paramString(group: entry->parentGroup, parameters: parseResult.parameters) << ");\n" ; |
416 | mConfigGroupList << parentGroup; |
417 | } |
418 | QString currentGroup = QString(mCurrentGroup).remove(re: QRegularExpression(QStringLiteral("\\W" ))); |
419 | if (!mConfigGroupList.contains(str: currentGroup)) { |
420 | stream() << " KConfigGroup cg" << currentGroup << " = cg" << QString(entry->parentGroup).remove(re: QRegularExpression(QStringLiteral("\\W" ))) |
421 | << ".group(" << paramString(group: mCurrentGroup, parameters: parseResult.parameters) << ");\n" ; |
422 | mConfigGroupList << currentGroup; |
423 | } |
424 | } else { |
425 | stream() << " setCurrentGroup( " << paramString(group: mCurrentGroup, parameters: 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(t&: parseResult.entries)) { |
467 | handleCurrentGroupChange(entry); |
468 | |
469 | const QString key = paramString(group: entry->key, parameters: parseResult.parameters); |
470 | if (!entry->code.isEmpty()) { |
471 | stream() << entry->code << '\n'; |
472 | } |
473 | createEnums(entry); |
474 | |
475 | stream() << itemDeclaration(e: entry, cfg: 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(e: entry, globalEnums: cfg().globalEnums); |
492 | } else { |
493 | stream() << cppType(t: entry->type); |
494 | } |
495 | |
496 | stream() << " " << getFunction(n: entry->name, className: cfg().className) << "(" ; |
497 | if (!entry->param.isEmpty()) { |
498 | stream() << " " << cppType(t: 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(e: entry, globalEnums: 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(n: entry->name, className: cfg().className) << "(" ; |
516 | if (!entry->param.isEmpty()) { |
517 | stream() << " " << cppType(t: entry->paramType) << " i " ; |
518 | } |
519 | stream() << ")" << Const() << '\n'; |
520 | startScope(); |
521 | memberImmutableBody(e: entry, globalEnums: 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(str: entry->name))) { |
530 | return; |
531 | } |
532 | |
533 | stream() << "void " << setFunction(n: entry->name, className: cfg().className) << "( " ; |
534 | if (!entry->param.isEmpty()) { |
535 | stream() << cppType(t: entry->paramType) << " i, " ; |
536 | } |
537 | |
538 | if (cfg().useEnumTypes && entry->type == QLatin1String("Enum" )) { |
539 | stream() << enumType(e: entry, globalEnums: cfg().globalEnums); |
540 | } else { |
541 | stream() << param(t: 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(e: 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(type: entry->type) << " *" << getFunction(n: entry->name, className: cfg().className) << "Item(" ; |
561 | if (!entry->param.isEmpty()) { |
562 | stream() << " " << cppType(t: entry->paramType) << " i " ; |
563 | } |
564 | stream() << ")\n" ; |
565 | startScope(); |
566 | stream() << " " << itemAccessorBody(e: entry, cfg: 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(t&: 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(t&: 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(str: n)) && !entry->defaultValue.isEmpty()) { |
595 | stream() << cppType(t) << " " << getDefaultFunction(n, className: cfg().className) << "_helper(" ; |
596 | if (!entry->param.isEmpty()) { |
597 | stream() << " " << cppType(t: entry->paramType) << " i " ; |
598 | } |
599 | stream() << ")" << Const() << '\n'; |
600 | startScope(); |
601 | stream() << memberGetDefaultBody(e: 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(t&: parseResult.signalList)) { |
636 | if (signal.modify) { |
637 | continue; |
638 | } |
639 | |
640 | stream() << " if (" << varPath(QStringLiteral("settingsChanged" ), cfg: cfg()) << ".contains(" << signalEnumName(signalName: 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(e: parseResult.entries.at(i), globalEnums: cfg().globalEnums) << ">(" ; |
651 | cast = true; |
652 | break; |
653 | } |
654 | } |
655 | } |
656 | stream() << varPath(n: argument.name, cfg: 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: 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: 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(t&: parseResult.signalList)) { |
692 | if (signal.modify) { |
693 | if (!modifySignalsWritten) { |
694 | stream() << " switch (signalFlag) {\n" ; |
695 | modifySignalsWritten = true; |
696 | } |
697 | stream() << " case " << signalEnumName(signalName: 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 | } |
720 | |