Changeset View
Changeset View
Standalone View
Standalone View
src/kconfig_compiler/KConfigSourceGenerator.cpp
- This file was added.
1 | /* This file is part of the KDE libraries | ||||
---|---|---|---|---|---|
2 | Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) | ||||
3 | Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> | ||||
4 | Copyright (c) 2003 Waldo Bastian <bastian@kde.org> | ||||
5 | Copyright (c) 2003 Zack Rusin <zack@kde.org> | ||||
6 | Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net> | ||||
7 | Copyright (c) 2008 Allen Winter <winter@kde.org> | ||||
8 | Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) | ||||
9 | | ||||
10 | This library is free software; you can redistribute it and/or | ||||
11 | modify it under the terms of the GNU Library General Public | ||||
12 | License as published by the Free Software Foundation; either | ||||
13 | version 2 of the License, or (at your option) any later version. | ||||
14 | | ||||
15 | This library is distributed in the hope that it will be useful, | ||||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
18 | Library General Public License for more details. | ||||
19 | | ||||
20 | You should have received a copy of the GNU Library General Public License | ||||
21 | along with this library; see the file COPYING.LIB. If not, write to | ||||
22 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||||
23 | Boston, MA 02110-1301, USA. | ||||
24 | */ | ||||
25 | | ||||
26 | #include "KConfigSourceGenerator.h" | ||||
27 | #include "KConfigCommonStructs.h" | ||||
28 | | ||||
29 | | ||||
30 | KConfigSourceGenerator::KConfigSourceGenerator( | ||||
31 | const QString& inputFile, | ||||
32 | const QString& baseDir, | ||||
33 | const KConfigXTParameters &cfg, | ||||
34 | ParseResult &parseResult) | ||||
35 | : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.sourceExtension, cfg, parseResult) | ||||
36 | { | ||||
37 | } | ||||
38 | | ||||
39 | void KConfigSourceGenerator::start() | ||||
40 | { | ||||
41 | KConfigCodeGeneratorBase::start(); | ||||
42 | stream << endl; | ||||
43 | createHeaders(); | ||||
44 | | ||||
45 | if (!cfg.nameSpace.isEmpty()) { | ||||
46 | stream << "using namespace " << cfg.nameSpace << ";"; | ||||
47 | stream << endl << endl; | ||||
48 | } | ||||
49 | | ||||
50 | createPrivateDPointerImplementation(); | ||||
51 | createSingletonImplementation(); | ||||
52 | createPreamble(); | ||||
53 | doConstructor(); | ||||
54 | doGetterSetterDPointerMode(); | ||||
55 | createDefaultValueGetterSetter(); | ||||
56 | createDestructor(); | ||||
57 | createNonModifyingSignalsHelper(); | ||||
58 | createSignalFlagsHandler(); | ||||
59 | includeMoc(); | ||||
60 | } | ||||
61 | | ||||
62 | void KConfigSourceGenerator::createHeaders() | ||||
63 | { | ||||
64 | QString headerName = cfg.baseName + QLatin1Char('.') + cfg.headerExtension; | ||||
65 | | ||||
66 | // TODO: Make addQuotes return a string instead of replacing it inplace. | ||||
67 | addQuotes(headerName); | ||||
68 | | ||||
69 | addHeaders({ headerName }); | ||||
70 | stream << endl; | ||||
71 | | ||||
72 | addHeaders(cfg.sourceIncludes); | ||||
73 | if (cfg.setUserTexts && cfg.translationSystem == KConfigXTParameters::KdeTranslation) { | ||||
74 | addHeaders({QStringLiteral("klocalizedstring.h")}); | ||||
75 | stream << endl; | ||||
76 | } | ||||
77 | | ||||
78 | // Header required by singleton implementation | ||||
79 | if (cfg.singleton) { | ||||
80 | addHeaders({QStringLiteral("qglobal.h"), QStringLiteral("QFile")}); | ||||
81 | | ||||
82 | // HACK: Add single line to fix test. | ||||
83 | if (cfg.singleton && parseResult.cfgFileNameArg) { | ||||
84 | stream << endl; | ||||
85 | } | ||||
86 | } | ||||
87 | | ||||
88 | if (cfg.singleton && parseResult.cfgFileNameArg) { | ||||
89 | addHeaders({QStringLiteral("QDebug")}); | ||||
90 | } | ||||
91 | | ||||
92 | if (cfg.singleton) { | ||||
93 | stream << endl; | ||||
94 | } | ||||
95 | } | ||||
96 | | ||||
97 | void KConfigSourceGenerator::createPrivateDPointerImplementation() | ||||
98 | { | ||||
99 | // private class implementation | ||||
100 | if (!cfg.dpointer) { | ||||
101 | return; | ||||
102 | } | ||||
103 | | ||||
104 | QString group; | ||||
105 | beginNamespaces(); | ||||
106 | stream << "class " << cfg.className << "Private" << endl; | ||||
107 | stream << "{" << endl; | ||||
108 | stream << " public:" << endl; | ||||
109 | | ||||
110 | // Create Members | ||||
111 | for (auto *entry : qAsConst(parseResult.entries)) { | ||||
112 | if (entry->group != group) { | ||||
113 | group = entry->group; | ||||
114 | stream << endl; | ||||
115 | stream << " // " << group << endl; | ||||
116 | } | ||||
117 | stream << " " << cppType(entry->type) << " " << varName(entry->name, cfg); | ||||
118 | if (!entry->param.isEmpty()) { | ||||
119 | stream << QStringLiteral("[%1]").arg(entry->paramMax + 1); | ||||
120 | } | ||||
121 | stream << ";" << endl; | ||||
122 | } | ||||
123 | stream << endl << " // items" << endl; | ||||
124 | | ||||
125 | // Create Items. | ||||
126 | for (auto *entry : qAsConst(parseResult.entries)) { | ||||
127 | const QString declType = entry->signalList.isEmpty() | ||||
128 | ? QString(cfg.inherits + QStringLiteral("::Item") + itemType(entry->type)) | ||||
129 | : QStringLiteral("KConfigCompilerSignallingItem"); | ||||
130 | | ||||
131 | stream << " " << declType << " *" << itemVar( entry, cfg ); | ||||
132 | if (!entry->param.isEmpty()) { | ||||
133 | stream << QStringLiteral("[%1]").arg(entry->paramMax + 1); | ||||
134 | } | ||||
135 | stream << ";" << endl; | ||||
136 | } | ||||
137 | | ||||
138 | if (parseResult.hasNonModifySignals) { | ||||
139 | stream << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl; | ||||
140 | } | ||||
141 | | ||||
142 | stream << "};" << endl << endl; | ||||
143 | endNamespaces(); | ||||
144 | } | ||||
145 | | ||||
146 | void KConfigSourceGenerator::createSingletonImplementation() | ||||
147 | { | ||||
148 | // Singleton implementation | ||||
149 | if (!cfg.singleton) { | ||||
150 | return; | ||||
151 | } | ||||
152 | | ||||
153 | beginNamespaces(); | ||||
154 | stream << "class " << cfg.className << "Helper" << endl; | ||||
155 | stream << '{' << endl; | ||||
156 | stream << " public:" << endl; | ||||
157 | stream << " " << cfg.className << "Helper() : q(nullptr) {}" << endl; | ||||
158 | stream << " ~" << cfg.className << "Helper() { delete q; }" << endl; | ||||
159 | stream << " " << cfg.className << "Helper(const " << cfg.className << "Helper&) = delete;" << endl; | ||||
160 | stream << " " << cfg.className << "Helper& operator=(const " << cfg.className << "Helper&) = delete;" << endl; | ||||
161 | stream << " " << cfg.className << " *q;" << endl; | ||||
162 | stream << "};" << endl; | ||||
163 | endNamespaces(); | ||||
164 | | ||||
165 | stream << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl; | ||||
166 | | ||||
167 | stream << cfg.className << " *" << cfg.className << "::self()" << endl; | ||||
168 | stream << "{" << endl; | ||||
169 | if (parseResult.cfgFileNameArg) { | ||||
170 | stream << " if (!s_global" << cfg.className << "()->q)" << endl; | ||||
171 | stream << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl; | ||||
172 | } else { | ||||
173 | stream << " if (!s_global" << cfg.className << "()->q) {" << endl; | ||||
174 | stream << " new " << cfg.className << ';' << endl; | ||||
175 | stream << " s_global" << cfg.className << "()->q->read();" << endl; | ||||
176 | stream << " }" << endl << endl; | ||||
177 | } | ||||
178 | stream << " return s_global" << cfg.className << "()->q;" << endl; | ||||
179 | stream << "}" << endl << endl; | ||||
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 << ")" << endl; | ||||
184 | stream << "{" << endl; | ||||
185 | stream << " if (s_global" << cfg.className << "()->q) {" << endl; | ||||
186 | stream << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl; | ||||
187 | stream << " return;" << endl; | ||||
188 | stream << " }" << endl; | ||||
189 | stream << " new " << cfg.className << "("; | ||||
190 | if (isString) { | ||||
191 | stream << "KSharedConfig::openConfig(" << arg << ")"; | ||||
192 | } else { | ||||
193 | stream << "std::move(" << arg << ")"; | ||||
194 | } | ||||
195 | stream << ");" << endl; | ||||
196 | stream << " s_global" << cfg.className << "()->q->read();" << endl; | ||||
197 | stream << "}" << endl << endl; | ||||
198 | }; | ||||
199 | instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true); | ||||
200 | instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false); | ||||
201 | } | ||||
202 | } | ||||
203 | | ||||
204 | void KConfigSourceGenerator::createPreamble() | ||||
205 | { | ||||
206 | QString cppPreamble; | ||||
207 | for (const auto entry : qAsConst(parseResult.entries)) { | ||||
208 | if (entry->paramValues.isEmpty()) { | ||||
209 | continue; | ||||
210 | } | ||||
211 | | ||||
212 | cppPreamble += QStringLiteral("const char* const ") + cfg.className + QStringLiteral("::") + enumName(entry->param); | ||||
213 | cppPreamble += cfg.globalEnums | ||||
214 | ? QStringLiteral("ToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n") | ||||
215 | : QStringLiteral("::enumToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n"); | ||||
216 | } | ||||
217 | | ||||
218 | if (!cppPreamble.isEmpty()) { | ||||
219 | stream << cppPreamble << endl; | ||||
220 | } | ||||
221 | } | ||||
222 | | ||||
223 | void KConfigSourceGenerator::createConstructorParameterList() | ||||
224 | { | ||||
225 | if (parseResult.cfgFileNameArg) { | ||||
226 | if (!cfg.forceStringFilename) { | ||||
227 | stream << " KSharedConfig::Ptr config"; | ||||
228 | } else { | ||||
229 | stream << " const QString& config"; | ||||
230 | } | ||||
231 | stream << (parseResult.parameters.isEmpty() ? "" : ","); | ||||
232 | } | ||||
233 | | ||||
234 | for (QList<Param>::ConstIterator it = parseResult.parameters.constBegin(); | ||||
235 | it != parseResult.parameters.constEnd(); ++it) { | ||||
236 | if (it != parseResult.parameters.constBegin()) { | ||||
237 | stream << ","; | ||||
238 | } | ||||
239 | stream << " " << param((*it).type) << " " << (*it).name; | ||||
240 | } | ||||
241 | | ||||
242 | if (cfg.parentInConstructor) { | ||||
243 | if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) { | ||||
244 | stream << ","; | ||||
245 | } | ||||
246 | stream << " QObject *parent"; | ||||
247 | } | ||||
248 | | ||||
249 | } | ||||
250 | | ||||
251 | void KConfigSourceGenerator::createParentConstructorCall() | ||||
252 | { | ||||
253 | stream << cfg.inherits << "("; | ||||
254 | if (!parseResult.cfgFileName.isEmpty()) { | ||||
255 | stream << " QStringLiteral( \"" << parseResult.cfgFileName << "\" "; | ||||
256 | } | ||||
257 | if (parseResult.cfgFileNameArg) { | ||||
258 | if (! cfg.forceStringFilename) { | ||||
259 | stream << " std::move( config ) "; | ||||
260 | } else { | ||||
261 | stream << " config "; | ||||
262 | } | ||||
263 | } | ||||
264 | if (!parseResult.cfgFileName.isEmpty()) { | ||||
265 | stream << ") "; | ||||
266 | } | ||||
267 | stream << ")" << endl; | ||||
268 | } | ||||
269 | | ||||
270 | void KConfigSourceGenerator::createInitializerList() | ||||
271 | { | ||||
272 | for (const auto ¶meter : qAsConst(parseResult.parameters)) { | ||||
273 | stream << " , mParam" << parameter.name << "(" << parameter.name << ")" << endl; | ||||
274 | } | ||||
275 | | ||||
276 | if (parseResult.hasNonModifySignals && !cfg.dpointer) { | ||||
277 | stream << " , " << varName(QStringLiteral("settingsChanged"), cfg) << "(0)" << endl; | ||||
278 | } | ||||
279 | } | ||||
280 | | ||||
281 | void KConfigSourceGenerator::createEnums(const CfgEntry *entry) | ||||
282 | { | ||||
283 | if (entry->type != QLatin1String("Enum")) { | ||||
284 | return; | ||||
285 | } | ||||
286 | stream << " QList<" << cfg.inherits << "::ItemEnum::Choice> values" << entry->name << ";" << endl; | ||||
287 | | ||||
288 | for (const auto &choice : qAsConst(entry->choices.choices)) { | ||||
289 | stream << " {" << endl; | ||||
290 | stream << " " << cfg.inherits << "::ItemEnum::Choice choice;" << endl; | ||||
291 | stream << " choice.name = QStringLiteral(\"" << choice.name << "\");" << endl; | ||||
292 | if (cfg.setUserTexts) { | ||||
293 | if (!choice.label.isEmpty()) { | ||||
294 | stream << " choice.label = " | ||||
295 | << translatedString(cfg, choice.label, choice.context) | ||||
296 | << ";" << endl; | ||||
297 | } | ||||
298 | if (!choice.toolTip.isEmpty()) { | ||||
299 | stream << " choice.toolTip = " | ||||
300 | << translatedString(cfg, choice.toolTip, choice.context) | ||||
301 | << ";" << endl; | ||||
302 | } | ||||
303 | if (!choice.whatsThis.isEmpty()) { | ||||
304 | stream << " choice.whatsThis = " | ||||
305 | << translatedString(cfg, choice.whatsThis, choice.context) | ||||
306 | << ";" << endl; | ||||
307 | } | ||||
308 | } | ||||
309 | stream << " values" << entry->name << ".append( choice );" << endl; | ||||
310 | stream << " }" << endl; | ||||
311 | } | ||||
312 | } | ||||
313 | | ||||
314 | void KConfigSourceGenerator::createNormalEntry(const CfgEntry *entry, const QString& key) | ||||
315 | { | ||||
316 | stream << " " << itemPath(entry, cfg) << " = " | ||||
317 | << newItem(entry, key, entry->defaultValue, cfg) << endl; | ||||
318 | | ||||
319 | if (!entry->min.isEmpty()) { | ||||
320 | stream << " " << itemPath(entry, cfg) << "->setMinValue(" << entry->min << ");" << endl; | ||||
321 | } | ||||
322 | if (!entry->max.isEmpty()) { | ||||
323 | stream << " " << itemPath(entry, cfg) << "->setMaxValue(" << entry->max << ");" << endl; | ||||
324 | } | ||||
325 | | ||||
326 | if (cfg.setUserTexts) { | ||||
327 | stream << userTextsFunctions(entry, cfg); | ||||
328 | } | ||||
329 | | ||||
330 | if (cfg.allNotifiers || cfg.notifiers.contains(entry->name)) { | ||||
331 | stream << " " << itemPath(entry, cfg) << "->setWriteFlags(KConfigBase::Notify);" << endl; | ||||
332 | } | ||||
333 | | ||||
334 | stream << " addItem( " << itemPath(entry, cfg); | ||||
335 | QString quotedName = entry->name; | ||||
336 | addQuotes(quotedName); | ||||
337 | if (quotedName != key) { | ||||
338 | stream << ", QStringLiteral( \"" << entry->name << "\" )"; | ||||
339 | } | ||||
340 | stream << " );" << endl; | ||||
341 | } | ||||
342 | | ||||
343 | void KConfigSourceGenerator::createIndexedEntry(const CfgEntry *entry, const QString& key) | ||||
344 | { | ||||
345 | for (int i = 0; i <= entry->paramMax; i++) { | ||||
346 | QString itemVarStr(itemPath(entry, cfg) + QStringLiteral("[%1]").arg(i)); | ||||
347 | | ||||
348 | QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i] | ||||
349 | : !entry->defaultValue.isEmpty() ? paramString(entry->defaultValue, entry, i) | ||||
350 | : defaultValue(entry->type); | ||||
351 | | ||||
352 | stream << " " << itemVarStr << " = " | ||||
353 | << newItem(entry, paramString(key, entry, i), defaultStr, cfg, QStringLiteral("[%1]").arg(i)) << endl; | ||||
354 | | ||||
355 | if (cfg.setUserTexts) { | ||||
356 | stream << userTextsFunctions(entry, cfg, itemVarStr, entry->paramName); | ||||
357 | } | ||||
358 | | ||||
359 | // Make mutators for enum parameters work by adding them with $(..) replaced by the | ||||
360 | // param name. The check for isImmutable in the set* functions doesn't have the param | ||||
361 | // name available, just the corresponding enum value (int), so we need to store the | ||||
362 | // param names in a separate static list!. | ||||
363 | const bool isEnum = entry->paramType == QLatin1String("Enum"); | ||||
364 | const QString arg = isEnum ? entry->paramValues[i] : QString::number(i); | ||||
365 | | ||||
366 | QString paramName = entry->paramName; | ||||
367 | | ||||
368 | stream << " addItem( " << itemVarStr << ", QStringLiteral( \""; | ||||
369 | stream << paramName.replace(QStringLiteral("$(") + entry->param + QLatin1Char(')'), QLatin1String("%1")).arg( arg ); | ||||
370 | stream << "\" ) );" << endl; | ||||
371 | } | ||||
372 | } | ||||
373 | | ||||
374 | void KConfigSourceGenerator::handleCurrentGroupChange(const CfgEntry *entry) | ||||
375 | { | ||||
376 | if (entry->group == mCurrentGroup) { | ||||
377 | return; | ||||
378 | } | ||||
379 | | ||||
380 | // HACK: This fixes one spacing line in the diff. Remove this in the future and adapt the testcases. | ||||
381 | static bool first = true; | ||||
382 | if (!entry->group.isEmpty()) { | ||||
383 | if (!first) { | ||||
384 | stream << endl; | ||||
385 | } | ||||
386 | first = false; | ||||
387 | } | ||||
388 | | ||||
389 | mCurrentGroup = entry->group; | ||||
390 | stream << " setCurrentGroup( " << paramString(mCurrentGroup, parseResult.parameters) << " );"; | ||||
391 | stream << endl << endl; | ||||
392 | } | ||||
393 | | ||||
394 | void KConfigSourceGenerator::doConstructor() | ||||
395 | { | ||||
396 | // Constructor | ||||
397 | stream << cfg.className << "::" << cfg.className << "("; | ||||
398 | createConstructorParameterList(); | ||||
399 | stream << " )" << endl; | ||||
400 | stream << " : "; | ||||
401 | createParentConstructorCall(); | ||||
402 | createInitializerList(); | ||||
403 | | ||||
404 | stream << "{" << endl; | ||||
405 | | ||||
406 | if (cfg.parentInConstructor) { | ||||
407 | stream << " setParent(parent);" << endl; | ||||
408 | } | ||||
409 | | ||||
410 | if (cfg.dpointer) { | ||||
411 | stream << " d = new " << cfg.className << "Private;" << endl; | ||||
412 | if (parseResult.hasNonModifySignals) { | ||||
413 | stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; | ||||
414 | } | ||||
415 | } | ||||
416 | | ||||
417 | // Needed in case the singleton class is used as baseclass for | ||||
418 | // another singleton. | ||||
419 | if (cfg.singleton) { | ||||
420 | stream << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl; | ||||
421 | stream << " s_global" << cfg.className << "()->q = this;" << endl; | ||||
422 | } | ||||
423 | | ||||
424 | if (!parseResult.signalList.isEmpty()) { | ||||
425 | // this cast to base-class pointer-to-member is valid C++ | ||||
426 | // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/ | ||||
427 | stream << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction =" | ||||
428 | << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&" | ||||
429 | << cfg.className << "::itemChanged);" << endl; | ||||
430 | | ||||
431 | stream << endl; | ||||
432 | } | ||||
433 | | ||||
434 | for (auto *entry : qAsConst(parseResult.entries)) { | ||||
435 | handleCurrentGroupChange(entry); | ||||
436 | | ||||
437 | const QString key = paramString(entry->key, parseResult.parameters); | ||||
438 | if (!entry->code.isEmpty()) { | ||||
439 | stream << entry->code << endl; | ||||
440 | } | ||||
441 | createEnums(entry); | ||||
442 | | ||||
443 | if (!cfg.dpointer) { | ||||
444 | stream << itemDeclaration(entry, cfg); | ||||
445 | } | ||||
446 | | ||||
447 | if (entry->param.isEmpty()) { | ||||
448 | createNormalEntry(entry, key); | ||||
449 | } else { | ||||
450 | createIndexedEntry(entry, key); | ||||
451 | } | ||||
452 | } | ||||
453 | | ||||
454 | stream << "}" << endl << endl; | ||||
455 | } | ||||
456 | | ||||
457 | void KConfigSourceGenerator::createGetterDPointerMode(const CfgEntry *entry) | ||||
458 | { | ||||
459 | // Accessor | ||||
460 | if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) { | ||||
461 | stream << enumType(entry, cfg.globalEnums); | ||||
462 | } else { | ||||
463 | stream << cppType(entry->type); | ||||
464 | } | ||||
465 | | ||||
466 | stream << " " << getFunction(entry->name, cfg.className) << "("; | ||||
467 | if (!entry->param.isEmpty()) { | ||||
468 | stream << " " << cppType(entry->paramType) << " i "; | ||||
469 | } | ||||
470 | stream << ")" << Const << endl; | ||||
471 | | ||||
472 | // function body inline only if not using dpointer | ||||
473 | // for BC mode | ||||
474 | startScope(); | ||||
475 | // HACK: Fix memberAccessorBody | ||||
476 | stream << " " << memberAccessorBody(entry, cfg.globalEnums); | ||||
477 | endScope(); | ||||
478 | stream << endl; | ||||
479 | } | ||||
480 | | ||||
481 | void KConfigSourceGenerator::createSetterDPointerMode(const CfgEntry *entry) | ||||
482 | { | ||||
483 | // Manipulator | ||||
484 | if (!(cfg.allMutators || cfg.mutators.contains(entry->name))) { | ||||
485 | return; | ||||
486 | } | ||||
487 | | ||||
488 | stream << "void " << setFunction(entry->name, cfg.className) << "( "; | ||||
489 | if (!entry->param.isEmpty()) { | ||||
490 | stream << cppType(entry->paramType) << " i, "; | ||||
491 | } | ||||
492 | | ||||
493 | if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) { | ||||
494 | stream << enumType(entry, cfg.globalEnums); | ||||
495 | } else { | ||||
496 | stream << param(entry->type); | ||||
497 | } | ||||
498 | stream << " v )" << endl; | ||||
499 | | ||||
500 | // function body inline only if not using dpointer | ||||
501 | // for BC mode | ||||
502 | startScope(); | ||||
503 | memberMutatorBody(entry); | ||||
504 | endScope(); | ||||
505 | stream << endl; | ||||
506 | } | ||||
507 | | ||||
508 | void KConfigSourceGenerator::createItemGetterDPointerMode(const CfgEntry *entry) | ||||
509 | { | ||||
510 | // Item accessor | ||||
511 | if (!cfg.itemAccessors) { | ||||
512 | return; | ||||
513 | } | ||||
514 | stream << endl; | ||||
515 | stream << cfg.inherits << "::Item" << itemType(entry->type) << " *" | ||||
516 | << getFunction(entry->name, cfg.className) << "Item("; | ||||
517 | if (!entry->param.isEmpty()) { | ||||
518 | stream << " " << cppType(entry->paramType) << " i "; | ||||
519 | } | ||||
520 | stream << ")" << endl; | ||||
521 | startScope(); | ||||
522 | stream << " " << itemAccessorBody(entry, cfg); | ||||
523 | endScope(); | ||||
524 | } | ||||
525 | | ||||
526 | void KConfigSourceGenerator::doGetterSetterDPointerMode() | ||||
527 | { | ||||
528 | if (!cfg.dpointer) { | ||||
529 | return; | ||||
530 | } | ||||
531 | | ||||
532 | // setters and getters go in Cpp if in dpointer mode | ||||
533 | for (auto *entry : qAsConst(parseResult.entries)) { | ||||
534 | createSetterDPointerMode(entry); | ||||
535 | createGetterDPointerMode(entry); | ||||
536 | createItemGetterDPointerMode(entry); | ||||
537 | stream << endl; | ||||
538 | } | ||||
539 | } | ||||
540 | | ||||
541 | void KConfigSourceGenerator::createDefaultValueGetterSetter() | ||||
542 | { | ||||
543 | // default value getters always go in Cpp | ||||
544 | for (auto *entry : qAsConst(parseResult.entries)) { | ||||
545 | QString n = entry->name; | ||||
546 | QString t = entry->type; | ||||
547 | | ||||
548 | // Default value Accessor, as "helper" function | ||||
549 | if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !entry->defaultValue.isEmpty()) { | ||||
550 | stream << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper("; | ||||
551 | if (!entry->param.isEmpty()) { | ||||
552 | stream << " " << cppType(entry->paramType) << " i "; | ||||
553 | } | ||||
554 | stream << ")" << Const << endl; | ||||
555 | startScope(); | ||||
556 | stream << memberGetDefaultBody(entry) << endl; | ||||
557 | endScope(); | ||||
558 | stream << endl; | ||||
559 | } | ||||
560 | } | ||||
561 | } | ||||
562 | | ||||
563 | void KConfigSourceGenerator::createDestructor() | ||||
564 | { | ||||
565 | stream << cfg.className << "::~" << cfg.className << "()" << endl; | ||||
566 | startScope(); | ||||
567 | if (cfg.dpointer) { | ||||
568 | stream << " delete d;" << endl; | ||||
569 | } | ||||
570 | if (cfg.singleton) { | ||||
571 | stream << " s_global" << cfg.className << "()->q = nullptr;" << endl; | ||||
572 | } | ||||
573 | endScope(); | ||||
574 | stream << endl; | ||||
575 | } | ||||
576 | | ||||
577 | void KConfigSourceGenerator::createNonModifyingSignalsHelper() | ||||
578 | { | ||||
579 | if (!parseResult.hasNonModifySignals) { | ||||
580 | return; | ||||
581 | } | ||||
582 | stream << "bool " << cfg.className << "::" << "usrSave()" << endl; | ||||
583 | startScope(); | ||||
584 | stream << " const bool res = " << cfg.inherits << "::usrSave();" << endl; | ||||
585 | stream << " if (!res) return false;" << endl << endl; | ||||
586 | for (const Signal &signal : qAsConst(parseResult.signalList)) { | ||||
587 | if (signal.modify) { | ||||
588 | continue; | ||||
589 | } | ||||
590 | | ||||
591 | stream << " if ( " << varPath(QStringLiteral("settingsChanged"), cfg) << " & " << signalEnumName(signal.name) << " )" << endl; | ||||
592 | stream << " Q_EMIT " << signal.name << "("; | ||||
593 | QList<Param>::ConstIterator it, itEnd = signal.arguments.constEnd(); | ||||
594 | for (it = signal.arguments.constBegin(); it != itEnd;) { | ||||
595 | Param argument = *it; | ||||
596 | bool cast = false; | ||||
597 | if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) { | ||||
598 | for (int i = 0, end = parseResult.entries.count(); i < end; ++i) { | ||||
599 | if (parseResult.entries.at(i)->name == argument.name) { | ||||
600 | stream << "static_cast<" << enumType(parseResult.entries.at(i), cfg.globalEnums) << ">("; | ||||
601 | cast = true; | ||||
602 | break; | ||||
603 | } | ||||
604 | } | ||||
605 | } | ||||
606 | stream << varPath(argument.name, cfg); | ||||
607 | if (cast) { | ||||
608 | stream << ")"; | ||||
609 | } | ||||
610 | if (++it != itEnd) { | ||||
611 | stream << ", "; | ||||
612 | } | ||||
613 | } | ||||
614 | | ||||
615 | stream << ");" << endl; | ||||
616 | } | ||||
617 | | ||||
618 | stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; | ||||
619 | stream << " return true;" << endl; | ||||
620 | endScope(); | ||||
621 | } | ||||
622 | | ||||
623 | void KConfigSourceGenerator::createSignalFlagsHandler() | ||||
624 | { | ||||
625 | if (parseResult.signalList.isEmpty()) { | ||||
626 | return; | ||||
627 | } | ||||
628 | | ||||
629 | stream << endl; | ||||
630 | stream << "void " << cfg.className << "::" << "itemChanged(quint64 flags) {" << endl; | ||||
631 | if (parseResult.hasNonModifySignals) | ||||
632 | stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " |= flags;" << endl; | ||||
633 | | ||||
634 | if (!parseResult.signalList.isEmpty()) | ||||
635 | stream << endl; | ||||
636 | | ||||
637 | for (const Signal &signal : qAsConst(parseResult.signalList)) { | ||||
638 | if (signal.modify) { | ||||
639 | stream << " if ( flags & " << signalEnumName(signal.name) << " ) {" << endl; | ||||
640 | stream << " Q_EMIT " << signal.name << "();" << endl; | ||||
641 | stream << " }" << endl; | ||||
642 | } | ||||
643 | } | ||||
644 | | ||||
645 | stream << "}" << endl; | ||||
646 | } | ||||
647 | | ||||
648 | void KConfigSourceGenerator::includeMoc() { | ||||
649 | const QString mocFileName = cfg.baseName + QStringLiteral(".moc"); | ||||
650 | | ||||
651 | if (parseResult.signalList.count() || cfg.generateProperties) { | ||||
652 | // Add includemoc if they are signals defined. | ||||
653 | stream << endl; | ||||
654 | stream << "#include \"" << mocFileName << "\"" << endl; | ||||
655 | stream << endl; | ||||
656 | } | ||||
657 | } |