Changeset View
Changeset View
Standalone View
Standalone View
src/kconfig_compiler/kconfig_compiler.cpp
Show All 28 Lines | |||||
29 | #include <QCoreApplication> | 29 | #include <QCoreApplication> | ||
30 | #include <QFile> | 30 | #include <QFile> | ||
31 | #include <QFileInfo> | 31 | #include <QFileInfo> | ||
32 | #include <QSettings> | 32 | #include <QSettings> | ||
33 | #include <QTextStream> | 33 | #include <QTextStream> | ||
34 | #include <QDomAttr> | 34 | #include <QDomAttr> | ||
35 | #include <QRegularExpression> | 35 | #include <QRegularExpression> | ||
36 | #include <QStringList> | 36 | #include <QStringList> | ||
37 | 37 | #include <QCommandLineParser> | |||
38 | #include <qcommandlineparser.h> | 38 | #include <QCommandLineOption> | ||
39 | #include <qcommandlineoption.h> | | |||
40 | 39 | | |||
41 | #include <ostream> | 40 | #include <ostream> | ||
42 | #include <iostream> | 41 | #include <iostream> | ||
43 | #include <stdlib.h> | 42 | #include <stdlib.h> | ||
44 | 43 | | |||
45 | #include "../../kconfig_version.h" | 44 | #include "../../kconfig_version.h" | ||
45 | #include "KConfigParameters.h" | ||||
46 | #include "KConfigCommonStructs.h" | ||||
47 | #include "KConfigHeaderGenerator.h" | ||||
48 | #include "KConfigSourceGenerator.h" | ||||
49 | #include "KConfigXmlParser.h" | ||||
46 | 50 | | |||
47 | namespace | 51 | namespace | ||
48 | { | 52 | { | ||
49 | QTextStream cout(stdout); | 53 | QTextStream cout(stdout); | ||
50 | QTextStream cerr(stderr); | 54 | QTextStream cerr(stderr); | ||
51 | } | 55 | } | ||
52 | 56 | | |||
53 | QStringList allNames; | 57 | QString varName(const QString &n, const KConfigParameters &cfg) | ||
54 | QRegularExpression *validNameRegexp; | | |||
55 | QString This; | | |||
56 | QString Const; | | |||
57 | | ||||
58 | /** | | |||
59 | Configuration Compiler Configuration | | |||
60 | */ | | |||
61 | class CfgConfig | | |||
62 | { | | |||
63 | public: | | |||
64 | CfgConfig(const QString &codegenFilename) | | |||
65 | { | | |||
66 | // Configure the compiler with some settings | | |||
67 | QSettings codegenConfig(codegenFilename, QSettings::IniFormat); | | |||
68 | | ||||
69 | nameSpace = codegenConfig.value(QStringLiteral("NameSpace")).toString(); | | |||
70 | className = codegenConfig.value(QStringLiteral("ClassName")).toString(); | | |||
71 | if (className.isEmpty()) { | | |||
72 | cerr << "Class name missing" << endl; | | |||
73 | exit(1); | | |||
74 | } | | |||
75 | inherits = codegenConfig.value(QStringLiteral("Inherits")).toString(); | | |||
76 | if (inherits.isEmpty()) { | | |||
77 | inherits = QStringLiteral("KConfigSkeleton"); | | |||
78 | } | | |||
79 | visibility = codegenConfig.value(QStringLiteral("Visibility")).toString(); | | |||
80 | if (!visibility.isEmpty()) { | | |||
81 | visibility += ' '; | | |||
82 | } | | |||
83 | parentInConstructor = codegenConfig.value(QStringLiteral("ParentInConstructor"), false).toBool(); | | |||
84 | forceStringFilename = codegenConfig.value(QStringLiteral("ForceStringFilename"), false).toBool(); | | |||
85 | singleton = codegenConfig.value(QStringLiteral("Singleton"), false).toBool(); | | |||
86 | staticAccessors = singleton; | | |||
87 | customAddons = codegenConfig.value(QStringLiteral("CustomAdditions"), false).toBool(); | | |||
88 | memberVariables = codegenConfig.value(QStringLiteral("MemberVariables")).toString(); | | |||
89 | dpointer = (memberVariables == QLatin1String("dpointer")); | | |||
90 | headerIncludes = codegenConfig.value(QStringLiteral("IncludeFiles"), QStringList()).toStringList(); | | |||
91 | sourceIncludes = codegenConfig.value(QStringLiteral("SourceIncludeFiles"), QStringList()).toStringList(); | | |||
92 | mutators = codegenConfig.value(QStringLiteral("Mutators"), QStringList()).toStringList(); | | |||
93 | allMutators = ((mutators.count() == 1) && (mutators.at(0).toLower() == QLatin1String("true"))); | | |||
94 | itemAccessors = codegenConfig.value(QStringLiteral("ItemAccessors"), false).toBool(); | | |||
95 | setUserTexts = codegenConfig.value(QStringLiteral("SetUserTexts"), false).toBool(); | | |||
96 | defaultGetters = codegenConfig.value(QStringLiteral("DefaultValueGetters"), QStringList()).toStringList(); | | |||
97 | allDefaultGetters = (defaultGetters.count() == 1) && (defaultGetters.at(0).toLower() == QLatin1String("true")); | | |||
98 | notifiers = codegenConfig.value(QStringLiteral("Notifiers"), QStringList()).toStringList(); | | |||
99 | allNotifiers = ((notifiers.count() == 1) && (notifiers.at(0).toLower() == QLatin1String("true"))); | | |||
100 | globalEnums = codegenConfig.value(QStringLiteral("GlobalEnums"), false).toBool(); | | |||
101 | useEnumTypes = codegenConfig.value(QStringLiteral("UseEnumTypes"), false).toBool(); | | |||
102 | const QString trString = codegenConfig.value(QStringLiteral("TranslationSystem")).toString().toLower(); | | |||
103 | generateProperties = codegenConfig.value(QStringLiteral("GenerateProperties"), false).toBool(); | | |||
104 | if (trString == QLatin1String("kde")) { | | |||
105 | translationSystem = KdeTranslation; | | |||
106 | translationDomain = codegenConfig.value(QStringLiteral("TranslationDomain")).toString(); | | |||
107 | } else { | | |||
108 | if (!trString.isEmpty() && trString != QLatin1String("qt")) { | | |||
109 | cerr << "Unknown translation system, falling back to Qt tr()" << endl; | | |||
110 | } | | |||
111 | translationSystem = QtTranslation; | | |||
112 | } | | |||
113 | qCategoryLoggingName = codegenConfig.value(QStringLiteral("CategoryLoggingName"), QString()).toString(); | | |||
114 | headerExtension = codegenConfig.value(QStringLiteral("HeaderExtension"), QStringLiteral("h")).toString(); | | |||
115 | sourceExtension = codegenConfig.value(QStringLiteral("SourceExtension"), QStringLiteral("cpp")).toString(); | | |||
116 | } | | |||
117 | | ||||
118 | public: | | |||
119 | enum TranslationSystem { | | |||
120 | QtTranslation, | | |||
121 | KdeTranslation | | |||
122 | }; | | |||
123 | | ||||
124 | // These are read from the .kcfgc configuration file | | |||
125 | QString nameSpace; // The namespace for the class to be generated | | |||
126 | QString className; // The class name to be generated | | |||
127 | QString inherits; // The class the generated class inherits (if empty, from KConfigSkeleton) | | |||
128 | QString visibility; | | |||
129 | bool parentInConstructor; // The class has the optional parent parameter in its constructor | | |||
130 | bool forceStringFilename; | | |||
131 | bool singleton; // The class will be a singleton | | |||
132 | bool staticAccessors; // provide or not static accessors | | |||
133 | bool customAddons; | | |||
134 | QString memberVariables; | | |||
135 | QStringList headerIncludes; | | |||
136 | QStringList sourceIncludes; | | |||
137 | QStringList mutators; | | |||
138 | QStringList defaultGetters; | | |||
139 | QStringList notifiers; | | |||
140 | QString qCategoryLoggingName; | | |||
141 | QString headerExtension; | | |||
142 | QString sourceExtension; | | |||
143 | bool allMutators; | | |||
144 | bool setUserTexts; | | |||
145 | bool allDefaultGetters; | | |||
146 | bool dpointer; | | |||
147 | bool globalEnums; | | |||
148 | bool useEnumTypes; | | |||
149 | bool itemAccessors; | | |||
150 | bool allNotifiers; | | |||
151 | TranslationSystem translationSystem; | | |||
152 | QString translationDomain; | | |||
153 | bool generateProperties; | | |||
154 | }; | | |||
155 | | ||||
156 | struct SignalArguments { | | |||
157 | QString type; | | |||
158 | QString variableName; | | |||
159 | }; | | |||
160 | | ||||
161 | class Signal | | |||
162 | { | | |||
163 | public: | | |||
164 | Signal() : modify(false) {} | | |||
165 | | ||||
166 | QString name; | | |||
167 | QString label; | | |||
168 | QList<SignalArguments> arguments; | | |||
169 | bool modify; | | |||
170 | }; | | |||
171 | | ||||
172 | class CfgEntry | | |||
173 | { | | |||
174 | public: | | |||
175 | struct Choice { | | |||
176 | QString name; | | |||
177 | QString context; | | |||
178 | QString label; | | |||
179 | QString toolTip; | | |||
180 | QString whatsThis; | | |||
181 | }; | | |||
182 | class Choices | | |||
183 | { | | |||
184 | public: | | |||
185 | Choices() {} | | |||
186 | Choices(const QList<Choice> &d, const QString &n, const QString &p) | | |||
187 | : prefix(p), choices(d), mName(n) | | |||
188 | { | | |||
189 | int i = n.indexOf(QLatin1String("::")); | | |||
190 | if (i >= 0) { | | |||
191 | mExternalQual = n.left(i + 2); | | |||
192 | } | | |||
193 | } | | |||
194 | QString prefix; | | |||
195 | QList<Choice> choices; | | |||
196 | const QString &name() const | | |||
197 | { | | |||
198 | return mName; | | |||
199 | } | | |||
200 | const QString &externalQualifier() const | | |||
201 | { | | |||
202 | return mExternalQual; | | |||
203 | } | | |||
204 | bool external() const | | |||
205 | { | | |||
206 | return !mExternalQual.isEmpty(); | | |||
207 | } | | |||
208 | private: | | |||
209 | QString mName; | | |||
210 | QString mExternalQual; | | |||
211 | }; | | |||
212 | | ||||
213 | CfgEntry(const QString &group, const QString &type, const QString &key, | | |||
214 | const QString &name, const QString &labelContext, const QString &label, | | |||
215 | const QString &toolTipContext, const QString &toolTip, const QString &whatsThisContext, const QString &whatsThis, const QString &code, | | |||
216 | const QString &defaultValue, const Choices &choices, const QList<Signal> &signalList, | | |||
217 | bool hidden) | | |||
218 | : mGroup(group), mType(type), mKey(key), mName(name), | | |||
219 | mLabelContext(labelContext), mLabel(label), mToolTipContext(toolTipContext), mToolTip(toolTip), | | |||
220 | mWhatsThisContext(whatsThisContext), mWhatsThis(whatsThis), | | |||
221 | mCode(code), mDefaultValue(defaultValue), mChoices(choices), | | |||
222 | mSignalList(signalList), mParamMax(0), mHidden(hidden) | | |||
223 | { | | |||
224 | } | | |||
225 | | ||||
226 | void setGroup(const QString &group) | | |||
227 | { | | |||
228 | mGroup = group; | | |||
229 | } | | |||
230 | QString group() const | | |||
231 | { | | |||
232 | return mGroup; | | |||
233 | } | | |||
234 | | ||||
235 | void setType(const QString &type) | | |||
236 | { | | |||
237 | mType = type; | | |||
238 | } | | |||
239 | QString type() const | | |||
240 | { | | |||
241 | return mType; | | |||
242 | } | | |||
243 | | ||||
244 | void setKey(const QString &key) | | |||
245 | { | | |||
246 | mKey = key; | | |||
247 | } | | |||
248 | QString key() const | | |||
249 | { | | |||
250 | return mKey; | | |||
251 | } | | |||
252 | | ||||
253 | void setName(const QString &name) | | |||
254 | { | | |||
255 | mName = name; | | |||
256 | } | | |||
257 | QString name() const | | |||
258 | { | | |||
259 | return mName; | | |||
260 | } | | |||
261 | | ||||
262 | void setLabelContext(const QString &labelContext) | | |||
263 | { | | |||
264 | mLabelContext = labelContext; | | |||
265 | } | | |||
266 | QString labelContext() const | | |||
267 | { | | |||
268 | return mLabelContext; | | |||
269 | } | | |||
270 | | ||||
271 | void setLabel(const QString &label) | | |||
272 | { | | |||
273 | mLabel = label; | | |||
274 | } | | |||
275 | QString label() const | | |||
276 | { | | |||
277 | return mLabel; | | |||
278 | } | | |||
279 | | ||||
280 | void setToolTipContext(const QString &toolTipContext) | | |||
281 | { | | |||
282 | mToolTipContext = toolTipContext; | | |||
283 | } | | |||
284 | QString toolTipContext() const | | |||
285 | { | | |||
286 | return mToolTipContext; | | |||
287 | } | | |||
288 | | ||||
289 | void setToolTip(const QString &toolTip) | | |||
290 | { | | |||
291 | mToolTip = toolTip; | | |||
292 | } | | |||
293 | QString toolTip() const | | |||
294 | { | | |||
295 | return mToolTip; | | |||
296 | } | | |||
297 | | ||||
298 | void setWhatsThisContext(const QString &whatsThisContext) | | |||
299 | { | | |||
300 | mWhatsThisContext = whatsThisContext; | | |||
301 | } | | |||
302 | QString whatsThisContext() const | | |||
303 | { | | |||
304 | return mWhatsThisContext; | | |||
305 | } | | |||
306 | | ||||
307 | void setWhatsThis(const QString &whatsThis) | | |||
308 | { | | |||
309 | mWhatsThis = whatsThis; | | |||
310 | } | | |||
311 | QString whatsThis() const | | |||
312 | { | | |||
313 | return mWhatsThis; | | |||
314 | } | | |||
315 | | ||||
316 | void setDefaultValue(const QString &d) | | |||
317 | { | | |||
318 | mDefaultValue = d; | | |||
319 | } | | |||
320 | QString defaultValue() const | | |||
321 | { | | |||
322 | return mDefaultValue; | | |||
323 | } | | |||
324 | | ||||
325 | void setCode(const QString &d) | | |||
326 | { | | |||
327 | mCode = d; | | |||
328 | } | | |||
329 | QString code() const | | |||
330 | { | | |||
331 | return mCode; | | |||
332 | } | | |||
333 | | ||||
334 | void setMinValue(const QString &d) | | |||
335 | { | | |||
336 | mMin = d; | | |||
337 | } | | |||
338 | QString minValue() const | | |||
339 | { | | |||
340 | return mMin; | | |||
341 | } | | |||
342 | | ||||
343 | void setMaxValue(const QString &d) | | |||
344 | { | | |||
345 | mMax = d; | | |||
346 | } | | |||
347 | QString maxValue() const | | |||
348 | { | | |||
349 | return mMax; | | |||
350 | } | | |||
351 | | ||||
352 | void setParam(const QString &d) | | |||
353 | { | | |||
354 | mParam = d; | | |||
355 | } | | |||
356 | QString param() const | | |||
357 | { | | |||
358 | return mParam; | | |||
359 | } | | |||
360 | | ||||
361 | void setParamName(const QString &d) | | |||
362 | { | | |||
363 | mParamName = d; | | |||
364 | } | | |||
365 | QString paramName() const | | |||
366 | { | | |||
367 | return mParamName; | | |||
368 | } | | |||
369 | | ||||
370 | void setParamType(const QString &d) | | |||
371 | { | | |||
372 | mParamType = d; | | |||
373 | } | | |||
374 | QString paramType() const | | |||
375 | { | | |||
376 | return mParamType; | | |||
377 | } | | |||
378 | | ||||
379 | void setChoices(const QList<Choice> &d, const QString &n, const QString &p) | | |||
380 | { | | |||
381 | mChoices = Choices(d, n, p); | | |||
382 | } | | |||
383 | Choices choices() const | | |||
384 | { | | |||
385 | return mChoices; | | |||
386 | } | | |||
387 | | ||||
388 | void setParamValues(const QStringList &d) | | |||
389 | { | | |||
390 | mParamValues = d; | | |||
391 | } | | |||
392 | QStringList paramValues() const | | |||
393 | { | | |||
394 | return mParamValues; | | |||
395 | } | | |||
396 | | ||||
397 | void setParamDefaultValues(const QStringList &d) | | |||
398 | { | | |||
399 | mParamDefaultValues = d; | | |||
400 | } | | |||
401 | QString paramDefaultValue(int i) const | | |||
402 | { | | |||
403 | return mParamDefaultValues[i]; | | |||
404 | } | | |||
405 | | ||||
406 | void setParamMax(int d) | | |||
407 | { | | |||
408 | mParamMax = d; | | |||
409 | } | | |||
410 | int paramMax() const | | |||
411 | { | | |||
412 | return mParamMax; | | |||
413 | } | | |||
414 | | ||||
415 | void setSignalList(const QList<Signal> &value) | | |||
416 | { | | |||
417 | mSignalList = value; | | |||
418 | } | | |||
419 | QList<Signal> signalList() const | | |||
420 | { | | |||
421 | return mSignalList; | | |||
422 | } | | |||
423 | | ||||
424 | bool hidden() const | | |||
425 | { | | |||
426 | return mHidden; | | |||
427 | } | | |||
428 | | ||||
429 | void dump() const | | |||
430 | { | | |||
431 | cerr << "<entry>" << endl; | | |||
432 | cerr << " group: " << mGroup << endl; | | |||
433 | cerr << " type: " << mType << endl; | | |||
434 | cerr << " key: " << mKey << endl; | | |||
435 | cerr << " name: " << mName << endl; | | |||
436 | cerr << " label context: " << mLabelContext << endl; | | |||
437 | cerr << " label: " << mLabel << endl; | | |||
438 | // whatsthis | | |||
439 | cerr << " code: " << mCode << endl; | | |||
440 | // cerr << " values: " << mValues.join(":") << endl; | | |||
441 | | ||||
442 | if (!param().isEmpty()) { | | |||
443 | cerr << " param name: " << mParamName << endl; | | |||
444 | cerr << " param type: " << mParamType << endl; | | |||
445 | cerr << " paramvalues: " << mParamValues.join(QChar::fromLatin1(':')) << endl; | | |||
446 | } | | |||
447 | cerr << " default: " << mDefaultValue << endl; | | |||
448 | cerr << " hidden: " << mHidden << endl; | | |||
449 | cerr << " min: " << mMin << endl; | | |||
450 | cerr << " max: " << mMax << endl; | | |||
451 | cerr << "</entry>" << endl; | | |||
452 | } | | |||
453 | | ||||
454 | private: | | |||
455 | QString mGroup; | | |||
456 | QString mType; | | |||
457 | QString mKey; | | |||
458 | QString mName; | | |||
459 | QString mLabelContext; | | |||
460 | QString mLabel; | | |||
461 | QString mToolTipContext; | | |||
462 | QString mToolTip; | | |||
463 | QString mWhatsThisContext; | | |||
464 | QString mWhatsThis; | | |||
465 | QString mCode; | | |||
466 | QString mDefaultValue; | | |||
467 | QString mParam; | | |||
468 | QString mParamName; | | |||
469 | QString mParamType; | | |||
470 | Choices mChoices; | | |||
471 | QList<Signal> mSignalList; | | |||
472 | QStringList mParamValues; | | |||
473 | QStringList mParamDefaultValues; | | |||
474 | int mParamMax; | | |||
475 | bool mHidden; | | |||
476 | QString mMin; | | |||
477 | QString mMax; | | |||
478 | }; | | |||
479 | | ||||
480 | class Param | | |||
481 | { | | |||
482 | public: | | |||
483 | QString name; | | |||
484 | QString type; | | |||
485 | }; | | |||
486 | | ||||
487 | // returns the name of an member variable | | |||
488 | // use itemPath to know the full path | | |||
489 | // like using d-> in case of dpointer | | |||
490 | static QString varName(const QString &n, const CfgConfig &cfg) | | |||
491 | { | 58 | { | ||
492 | QString result; | 59 | QString result; | ||
493 | if (!cfg.dpointer) { | 60 | if (!cfg.dpointer) { | ||
494 | result = QChar::fromLatin1('m') + n; | 61 | result = QChar::fromLatin1('m') + n; | ||
495 | result[1] = result[1].toUpper(); | 62 | result[1] = result[1].toUpper(); | ||
496 | } else { | 63 | } else { | ||
497 | result = n; | 64 | result = n; | ||
498 | result[0] = result[0].toLower(); | 65 | result[0] = result[0].toLower(); | ||
499 | } | 66 | } | ||
500 | return result; | 67 | return result; | ||
501 | } | 68 | } | ||
502 | 69 | | |||
503 | static QString varPath(const QString &n, const CfgConfig &cfg) | 70 | QString varPath(const QString &n, const KConfigParameters &cfg) | ||
504 | { | 71 | { | ||
505 | QString result; | 72 | QString result; | ||
506 | if (cfg.dpointer) { | 73 | if (cfg.dpointer) { | ||
507 | result = "d->" + varName(n, cfg); | 74 | result = "d->" + varName(n, cfg); | ||
508 | } else { | 75 | } else { | ||
509 | result = varName(n, cfg); | 76 | result = varName(n, cfg); | ||
510 | } | 77 | } | ||
511 | return result; | 78 | return result; | ||
512 | } | 79 | } | ||
513 | 80 | | |||
514 | static QString enumName(const QString &n) | 81 | QString enumName(const QString &n) | ||
515 | { | 82 | { | ||
516 | QString result = QLatin1String("Enum") + n; | 83 | QString result = QLatin1String("Enum") + n; | ||
517 | result[4] = result[4].toUpper(); | 84 | result[4] = result[4].toUpper(); | ||
518 | return result; | 85 | return result; | ||
519 | } | 86 | } | ||
520 | 87 | | |||
521 | static QString enumName(const QString &n, const CfgEntry::Choices &c) | 88 | QString enumName(const QString &n, const CfgEntry::Choices &c) | ||
522 | { | 89 | { | ||
523 | QString result = c.name(); | 90 | QString result = c.name(); | ||
524 | if (result.isEmpty()) { | 91 | if (result.isEmpty()) { | ||
525 | result = QLatin1String("Enum") + n; | 92 | result = QLatin1String("Enum") + n; | ||
526 | result[4] = result[4].toUpper(); | 93 | result[4] = result[4].toUpper(); | ||
527 | } | 94 | } | ||
528 | return result; | 95 | return result; | ||
529 | } | 96 | } | ||
530 | 97 | | |||
531 | static QString enumType(const CfgEntry *e, bool globalEnums) | 98 | QString enumType(const CfgEntry *e, bool globalEnums) | ||
532 | { | 99 | { | ||
533 | QString result = e->choices().name(); | 100 | QString result = e->choices.name(); | ||
534 | if (result.isEmpty()) { | 101 | if (result.isEmpty()) { | ||
535 | result = QLatin1String("Enum") + e->name(); | 102 | result = QLatin1String("Enum") + e->name; | ||
536 | if (!globalEnums) { | 103 | if (!globalEnums) { | ||
537 | result += QLatin1String("::type"); | 104 | result += QLatin1String("::type"); | ||
538 | } | 105 | } | ||
539 | result[4] = result[4].toUpper(); | 106 | result[4] = result[4].toUpper(); | ||
540 | } | 107 | } | ||
541 | return result; | 108 | return result; | ||
542 | } | 109 | } | ||
543 | 110 | | |||
544 | static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) | 111 | QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) | ||
545 | { | 112 | { | ||
546 | QString result = c.name(); | 113 | QString result = c.name(); | ||
547 | if (result.isEmpty()) { | 114 | if (result.isEmpty()) { | ||
548 | result = QLatin1String("Enum") + n + QLatin1String("::"); | 115 | result = QLatin1String("Enum") + n + QLatin1String("::"); | ||
549 | result[4] = result[4].toUpper(); | 116 | result[4] = result[4].toUpper(); | ||
550 | } else if (c.external()) { | 117 | } else if (c.external()) { | ||
551 | result = c.externalQualifier(); | 118 | result = c.externalQualifier(); | ||
552 | } else { | 119 | } else { | ||
553 | result.clear(); | 120 | result.clear(); | ||
554 | } | 121 | } | ||
555 | return result; | 122 | return result; | ||
556 | } | 123 | } | ||
557 | 124 | | |||
558 | static QString setFunction(const QString &n, const QString &className = QString()) | 125 | QString setFunction(const QString &n, const QString &className) | ||
559 | { | 126 | { | ||
560 | QString result = QLatin1String("set") + n; | 127 | QString result = QLatin1String("set") + n; | ||
561 | result[3] = result[3].toUpper(); | 128 | result[3] = result[3].toUpper(); | ||
562 | 129 | | |||
563 | if (!className.isEmpty()) { | 130 | if (!className.isEmpty()) { | ||
564 | result = className + QLatin1String("::") + result; | 131 | result = className + QLatin1String("::") + result; | ||
565 | } | 132 | } | ||
566 | return result; | 133 | return result; | ||
567 | } | 134 | } | ||
568 | 135 | | |||
569 | static QString changeSignalName(const QString &n) | 136 | QString changeSignalName(const QString &n) | ||
570 | { | 137 | { | ||
571 | return n+QStringLiteral("Changed"); | 138 | return n+QStringLiteral("Changed"); | ||
572 | } | 139 | } | ||
573 | 140 | | |||
574 | static QString getDefaultFunction(const QString &n, const QString &className = QString()) | 141 | QString getDefaultFunction(const QString &n, const QString &className) | ||
575 | { | 142 | { | ||
576 | QString result = QLatin1String("default") + n + QLatin1String("Value"); | 143 | QString result = QLatin1String("default") + n + QLatin1String("Value"); | ||
577 | result[7] = result[7].toUpper(); | 144 | result[7] = result[7].toUpper(); | ||
578 | 145 | | |||
579 | if (!className.isEmpty()) { | 146 | if (!className.isEmpty()) { | ||
580 | result = className + QLatin1String("::") + result; | 147 | result = className + QLatin1String("::") + result; | ||
581 | } | 148 | } | ||
582 | return result; | 149 | return result; | ||
583 | } | 150 | } | ||
584 | 151 | | |||
585 | static QString getFunction(const QString &n, const QString &className = QString()) | 152 | QString getFunction(const QString &n, const QString &className) | ||
586 | { | 153 | { | ||
587 | QString result = n; | 154 | QString result = n; | ||
588 | result[0] = result[0].toLower(); | 155 | result[0] = result[0].toLower(); | ||
589 | 156 | | |||
590 | if (!className.isEmpty()) { | 157 | if (!className.isEmpty()) { | ||
591 | result = className + QLatin1String("::") + result; | 158 | result = className + QLatin1String("::") + result; | ||
592 | } | 159 | } | ||
593 | return result; | 160 | return result; | ||
594 | } | 161 | } | ||
595 | 162 | | |||
596 | static void addQuotes(QString &s) | 163 | void addQuotes(QString &s) | ||
597 | { | 164 | { | ||
598 | if (!s.startsWith(QLatin1Char('"'))) { | 165 | if (!s.startsWith(QLatin1Char('"'))) { | ||
599 | s.prepend(QLatin1Char('"')); | 166 | s.prepend(QLatin1Char('"')); | ||
600 | } | 167 | } | ||
601 | if (!s.endsWith(QLatin1Char('"'))) { | 168 | if (!s.endsWith(QLatin1Char('"'))) { | ||
602 | s.append(QLatin1Char('"')); | 169 | s.append(QLatin1Char('"')); | ||
603 | } | 170 | } | ||
604 | } | 171 | } | ||
605 | 172 | | |||
606 | static QString quoteString(const QString &s) | 173 | static QString quoteString(const QString &s) | ||
607 | { | 174 | { | ||
608 | QString r = s; | 175 | QString r = s; | ||
609 | r.replace(QLatin1Char('\\'), QLatin1String("\\\\")); | 176 | r.replace(QLatin1Char('\\'), QLatin1String("\\\\")); | ||
610 | r.replace(QLatin1Char('\"'), QLatin1String("\\\"")); | 177 | r.replace(QLatin1Char('\"'), QLatin1String("\\\"")); | ||
611 | r.remove(QLatin1Char('\r')); | 178 | r.remove(QLatin1Char('\r')); | ||
612 | r.replace(QLatin1Char('\n'), QLatin1String("\\n\"\n\"")); | 179 | r.replace(QLatin1Char('\n'), QLatin1String("\\n\"\n\"")); | ||
613 | return QLatin1Char('\"') + r + QLatin1Char('\"'); | 180 | return QLatin1Char('\"') + r + QLatin1Char('\"'); | ||
614 | } | 181 | } | ||
615 | 182 | | |||
616 | static QString literalString(const QString &s) | 183 | QString literalString(const QString &s) | ||
617 | { | 184 | { | ||
618 | bool isAscii = true; | 185 | bool isAscii = true; | ||
619 | for (int i = s.length(); i--;) | 186 | for (int i = s.length(); i--;) | ||
620 | if (s[i].unicode() > 127) { | 187 | if (s[i].unicode() > 127) { | ||
621 | isAscii = false; | 188 | isAscii = false; | ||
622 | } | 189 | } | ||
623 | 190 | | |||
624 | if (isAscii) { | 191 | if (isAscii) { | ||
625 | return QLatin1String("QStringLiteral( ") + quoteString(s) + QLatin1String(" )"); | 192 | return QLatin1String("QStringLiteral( ") + quoteString(s) + QLatin1String(" )"); | ||
626 | } else { | 193 | } else { | ||
627 | return QLatin1String("QString::fromUtf8( ") + quoteString(s) + QLatin1String(" )"); | 194 | return QLatin1String("QString::fromUtf8( ") + quoteString(s) + QLatin1String(" )"); | ||
628 | } | 195 | } | ||
629 | } | 196 | } | ||
630 | 197 | | |||
631 | static QString dumpNode(const QDomNode &node) | | |||
632 | { | | |||
633 | QString msg; | | |||
634 | QTextStream s(&msg, QIODevice::WriteOnly); | | |||
635 | node.save(s, 0); | | |||
636 | | ||||
637 | msg = msg.simplified(); | | |||
638 | if (msg.length() > 40) { | | |||
639 | return msg.left(37) + QLatin1String("..."); | | |||
640 | } | | |||
641 | return msg; | | |||
642 | } | | |||
643 | 198 | | |||
644 | static QString signalEnumName(const QString &signalName) | 199 | QString signalEnumName(const QString &signalName) | ||
645 | { | 200 | { | ||
646 | QString result; | 201 | QString result; | ||
647 | result = QLatin1String("signal") + signalName; | 202 | result = QLatin1String("signal") + signalName; | ||
648 | result[6] = result[6].toUpper(); | 203 | result[6] = result[6].toUpper(); | ||
649 | 204 | | |||
650 | return result; | 205 | return result; | ||
651 | } | 206 | } | ||
652 | 207 | | |||
653 | static void preProcessDefault(QString &defaultValue, const QString &name, | | |||
654 | const QString &type, | | |||
655 | const CfgEntry::Choices &choices, | | |||
656 | QString &code, const CfgConfig &cfg) | | |||
657 | { | | |||
658 | if (type == QLatin1String("String") && !defaultValue.isEmpty()) { | | |||
659 | defaultValue = literalString(defaultValue); | | |||
660 | | ||||
661 | } else if (type == QLatin1String("Path") && !defaultValue.isEmpty()) { | | |||
662 | defaultValue = literalString(defaultValue); | | |||
663 | } else if (type == QLatin1String("Url") && !defaultValue.isEmpty()) { | | |||
664 | // Use fromUserInput in order to support absolute paths and absolute urls, like KDE4's KUrl(QString) did. | | |||
665 | defaultValue = QLatin1String("QUrl::fromUserInput( ") + literalString(defaultValue) + QLatin1Char(')'); | | |||
666 | } else if ((type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty()) { | | |||
667 | QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); | | |||
668 | if (!code.isEmpty()) { | | |||
669 | cpp << endl; | | |||
670 | } | | |||
671 | | ||||
672 | if (type == QLatin1String("UrlList")) { | | |||
673 | cpp << " QList<QUrl> default" << name << ";" << endl; | | |||
674 | } else { | | |||
675 | cpp << " QStringList default" << name << ";" << endl; | | |||
676 | } | | |||
677 | const QStringList defaults = defaultValue.split(QLatin1Char(',')); | | |||
678 | QStringList::ConstIterator it; | | |||
679 | for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) { | | |||
680 | cpp << " default" << name << ".append( "; | | |||
681 | if (type == QLatin1String("UrlList")) { | | |||
682 | cpp << "QUrl::fromUserInput("; | | |||
683 | } | | |||
684 | cpp << "QString::fromUtf8( \"" << *it << "\" ) "; | | |||
685 | if (type == QLatin1String("UrlList")) { | | |||
686 | cpp << ") "; | | |||
687 | } | | |||
688 | cpp << ");" << endl; | | |||
689 | } | | |||
690 | defaultValue = QLatin1String("default") + name; | | |||
691 | | ||||
692 | } else if (type == QLatin1String("Color") && !defaultValue.isEmpty()) { | | |||
693 | const QRegularExpression colorRe(QRegularExpression::anchoredPattern( | | |||
694 | QStringLiteral("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?"))); | | |||
695 | | ||||
696 | if (colorRe.match(defaultValue).hasMatch()) { | | |||
697 | defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )"); | | |||
698 | } else { | | |||
699 | defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )"); | | |||
700 | } | | |||
701 | | ||||
702 | } else if (type == QLatin1String("Enum")) { | | |||
703 | QList<CfgEntry::Choice>::ConstIterator it; | | |||
704 | for (it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it) { | | |||
705 | if ((*it).name == defaultValue) { | | |||
706 | if (cfg.globalEnums && choices.name().isEmpty()) { | | |||
707 | defaultValue.prepend(choices.prefix); | | |||
708 | } else { | | |||
709 | defaultValue.prepend(enumTypeQualifier(name, choices) + choices.prefix); | | |||
710 | } | | |||
711 | break; | | |||
712 | } | | |||
713 | } | | |||
714 | | ||||
715 | } else if (type == QLatin1String("IntList")) { | | |||
716 | QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); | | |||
717 | if (!code.isEmpty()) { | | |||
718 | cpp << endl; | | |||
719 | } | | |||
720 | | ||||
721 | cpp << " QList<int> default" << name << ";" << endl; | | |||
722 | if (!defaultValue.isEmpty()) { | | |||
723 | const QStringList defaults = defaultValue.split(QLatin1Char(',')); | | |||
724 | QStringList::ConstIterator it; | | |||
725 | for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) { | | |||
726 | cpp << " default" << name << ".append( " << *it << " );" | | |||
727 | << endl; | | |||
728 | } | | |||
729 | } | | |||
730 | defaultValue = QLatin1String("default") + name; | | |||
731 | } | | |||
732 | } | | |||
733 | | ||||
734 | CfgEntry *parseEntry(const QString &group, const QDomElement &element, const CfgConfig &cfg) | | |||
735 | { | | |||
736 | bool defaultCode = false; | | |||
737 | QString type = element.attribute(QStringLiteral("type")); | | |||
738 | QString name = element.attribute(QStringLiteral("name")); | | |||
739 | QString key = element.attribute(QStringLiteral("key")); | | |||
740 | QString hidden = element.attribute(QStringLiteral("hidden")); | | |||
741 | QString labelContext; | | |||
742 | QString label; | | |||
743 | QString toolTipContext; | | |||
744 | QString toolTip; | | |||
745 | QString whatsThisContext; | | |||
746 | QString whatsThis; | | |||
747 | QString defaultValue; | | |||
748 | QString code; | | |||
749 | QString param; | | |||
750 | QString paramName; | | |||
751 | QString paramType; | | |||
752 | CfgEntry::Choices choices; | | |||
753 | QList<Signal> signalList; | | |||
754 | QStringList paramValues; | | |||
755 | QStringList paramDefaultValues; | | |||
756 | QString minValue; | | |||
757 | QString maxValue; | | |||
758 | int paramMax = 0; | | |||
759 | | ||||
760 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { | | |||
761 | QString tag = e.tagName(); | | |||
762 | if (tag == QLatin1String("label")) { | | |||
763 | label = e.text(); | | |||
764 | labelContext = e.attribute(QStringLiteral("context")); | | |||
765 | } else if (tag == QLatin1String("tooltip")) { | | |||
766 | toolTip = e.text(); | | |||
767 | toolTipContext = e.attribute(QStringLiteral("context")); | | |||
768 | } else if (tag == QLatin1String("whatsthis")) { | | |||
769 | whatsThis = e.text(); | | |||
770 | whatsThisContext = e.attribute(QStringLiteral("context")); | | |||
771 | } else if (tag == QLatin1String("min")) { | | |||
772 | minValue = e.text(); | | |||
773 | } else if (tag == QLatin1String("max")) { | | |||
774 | maxValue = e.text(); | | |||
775 | } else if (tag == QLatin1String("code")) { | | |||
776 | code = e.text(); | | |||
777 | } else if (tag == QLatin1String("parameter")) { | | |||
778 | param = e.attribute(QStringLiteral("name")); | | |||
779 | paramType = e.attribute(QStringLiteral("type")); | | |||
780 | if (param.isEmpty()) { | | |||
781 | cerr << "Parameter must have a name: " << dumpNode(e) << endl; | | |||
782 | return nullptr; | | |||
783 | } | | |||
784 | if (paramType.isEmpty()) { | | |||
785 | cerr << "Parameter must have a type: " << dumpNode(e) << endl; | | |||
786 | return nullptr; | | |||
787 | } | | |||
788 | if ((paramType == QLatin1String("Int")) || (paramType == QLatin1String("UInt"))) { | | |||
789 | bool ok; | | |||
790 | paramMax = e.attribute(QStringLiteral("max")).toInt(&ok); | | |||
791 | if (!ok) { | | |||
792 | cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): " | | |||
793 | << dumpNode(e) << endl; | | |||
794 | return nullptr; | | |||
795 | } | | |||
796 | } else if (paramType == QLatin1String("Enum")) { | | |||
797 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | | |||
798 | if (e2.tagName() == QLatin1String("values")) { | | |||
799 | for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) { | | |||
800 | if (e3.tagName() == QLatin1String("value")) { | | |||
801 | paramValues.append(e3.text()); | | |||
802 | } | | |||
803 | } | | |||
804 | break; | | |||
805 | } | | |||
806 | } | | |||
807 | if (paramValues.isEmpty()) { | | |||
808 | cerr << "No values specified for parameter '" << param | | |||
809 | << "'." << endl; | | |||
810 | return nullptr; | | |||
811 | } | | |||
812 | paramMax = paramValues.count() - 1; | | |||
813 | } else { | | |||
814 | cerr << "Parameter '" << param << "' has type " << paramType | | |||
815 | << " but must be of type int, uint or Enum." << endl; | | |||
816 | return nullptr; | | |||
817 | } | | |||
818 | } else if (tag == QLatin1String("default")) { | | |||
819 | if (e.attribute(QStringLiteral("param")).isEmpty()) { | | |||
820 | defaultValue = e.text(); | | |||
821 | if (e.attribute(QStringLiteral("code")) == QLatin1String("true")) { | | |||
822 | defaultCode = true; | | |||
823 | } | | |||
824 | } | | |||
825 | } else if (tag == QLatin1String("choices")) { | | |||
826 | QString name = e.attribute(QStringLiteral("name")); | | |||
827 | QString prefix = e.attribute(QStringLiteral("prefix")); | | |||
828 | QList<CfgEntry::Choice> chlist; | | |||
829 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | | |||
830 | if (e2.tagName() == QLatin1String("choice")) { | | |||
831 | CfgEntry::Choice choice; | | |||
832 | choice.name = e2.attribute(QStringLiteral("name")); | | |||
833 | if (choice.name.isEmpty()) { | | |||
834 | cerr << "Tag <choice> requires attribute 'name'." << endl; | | |||
835 | } | | |||
836 | for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) { | | |||
837 | if (e3.tagName() == QLatin1String("label")) { | | |||
838 | choice.label = e3.text(); | | |||
839 | choice.context = e3.attribute(QStringLiteral("context")); | | |||
840 | } | | |||
841 | if (e3.tagName() == QLatin1String("tooltip")) { | | |||
842 | choice.toolTip = e3.text(); | | |||
843 | choice.context = e3.attribute(QStringLiteral("context")); | | |||
844 | } | | |||
845 | if (e3.tagName() == QLatin1String("whatsthis")) { | | |||
846 | choice.whatsThis = e3.text(); | | |||
847 | choice.context = e3.attribute(QStringLiteral("context")); | | |||
848 | } | | |||
849 | } | | |||
850 | chlist.append(choice); | | |||
851 | } | | |||
852 | } | | |||
853 | choices = CfgEntry::Choices(chlist, name, prefix); | | |||
854 | } else if (tag == QLatin1String("emit")) { | | |||
855 | Signal signal; | | |||
856 | signal.name = e.attribute(QStringLiteral("signal")); | | |||
857 | signalList.append(signal); | | |||
858 | } | | |||
859 | } | | |||
860 | | ||||
861 | if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.contains(name))) { | | |||
862 | Signal s; | | |||
863 | s.name = changeSignalName(name); | | |||
864 | s.modify = true; | | |||
865 | signalList.append(s); | | |||
866 | } | | |||
867 | | ||||
868 | bool nameIsEmpty = name.isEmpty(); | | |||
869 | if (nameIsEmpty && key.isEmpty()) { | | |||
870 | cerr << "Entry must have a name or a key: " << dumpNode(element) << endl; | | |||
871 | return nullptr; | | |||
872 | } | | |||
873 | | ||||
874 | if (key.isEmpty()) { | | |||
875 | key = name; | | |||
876 | } | | |||
877 | | ||||
878 | if (nameIsEmpty) { | | |||
879 | name = key; | | |||
880 | name.remove(' '); | | |||
881 | } else if (name.contains(' ')) { | | |||
882 | cout << "Entry '" << name << "' contains spaces! <name> elements can not contain spaces!" << endl; | | |||
883 | name.remove(' '); | | |||
884 | } | | |||
885 | | ||||
886 | if (name.contains(QStringLiteral("$("))) { | | |||
887 | if (param.isEmpty()) { | | |||
888 | cerr << "Name may not be parameterized: " << name << endl; | | |||
889 | return nullptr; | | |||
890 | } | | |||
891 | } else { | | |||
892 | if (!param.isEmpty()) { | | |||
893 | cerr << "Name must contain '$(" << param << ")': " << name << endl; | | |||
894 | return nullptr; | | |||
895 | } | | |||
896 | } | | |||
897 | | ||||
898 | if (label.isEmpty()) { | | |||
899 | label = key; | | |||
900 | } | | |||
901 | | ||||
902 | if (type.isEmpty()) { | | |||
903 | type = QStringLiteral("String"); // XXX : implicit type might be bad | | |||
904 | } | | |||
905 | | ||||
906 | if (!param.isEmpty()) { | | |||
907 | // Adjust name | | |||
908 | paramName = name; | | |||
909 | name.remove("$(" + param + ')'); | | |||
910 | // Lookup defaults for indexed entries | | |||
911 | for (int i = 0; i <= paramMax; i++) { | | |||
912 | paramDefaultValues.append(QString()); | | |||
913 | } | | |||
914 | | ||||
915 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { | | |||
916 | QString tag = e.tagName(); | | |||
917 | if (tag == QLatin1String("default")) { | | |||
918 | QString index = e.attribute(QStringLiteral("param")); | | |||
919 | if (index.isEmpty()) { | | |||
920 | continue; | | |||
921 | } | | |||
922 | | ||||
923 | bool ok; | | |||
924 | int i = index.toInt(&ok); | | |||
925 | if (!ok) { | | |||
926 | i = paramValues.indexOf(index); | | |||
927 | if (i == -1) { | | |||
928 | cerr << "Index '" << index << "' for default value is unknown." << endl; | | |||
929 | return nullptr; | | |||
930 | } | | |||
931 | } | | |||
932 | | ||||
933 | if ((i < 0) || (i > paramMax)) { | | |||
934 | cerr << "Index '" << i << "' for default value is out of range [0, " << paramMax << "]." << endl; | | |||
935 | return nullptr; | | |||
936 | } | | |||
937 | | ||||
938 | QString tmpDefaultValue = e.text(); | | |||
939 | | ||||
940 | if (e.attribute(QStringLiteral("code")) != QLatin1String("true")) { | | |||
941 | preProcessDefault(tmpDefaultValue, name, type, choices, code, cfg); | | |||
942 | } | | |||
943 | | ||||
944 | paramDefaultValues[i] = tmpDefaultValue; | | |||
945 | } | | |||
946 | } | | |||
947 | } | | |||
948 | | ||||
949 | if (!validNameRegexp->match(name).hasMatch()) { | | |||
950 | if (nameIsEmpty) | | |||
951 | cerr << "The key '" << key << "' can not be used as name for the entry because " | | |||
952 | "it is not a valid name. You need to specify a valid name for this entry." << endl; | | |||
953 | else { | | |||
954 | cerr << "The name '" << name << "' is not a valid name for an entry." << endl; | | |||
955 | } | | |||
956 | return nullptr; | | |||
957 | } | | |||
958 | | ||||
959 | if (allNames.contains(name)) { | | |||
960 | if (nameIsEmpty) | | |||
961 | cerr << "The key '" << key << "' can not be used as name for the entry because " | | |||
962 | "it does not result in a unique name. You need to specify a unique name for this entry." << endl; | | |||
963 | else { | | |||
964 | cerr << "The name '" << name << "' is not unique." << endl; | | |||
965 | } | | |||
966 | return nullptr; | | |||
967 | } | | |||
968 | allNames.append(name); | | |||
969 | | ||||
970 | if (!defaultCode) { | | |||
971 | preProcessDefault(defaultValue, name, type, choices, code, cfg); | | |||
972 | } | | |||
973 | | ||||
974 | CfgEntry *result = new CfgEntry(group, type, key, name, labelContext, label, toolTipContext, toolTip, whatsThisContext, whatsThis, | | |||
975 | code, defaultValue, choices, signalList, | | |||
976 | hidden == QLatin1String("true")); | | |||
977 | if (!param.isEmpty()) { | | |||
978 | result->setParam(param); | | |||
979 | result->setParamName(paramName); | | |||
980 | result->setParamType(paramType); | | |||
981 | result->setParamValues(paramValues); | | |||
982 | result->setParamDefaultValues(paramDefaultValues); | | |||
983 | result->setParamMax(paramMax); | | |||
984 | } | | |||
985 | result->setMinValue(minValue); | | |||
986 | result->setMaxValue(maxValue); | | |||
987 | | ||||
988 | return result; | | |||
989 | } | | |||
990 | 208 | | |||
991 | static bool isUnsigned(const QString &type) | 209 | bool isUnsigned(const QString &type) | ||
992 | { | 210 | { | ||
993 | if (type == QLatin1String("UInt")) { | 211 | if (type == QLatin1String("UInt")) { | ||
994 | return true; | 212 | return true; | ||
995 | } | 213 | } | ||
996 | if (type == QLatin1String("ULongLong")) { | 214 | if (type == QLatin1String("ULongLong")) { | ||
997 | return true; | 215 | return true; | ||
998 | } | 216 | } | ||
999 | return false; | 217 | return false; | ||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Line(s) | 380 | { | |||
1163 | QString t; | 381 | QString t; | ||
1164 | 382 | | |||
1165 | t = type; | 383 | t = type; | ||
1166 | t.replace(0, 1, t.left(1).toUpper()); | 384 | t.replace(0, 1, t.left(1).toUpper()); | ||
1167 | 385 | | |||
1168 | return t; | 386 | return t; | ||
1169 | } | 387 | } | ||
1170 | 388 | | |||
1171 | static QString itemDeclaration(const CfgEntry *e, const CfgConfig &cfg) | 389 | QString itemDeclaration(const CfgEntry *e, const KConfigParameters &cfg) | ||
1172 | { | 390 | { | ||
1173 | if (cfg.itemAccessors) { | 391 | if (cfg.itemAccessors) { | ||
1174 | return QString(); | 392 | return QString(); | ||
1175 | } | 393 | } | ||
1176 | 394 | | |||
1177 | QString type; | 395 | QString type; | ||
1178 | if (!e->signalList().isEmpty()) { | 396 | if (!e->signalList.isEmpty()) { | ||
1179 | type = QStringLiteral("KConfigCompilerSignallingItem"); | 397 | type = QStringLiteral("KConfigCompilerSignallingItem"); | ||
1180 | } else { | 398 | } else { | ||
1181 | type = cfg.inherits + "::Item" + itemType(e->type()); | 399 | type = cfg.inherits + "::Item" + itemType(e->type); | ||
1182 | } | 400 | } | ||
1183 | 401 | | |||
1184 | QString fCap = e->name(); | 402 | QString fCap = e->name; | ||
1185 | fCap[0] = fCap[0].toUpper(); | 403 | fCap[0] = fCap[0].toUpper(); | ||
1186 | return " " + type + " *item" + fCap + | 404 | return " " + type + " *item" + fCap + | ||
1187 | ( (!e->param().isEmpty())?(QStringLiteral("[%1]").arg(e->paramMax()+1)) : QString()) + ";\n"; | 405 | ( (!e->param.isEmpty())?(QStringLiteral("[%1]").arg(e->paramMax+1)) : QString()) + ";\n"; | ||
1188 | } | 406 | } | ||
1189 | 407 | | |||
1190 | // returns the name of an item variable | 408 | // returns the name of an item variable | ||
1191 | // use itemPath to know the full path | 409 | // use itemPath to know the full path | ||
1192 | // like using d-> in case of dpointer | 410 | // like using d-> in case of dpointer | ||
1193 | static QString itemVar(const CfgEntry *e, const CfgConfig &cfg) | 411 | QString itemVar(const CfgEntry *e, const KConfigParameters &cfg) | ||
1194 | { | 412 | { | ||
1195 | QString result; | 413 | QString result; | ||
1196 | if (cfg.itemAccessors) { | 414 | if (cfg.itemAccessors) { | ||
1197 | if (!cfg.dpointer) { | 415 | if (!cfg.dpointer) { | ||
1198 | result = 'm' + e->name() + "Item"; | 416 | result = 'm' + e->name + "Item"; | ||
1199 | result[1] = result[1].toUpper(); | 417 | result[1] = result[1].toUpper(); | ||
1200 | } else { | 418 | } else { | ||
1201 | result = e->name() + "Item"; | 419 | result = e->name + "Item"; | ||
1202 | result[0] = result[0].toLower(); | 420 | result[0] = result[0].toLower(); | ||
1203 | } | 421 | } | ||
1204 | } else { | 422 | } else { | ||
1205 | result = "item" + e->name(); | 423 | result = "item" + e->name; | ||
1206 | result[4] = result[4].toUpper(); | 424 | result[4] = result[4].toUpper(); | ||
1207 | } | 425 | } | ||
1208 | return result; | 426 | return result; | ||
1209 | } | 427 | } | ||
1210 | 428 | | |||
1211 | static QString itemPath(const CfgEntry *e, const CfgConfig &cfg) | 429 | QString itemPath(const CfgEntry *e, const KConfigParameters &cfg) | ||
1212 | { | 430 | { | ||
1213 | QString result; | 431 | QString result; | ||
1214 | if (cfg.dpointer) { | 432 | if (cfg.dpointer) { | ||
1215 | result = "d->" + itemVar(e, cfg); | 433 | result = "d->" + itemVar(e, cfg); | ||
1216 | } else { | 434 | } else { | ||
1217 | result = itemVar(e, cfg); | 435 | result = itemVar(e, cfg); | ||
1218 | } | 436 | } | ||
1219 | return result; | 437 | return result; | ||
1220 | } | 438 | } | ||
1221 | 439 | | |||
1222 | QString newItem(const CfgEntry* entry, const QString &key, const QString& defaultValue, | 440 | QString newItem(const CfgEntry* entry, const QString &key, const QString& defaultValue, | ||
1223 | const CfgConfig &cfg, const QString ¶m = QString()) { | 441 | const KConfigParameters &cfg, const QString ¶m) { | ||
1224 | 442 | | |||
1225 | QList<Signal> sigs = entry->signalList(); | 443 | QList<Signal> sigs = entry->signalList; | ||
1226 | QString t; | 444 | QString t; | ||
1227 | if (!sigs.isEmpty()) { | 445 | if (!sigs.isEmpty()) { | ||
1228 | t += QLatin1String("new KConfigCompilerSignallingItem("); | 446 | t += QLatin1String("new KConfigCompilerSignallingItem("); | ||
1229 | } | 447 | } | ||
1230 | t += "new "+ cfg.inherits + "::Item" + itemType(entry->type()) + "( currentGroup(), " | 448 | t += "new "+ cfg.inherits + "::Item" + itemType(entry->type) + "( currentGroup(), " | ||
1231 | + key + ", " + varPath( entry->name(), cfg ) + param; | 449 | + key + ", " + varPath( entry->name, cfg ) + param; | ||
1232 | 450 | | |||
1233 | if (entry->type() == QLatin1String("Enum")) { | 451 | if (entry->type == QLatin1String("Enum")) { | ||
1234 | t += ", values" + entry->name(); | 452 | t += ", values" + entry->name; | ||
1235 | } | 453 | } | ||
1236 | if (!defaultValue.isEmpty()) { | 454 | if (!defaultValue.isEmpty()) { | ||
1237 | t += QLatin1String(", ") + defaultValue; | 455 | t += QLatin1String(", ") + defaultValue; | ||
1238 | } | 456 | } | ||
1239 | t += QLatin1String(" )"); | 457 | t += QLatin1String(" )"); | ||
1240 | 458 | | |||
1241 | if (!sigs.isEmpty()) { | 459 | if (!sigs.isEmpty()) { | ||
1242 | t += QLatin1String(", this, notifyFunction, "); | 460 | t += QLatin1String(", this, notifyFunction, "); | ||
1243 | //append the signal flags | 461 | //append the signal flags | ||
1244 | for (int i = 0; i < sigs.size(); ++i) { | 462 | for (int i = 0; i < sigs.size(); ++i) { | ||
1245 | if (i != 0) | 463 | if (i != 0) | ||
1246 | t += QLatin1String(" | "); | 464 | t += QLatin1String(" | "); | ||
1247 | t += signalEnumName(sigs[i].name); | 465 | t += signalEnumName(sigs[i].name); | ||
1248 | } | 466 | } | ||
1249 | t += QLatin1String(")"); | 467 | t += QLatin1String(")"); | ||
1250 | } | 468 | } | ||
1251 | t += QLatin1String(";"); | 469 | t += QLatin1String(";"); | ||
1252 | return t; | 470 | return t; | ||
1253 | } | 471 | } | ||
1254 | 472 | | |||
1255 | QString paramString(const QString &s, const CfgEntry *e, int i) | 473 | QString paramString(const QString &s, const CfgEntry *e, int i) | ||
1256 | { | 474 | { | ||
1257 | QString result = s; | 475 | QString result = s; | ||
1258 | QString needle = "$(" + e->param() + ')'; | 476 | QString needle = "$(" + e->param + ')'; | ||
1259 | if (result.contains(needle)) { | 477 | if (result.contains(needle)) { | ||
1260 | QString tmp; | 478 | QString tmp; | ||
1261 | if (e->paramType() == QLatin1String("Enum")) { | 479 | if (e->paramType == QLatin1String("Enum")) { | ||
1262 | tmp = e->paramValues().at(i); | 480 | tmp = e->paramValues.at(i); | ||
1263 | } else { | 481 | } else { | ||
1264 | tmp = QString::number(i); | 482 | tmp = QString::number(i); | ||
1265 | } | 483 | } | ||
1266 | 484 | | |||
1267 | result.replace(needle, tmp); | 485 | result.replace(needle, tmp); | ||
1268 | } | 486 | } | ||
1269 | return result; | 487 | return result; | ||
1270 | } | 488 | } | ||
Show All 13 Lines | 491 | { | |||
1284 | } | 502 | } | ||
1285 | if (arguments.isEmpty()) { | 503 | if (arguments.isEmpty()) { | ||
1286 | return "QStringLiteral( \"" + group + "\" )"; | 504 | return "QStringLiteral( \"" + group + "\" )"; | ||
1287 | } | 505 | } | ||
1288 | 506 | | |||
1289 | return "QStringLiteral( \"" + paramString + "\" )" + arguments; | 507 | return "QStringLiteral( \"" + paramString + "\" )" + arguments; | ||
1290 | } | 508 | } | ||
1291 | 509 | | |||
1292 | QString translatedString(const CfgConfig &cfg, const QString &string, const QString &context = QString(), const QString ¶m = QString(), const QString ¶mValue = QString()) | 510 | QString translatedString(const KConfigParameters &cfg, const QString &string, const QString &context, const QString ¶m, const QString ¶mValue) | ||
1293 | { | 511 | { | ||
1294 | QString result; | 512 | QString result; | ||
1295 | 513 | | |||
1296 | switch (cfg.translationSystem) { | 514 | switch (cfg.translationSystem) { | ||
1297 | case CfgConfig::QtTranslation: | 515 | case KConfigParameters::QtTranslation: | ||
1298 | if (!context.isEmpty()) { | 516 | if (!context.isEmpty()) { | ||
1299 | result += "/*: " + context + " */ QCoreApplication::translate(\""; | 517 | result += "/*: " + context + " */ QCoreApplication::translate(\""; | ||
1300 | } else { | 518 | } else { | ||
1301 | result += QLatin1String("QCoreApplication::translate(\""); | 519 | result += QLatin1String("QCoreApplication::translate(\""); | ||
1302 | } | 520 | } | ||
1303 | result += cfg.className + "\", "; | 521 | result += cfg.className + "\", "; | ||
1304 | break; | 522 | break; | ||
1305 | 523 | | |||
1306 | case CfgConfig::KdeTranslation: | 524 | case KConfigParameters::KdeTranslation: | ||
1307 | if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) { | 525 | if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) { | ||
1308 | result += "i18ndc(" + quoteString(cfg.translationDomain) + ", " + quoteString(context) + ", "; | 526 | result += "i18ndc(" + quoteString(cfg.translationDomain) + ", " + quoteString(context) + ", "; | ||
1309 | } else if (!cfg.translationDomain.isEmpty()) { | 527 | } else if (!cfg.translationDomain.isEmpty()) { | ||
1310 | result += "i18nd(" + quoteString(cfg.translationDomain) + ", "; | 528 | result += "i18nd(" + quoteString(cfg.translationDomain) + ", "; | ||
1311 | } else if (!context.isEmpty()) { | 529 | } else if (!context.isEmpty()) { | ||
1312 | result += "i18nc(" + quoteString(context) + ", "; | 530 | result += "i18nc(" + quoteString(context) + ", "; | ||
1313 | } else { | 531 | } else { | ||
1314 | result += QLatin1String("i18n("); | 532 | result += QLatin1String("i18n("); | ||
Show All 10 Lines | |||||
1325 | } | 543 | } | ||
1326 | 544 | | |||
1327 | result += ')'; | 545 | result += ')'; | ||
1328 | 546 | | |||
1329 | return result; | 547 | return result; | ||
1330 | } | 548 | } | ||
1331 | 549 | | |||
1332 | /* int i is the value of the parameter */ | 550 | /* int i is the value of the parameter */ | ||
1333 | QString userTextsFunctions(CfgEntry *e, const CfgConfig &cfg, QString itemVarStr = QString(), const QString &i = QString()) | 551 | QString userTextsFunctions(const CfgEntry *e, const KConfigParameters &cfg, QString itemVarStr, const QString &i) | ||
1334 | { | 552 | { | ||
1335 | QString txt; | 553 | QString txt; | ||
1336 | if (itemVarStr.isNull()) { | 554 | if (itemVarStr.isNull()) { | ||
1337 | itemVarStr = itemPath(e, cfg); | 555 | itemVarStr = itemPath(e, cfg); | ||
1338 | } | 556 | } | ||
1339 | if (!e->label().isEmpty()) { | 557 | if (!e->label.isEmpty()) { | ||
1340 | txt += " " + itemVarStr + "->setLabel( "; | 558 | txt += " " + itemVarStr + "->setLabel( "; | ||
1341 | txt += translatedString(cfg, e->label(), e->labelContext(), e->param(), i); | 559 | txt += translatedString(cfg, e->label, e->labelContext, e->param, i); | ||
1342 | txt += QLatin1String(" );\n"); | 560 | txt += QLatin1String(" );\n"); | ||
1343 | } | 561 | } | ||
1344 | if (!e->toolTip().isEmpty()) { | 562 | if (!e->toolTip.isEmpty()) { | ||
1345 | txt += " " + itemVarStr + "->setToolTip( "; | 563 | txt += " " + itemVarStr + "->setToolTip( "; | ||
1346 | txt += translatedString(cfg, e->toolTip(), e->toolTipContext(), e->param(), i); | 564 | txt += translatedString(cfg, e->toolTip, e->toolTipContext, e->param, i); | ||
1347 | txt += QLatin1String(" );\n"); | 565 | txt += QLatin1String(" );\n"); | ||
1348 | } | 566 | } | ||
1349 | if (!e->whatsThis().isEmpty()) { | 567 | if (!e->whatsThis.isEmpty()) { | ||
1350 | txt += " " + itemVarStr + "->setWhatsThis( "; | 568 | txt += " " + itemVarStr + "->setWhatsThis( "; | ||
1351 | txt += translatedString(cfg, e->whatsThis(), e->whatsThisContext(), e->param(), i); | 569 | txt += translatedString(cfg, e->whatsThis, e->whatsThisContext, e->param, i); | ||
1352 | txt += QLatin1String(" );\n"); | 570 | txt += QLatin1String(" );\n"); | ||
1353 | } | 571 | } | ||
1354 | return txt; | 572 | return txt; | ||
1355 | } | 573 | } | ||
1356 | 574 | | |||
1357 | // returns the member accesor implementation | 575 | | ||
576 | // returns the member mutator implementation | ||||
1358 | // which should go in the h file if inline | 577 | // which should go in the h file if inline | ||
1359 | // or the cpp file if not inline | 578 | // or the cpp file if not inline | ||
1360 | QString memberAccessorBody(CfgEntry *e, bool globalEnums, const CfgConfig &cfg) | 579 | //TODO: Fix add Debug Method, it should also take the debug string. | ||
1361 | { | 580 | void addDebugMethod(QTextStream &out, const KConfigParameters &cfg, const QString &n) | ||
1362 | QString result; | | |||
1363 | QTextStream out(&result, QIODevice::WriteOnly); | | |||
1364 | QString n = e->name(); | | |||
1365 | QString t = e->type(); | | |||
1366 | bool useEnumType = cfg.useEnumTypes && t == QLatin1String("Enum"); | | |||
1367 | | ||||
1368 | out << "return "; | | |||
1369 | if (useEnumType) { | | |||
1370 | out << "static_cast<" << enumType(e, globalEnums) << ">("; | | |||
1371 | } | | |||
1372 | out << This << varPath(n, cfg); | | |||
1373 | if (!e->param().isEmpty()) { | | |||
1374 | out << "[i]"; | | |||
1375 | } | | |||
1376 | if (useEnumType) { | | |||
1377 | out << ")"; | | |||
1378 | } | | |||
1379 | out << ";" << endl; | | |||
1380 | | ||||
1381 | return result; | | |||
1382 | } | | |||
1383 | | ||||
1384 | // returns the member mutator implementation | | |||
1385 | // which should go in the h file if inline | | |||
1386 | // or the cpp file if not inline | | |||
1387 | | ||||
1388 | void addDebugMethod(QTextStream &out, const CfgConfig &cfg, const QString &n) | | |||
1389 | { | 581 | { | ||
1390 | if (cfg.qCategoryLoggingName.isEmpty()) { | 582 | if (cfg.qCategoryLoggingName.isEmpty()) { | ||
1391 | out << " qDebug() << \"" << setFunction(n); | 583 | out << " qDebug() << \"" << setFunction(n); | ||
1392 | } else { | 584 | } else { | ||
1393 | out << " qCDebug(" << cfg.qCategoryLoggingName << ") << \"" << setFunction(n); | 585 | out << " qCDebug(" << cfg.qCategoryLoggingName << ") << \"" << setFunction(n); | ||
1394 | } | 586 | } | ||
1395 | } | 587 | } | ||
1396 | 588 | | |||
1397 | QString memberMutatorBody(CfgEntry *e, const CfgConfig &cfg) | | |||
1398 | { | | |||
1399 | QString result; | | |||
1400 | QTextStream out(&result, QIODevice::WriteOnly); | | |||
1401 | QString n = e->name(); | | |||
1402 | QString t = e->type(); | | |||
1403 | | ||||
1404 | if (!e->minValue().isEmpty()) { | | |||
1405 | if (e->minValue() != QLatin1String("0") || !isUnsigned(t)) { // skip writing "if uint<0" (#187579) | | |||
1406 | out << "if (v < " << e->minValue() << ")" << endl; | | |||
1407 | out << "{" << endl; | | |||
1408 | addDebugMethod(out, cfg, n); | | |||
1409 | out << ": value \" << v << \" is less than the minimum value of "; | | |||
1410 | out << e->minValue() << "\";" << endl; | | |||
1411 | out << " v = " << e->minValue() << ";" << endl; | | |||
1412 | out << "}" << endl; | | |||
1413 | } | | |||
1414 | } | | |||
1415 | | ||||
1416 | if (!e->maxValue().isEmpty()) { | | |||
1417 | out << endl << "if (v > " << e->maxValue() << ")" << endl; | | |||
1418 | out << "{" << endl; | | |||
1419 | addDebugMethod(out, cfg, n); | | |||
1420 | out << ": value \" << v << \" is greater than the maximum value of "; | | |||
1421 | out << e->maxValue() << "\";" << endl; | | |||
1422 | out << " v = " << e->maxValue() << ";" << endl; | | |||
1423 | out << "}" << endl << endl; | | |||
1424 | } | | |||
1425 | | ||||
1426 | const QString varExpression = This + varPath(n, cfg) + (e->param().isEmpty() ? QString() : QStringLiteral("[i]")); | | |||
1427 | | ||||
1428 | const bool hasBody = !e->signalList().empty() || cfg.generateProperties; | | |||
1429 | out << "if ("; | | |||
1430 | if (hasBody) { | | |||
1431 | out << "v != " << varExpression << " && "; | | |||
1432 | } | | |||
1433 | out << "!" << This << "isImmutable( QStringLiteral( \""; | | |||
1434 | if (!e->param().isEmpty()) { | | |||
1435 | out << e->paramName().replace("$(" + e->param() + ")", QLatin1String("%1")) << "\" ).arg( "; | | |||
1436 | if (e->paramType() == QLatin1String("Enum")) { | | |||
1437 | out << "QLatin1String( "; | | |||
1438 | | ||||
1439 | if (cfg.globalEnums) { | | |||
1440 | out << enumName(e->param()) << "ToString[i]"; | | |||
1441 | } else { | | |||
1442 | out << enumName(e->param()) << "::enumToString[i]"; | | |||
1443 | } | | |||
1444 | | ||||
1445 | out << " )"; | | |||
1446 | } else { | | |||
1447 | out << "i"; | | |||
1448 | } | | |||
1449 | out << " )"; | | |||
1450 | } else { | | |||
1451 | out << n << "\" )"; | | |||
1452 | } | | |||
1453 | out << " ))" << (hasBody ? " {" : "") << endl; | | |||
1454 | out << " " << varExpression << " = v;" << endl; | | |||
1455 | | ||||
1456 | const auto listSignal = e->signalList(); | | |||
1457 | for (const Signal &signal : listSignal) { | | |||
1458 | if (signal.modify) { | | |||
1459 | out << " Q_EMIT " << This << signal.name << "();" << endl; | | |||
1460 | } else { | | |||
1461 | out << " " << This << varPath(QStringLiteral("settingsChanged"), cfg) << " |= " << signalEnumName(signal.name) << ";" << endl; | | |||
1462 | } | | |||
1463 | } | | |||
1464 | if (hasBody) { | | |||
1465 | out << "}" << endl; | | |||
1466 | } | | |||
1467 | | ||||
1468 | return result; | | |||
1469 | } | | |||
1470 | 589 | | |||
1471 | // returns the member get default implementation | 590 | // returns the member get default implementation | ||
1472 | // which should go in the h file if inline | 591 | // which should go in the h file if inline | ||
1473 | // or the cpp file if not inline | 592 | // or the cpp file if not inline | ||
1474 | QString memberGetDefaultBody(CfgEntry *e) | 593 | QString memberGetDefaultBody(const CfgEntry *e) | ||
1475 | { | 594 | { | ||
1476 | QString result = e->code(); | 595 | QString result = e->code; | ||
1477 | QTextStream out(&result, QIODevice::WriteOnly); | 596 | QTextStream out(&result, QIODevice::WriteOnly); | ||
1478 | out << endl; | 597 | out << endl; | ||
1479 | 598 | | |||
1480 | if (!e->param().isEmpty()) { | 599 | if (!e->param.isEmpty()) { | ||
1481 | out << " switch (i) {" << endl; | 600 | out << " switch (i) {" << endl; | ||
1482 | for (int i = 0; i <= e->paramMax(); ++i) { | 601 | for (int i = 0; i <= e->paramMax; ++i) { | ||
1483 | if (!e->paramDefaultValue(i).isEmpty()) { | 602 | if (!e->paramDefaultValues[i].isEmpty()) { | ||
1484 | out << " case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl; | 603 | out << " case " << i << ": return " << e->paramDefaultValues[i] << ';' << endl; | ||
1485 | } | 604 | } | ||
1486 | } | 605 | } | ||
606 | QString defaultValue = e->defaultValue; | ||||
607 | | ||||
1487 | out << " default:" << endl; | 608 | out << " default:" << endl; | ||
1488 | out << " return " << e->defaultValue().replace("$(" + e->param() + ')', QLatin1String("i")) << ';' << endl; | 609 | out << " return " << defaultValue.replace("$(" + e->param + ')', QLatin1String("i")) << ';' << endl; | ||
1489 | out << " }" << endl; | 610 | out << " }" << endl; | ||
1490 | } else { | 611 | } else { | ||
1491 | out << " return " << e->defaultValue() << ';'; | 612 | out << " return " << e->defaultValue << ';'; | ||
1492 | } | 613 | } | ||
1493 | 614 | | |||
1494 | return result; | 615 | return result; | ||
1495 | } | 616 | } | ||
1496 | 617 | | |||
1497 | // returns the item accesor implementation | 618 | // returns the item accesor implementation | ||
1498 | // which should go in the h file if inline | 619 | // which should go in the h file if inline | ||
1499 | // or the cpp file if not inline | 620 | // or the cpp file if not inline | ||
1500 | QString itemAccessorBody(CfgEntry *e, const CfgConfig &cfg) | 621 | QString itemAccessorBody(const CfgEntry *e, const KConfigParameters &cfg) | ||
1501 | { | 622 | { | ||
1502 | QString result; | 623 | QString result; | ||
1503 | QTextStream out(&result, QIODevice::WriteOnly); | 624 | QTextStream out(&result, QIODevice::WriteOnly); | ||
1504 | 625 | | |||
1505 | out << "return " << itemPath(e, cfg); | 626 | out << "return " << itemPath(e, cfg); | ||
1506 | if (!e->param().isEmpty()) { | 627 | if (!e->param.isEmpty()) { | ||
1507 | out << "[i]"; | 628 | out << "[i]"; | ||
1508 | } | 629 | } | ||
1509 | out << ";" << endl; | 630 | out << ";" << endl; | ||
1510 | 631 | | |||
1511 | return result; | 632 | return result; | ||
1512 | } | 633 | } | ||
1513 | 634 | | |||
1514 | //indents text adding X spaces per line | 635 | //indents text adding X spaces per line | ||
Show All 9 Lines | 644 | if (!currLine.isEmpty()) | |||
1524 | for (int i = 0; i < spaces; i++) { | 645 | for (int i = 0; i < spaces; i++) { | ||
1525 | out << " "; | 646 | out << " "; | ||
1526 | } | 647 | } | ||
1527 | out << currLine << endl; | 648 | out << currLine << endl; | ||
1528 | } | 649 | } | ||
1529 | return result; | 650 | return result; | ||
1530 | } | 651 | } | ||
1531 | 652 | | |||
1532 | // adds as many 'namespace foo {' lines to p_out as | 653 | bool hasErrors(KConfigXmlParser &parser, const ParseResult& parseResult, const KConfigParameters &cfg) | ||
ervin: Space before & not after | |||||
1533 | // there are namespaces in p_ns | | |||
1534 | void beginNamespaces(const QString &p_ns, QTextStream &p_out) | | |||
1535 | { | 654 | { | ||
1536 | if (!p_ns.isEmpty()) { | 655 | if (cfg.className.isEmpty()) { | ||
1537 | const QStringList nameSpaces = p_ns.split(QStringLiteral("::")); | 656 | cerr << "Class name missing" << endl; | ||
1538 | for (const QString &ns : nameSpaces) { | 657 | return true; | ||
1539 | p_out << "namespace " << ns << " {" << endl; | | |||
1540 | } | | |||
1541 | p_out << endl; | | |||
1542 | } | 658 | } | ||
659 | | ||||
660 | if (cfg.singleton && !parseResult.parameters.isEmpty()) { | ||||
661 | cerr << "Singleton class can not have parameters" << endl; | ||||
662 | return true; | ||||
1543 | } | 663 | } | ||
1544 | 664 | | |||
1545 | // adds as many '}' lines to p_out as | 665 | if (!parseResult.cfgFileName.isEmpty() && parseResult.cfgFileNameArg) { | ||
1546 | // there are namespaces in p_ns | 666 | cerr << "Having both a fixed filename and a filename as argument is not possible." << endl; | ||
1547 | void endNamespaces(const QString &p_ns, QTextStream &p_out) | 667 | return true; | ||
1548 | { | | |||
1549 | if (!p_ns.isEmpty()) { | | |||
1550 | const int namespaceCount = p_ns.count(QStringLiteral("::")) + 1; | | |||
1551 | for (int i = 0; i < namespaceCount; ++i) { | | |||
1552 | p_out << "}" << endl; | | |||
1553 | } | 668 | } | ||
1554 | p_out << endl; | 669 | | ||
670 | /* TODO: For some reason some configuration files prefer to have *no* entries | ||||
671 | * at all in it, and the generated code is mostly bogus as KConfigXT will not | ||||
672 | * handle save / load / properties, etc, nothing. | ||||
673 | * | ||||
674 | * The first of those files that I came across are qmakebuilderconfig.kcfg from the KDevelop | ||||
675 | * project. | ||||
676 | * I think we should remove the possibility of creating configuration classes from configuration | ||||
677 | * files that don't really have configuration in it. but I'm changing this right now to allow | ||||
678 | * kdevelop files to pass. | ||||
679 | * | ||||
680 | * Remove for KDE 6 | ||||
681 | * (to make things more interesting, it failed in a code that's never used within KDevelop... ) | ||||
682 | */ | ||||
683 | if (parseResult.entries.isEmpty()) { | ||||
684 | cerr << "No entries." << endl; | ||||
685 | return false; | ||||
1555 | } | 686 | } | ||
687 | | ||||
688 | return false; | ||||
1556 | } | 689 | } | ||
1557 | 690 | | |||
1558 | int main(int argc, char **argv) | 691 | int main(int argc, char **argv) | ||
1559 | { | 692 | { | ||
1560 | QCoreApplication app(argc, argv); | 693 | QCoreApplication app(argc, argv); | ||
1561 | app.setApplicationName(QStringLiteral("kconfig_compiler")); | 694 | app.setApplicationName(QStringLiteral("kconfig_compiler")); | ||
1562 | app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING)); | 695 | app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING)); | ||
1563 | 696 | | |||
1564 | validNameRegexp = new QRegularExpression(QRegularExpression::anchoredPattern( | | |||
1565 | QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*"))); | | |||
1566 | | ||||
1567 | QString inputFilename, codegenFilename; | 697 | QString inputFilename, codegenFilename; | ||
1568 | 698 | | |||
699 | QCommandLineOption targetDirectoryOption(QStringList { QStringLiteral("d"), QStringLiteral("directory") }, | ||||
700 | QCoreApplication::translate("main", "Directory to generate files in [.]"), | ||||
701 | QCoreApplication::translate("main", "directory"), QStringLiteral(".")); | ||||
702 | | ||||
703 | QCommandLineOption licenseOption ( | ||||
704 | QStringList { QStringLiteral("l"), QStringLiteral("license") }, | ||||
705 | QCoreApplication::translate("main", "Display software license.")); | ||||
706 | | ||||
1569 | QCommandLineParser parser; | 707 | QCommandLineParser parser; | ||
1570 | 708 | | |||
1571 | parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file")); | 709 | parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file")); | ||
1572 | parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file")); | 710 | parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file")); | ||
1573 | 711 | | |||
1574 | QCommandLineOption targetDirectoryOption(QStringList { QStringLiteral("d"), QStringLiteral("directory") }, | | |||
1575 | QCoreApplication::translate("main", "Directory to generate files in [.]"), | | |||
1576 | QCoreApplication::translate("main", "directory"), QStringLiteral(".")); | | |||
1577 | parser.addOption(targetDirectoryOption); | 712 | parser.addOption(targetDirectoryOption); | ||
1578 | | ||||
1579 | QCommandLineOption licenseOption (QStringList { QStringLiteral("l"), QStringLiteral("license") }, QCoreApplication::translate("main", "Display software license.")); | | |||
1580 | parser.addOption (licenseOption); | 713 | parser.addOption (licenseOption); | ||
1581 | 714 | | |||
1582 | parser.addVersionOption(); | 715 | parser.addVersionOption(); | ||
1583 | parser.addHelpOption(); | 716 | parser.addHelpOption(); | ||
1584 | parser.process(app); | 717 | parser.process(app); | ||
1585 | 718 | | |||
1586 | if (parser.isSet(licenseOption)) { | 719 | if (parser.isSet(licenseOption)) { | ||
1587 | cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl; | 720 | cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl; | ||
1588 | cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << endl; | 721 | cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << endl; | ||
1589 | cout << "This program comes with ABSOLUTELY NO WARRANTY." << endl; | 722 | cout << "This program comes with ABSOLUTELY NO WARRANTY." << endl; | ||
1590 | cout << "You may redistribute copies of this program" << endl; | 723 | cout << "You may redistribute copies of this program" << endl; | ||
1591 | cout << "under the terms of the GNU Library Public License." << endl; | 724 | cout << "under the terms of the GNU Library Public License." << endl; | ||
1592 | cout << "For more information about these matters, see the file named COPYING." << endl; | 725 | cout << "For more information about these matters, see the file named COPYING." << endl; | ||
1593 | return 0; | 726 | return 0; | ||
1594 | } | 727 | } | ||
1595 | 728 | | |||
1596 | const QStringList args = parser.positionalArguments(); | 729 | const QStringList args = parser.positionalArguments(); | ||
1597 | if (args.count() < 2) { | 730 | if (args.count() < 2) { | ||
1598 | cerr << "Too few arguments." << endl; | 731 | cerr << "Too few arguments." << endl; | ||
1599 | return 1; | 732 | return 1; | ||
1600 | } | 733 | } | ||
734 | | ||||
1601 | if (args.count() > 2) { | 735 | if (args.count() > 2) { | ||
1602 | cerr << "Too many arguments." << endl; | 736 | cerr << "Too many arguments." << endl; | ||
1603 | return 1; | 737 | return 1; | ||
1604 | } | 738 | } | ||
1605 | inputFilename = args.at(0); | 739 | inputFilename = args.at(0); | ||
1606 | codegenFilename = args.at(1); | 740 | codegenFilename = args.at(1); | ||
1607 | 741 | | |||
742 | // TODO: Transform baseDir into a helper. | ||||
1608 | QString baseDir = parser.value(targetDirectoryOption); | 743 | QString baseDir = parser.value(targetDirectoryOption); | ||
1609 | 744 | | |||
1610 | #ifdef Q_OS_WIN | 745 | #ifdef Q_OS_WIN | ||
1611 | if (!baseDir.endsWith('/') && !baseDir.endsWith('\\')) | 746 | if (!baseDir.endsWith('/') && !baseDir.endsWith('\\')) | ||
1612 | #else | 747 | #else | ||
1613 | if (!baseDir.endsWith('/')) | 748 | if (!baseDir.endsWith('/')) | ||
1614 | #endif | 749 | #endif | ||
1615 | baseDir.append("/"); | 750 | baseDir.append("/"); | ||
1616 | 751 | | |||
1617 | if (!codegenFilename.endsWith(QLatin1String(".kcfgc"))) { | 752 | KConfigParameters cfg(codegenFilename); | ||
dfaure: it's shorter and simpler to write KConfigXTParameters cfg(codegenFilename);
| |||||
1618 | cerr << "Codegen options file must have extension .kcfgc" << endl; | | |||
1619 | return 1; | | |||
1620 | } | | |||
1621 | QString baseName = QFileInfo(codegenFilename).fileName(); | | |||
1622 | baseName = baseName.left(baseName.length() - 6); | | |||
1623 | | ||||
1624 | CfgConfig cfg = CfgConfig(codegenFilename); | | |||
1625 | | ||||
1626 | QFile input(inputFilename); | | |||
1627 | | ||||
1628 | QDomDocument doc; | | |||
1629 | QString errorMsg; | | |||
1630 | int errorRow; | | |||
1631 | int errorCol; | | |||
1632 | if (!doc.setContent(&input, &errorMsg, &errorRow, &errorCol)) { | | |||
1633 | cerr << "Unable to load document." << endl; | | |||
1634 | cerr << "Parse error in " << inputFilename << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl; | | |||
1635 | return 1; | | |||
1636 | } | | |||
1637 | | ||||
1638 | QDomElement cfgElement = doc.documentElement(); | | |||
1639 | | ||||
1640 | if (cfgElement.isNull()) { | | |||
1641 | cerr << "No document in kcfg file" << endl; | | |||
1642 | return 1; | | |||
1643 | } | | |||
1644 | | ||||
1645 | QString cfgFileName; | | |||
1646 | bool cfgFileNameArg = false; | | |||
1647 | QList<Param> parameters; | | |||
1648 | QList<Signal> signalList; | | |||
1649 | QStringList includes; | | |||
1650 | | ||||
1651 | QList<CfgEntry *> entries; | | |||
1652 | | ||||
1653 | for (QDomElement e = cfgElement.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { | | |||
1654 | QString tag = e.tagName(); | | |||
1655 | | ||||
1656 | if (tag == QLatin1String("include")) { | | |||
1657 | QString includeFile = e.text(); | | |||
1658 | if (!includeFile.isEmpty()) { | | |||
1659 | includes.append(includeFile); | | |||
1660 | } | | |||
1661 | | ||||
1662 | } else if (tag == QLatin1String("kcfgfile")) { | | |||
1663 | cfgFileName = e.attribute(QStringLiteral("name")); | | |||
1664 | cfgFileNameArg = e.attribute(QStringLiteral("arg")).toLower() == QLatin1String("true"); | | |||
1665 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | | |||
1666 | if (e2.tagName() == QLatin1String("parameter")) { | | |||
1667 | Param p; | | |||
1668 | p.name = e2.attribute(QStringLiteral("name")); | | |||
1669 | p.type = e2.attribute(QStringLiteral("type")); | | |||
1670 | if (p.type.isEmpty()) { | | |||
1671 | p.type = QStringLiteral("String"); | | |||
1672 | } | | |||
1673 | parameters.append(p); | | |||
1674 | } | | |||
1675 | } | | |||
1676 | | ||||
1677 | } else if (tag == QLatin1String("group")) { | | |||
1678 | QString group = e.attribute(QStringLiteral("name")); | | |||
1679 | if (group.isEmpty()) { | | |||
1680 | cerr << "Group without name" << endl; | | |||
1681 | return 1; | | |||
1682 | } | | |||
1683 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | | |||
1684 | if (e2.tagName() != QLatin1String("entry")) { | | |||
1685 | continue; | | |||
1686 | } | | |||
1687 | CfgEntry *entry = parseEntry(group, e2, cfg); | | |||
1688 | if (entry) { | | |||
1689 | entries.append(entry); | | |||
1690 | } else { | | |||
1691 | cerr << "Can not parse entry." << endl; | | |||
1692 | return 1; | | |||
1693 | } | | |||
1694 | } | | |||
1695 | } else if (tag == QLatin1String("signal")) { | | |||
1696 | QString signalName = e.attribute(QStringLiteral("name")); | | |||
1697 | if (signalName.isEmpty()) { | | |||
1698 | cerr << "Signal without name." << endl; | | |||
1699 | return 1; | | |||
1700 | } | | |||
1701 | Signal theSignal; | | |||
1702 | theSignal.name = signalName; | | |||
1703 | | ||||
1704 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | | |||
1705 | if (e2.tagName() == QLatin1String("argument")) { | | |||
1706 | SignalArguments argument; | | |||
1707 | argument.type = e2.attribute(QStringLiteral("type")); | | |||
1708 | if (argument.type.isEmpty()) { | | |||
1709 | cerr << "Signal argument without type." << endl; | | |||
1710 | return 1; | | |||
1711 | } | | |||
1712 | argument.variableName = e2.text(); | | |||
1713 | theSignal.arguments.append(argument); | | |||
1714 | } else if (e2.tagName() == QLatin1String("label")) { | | |||
1715 | theSignal.label = e2.text(); | | |||
1716 | } | | |||
1717 | } | | |||
1718 | signalList.append(theSignal); | | |||
1719 | } | | |||
1720 | } | | |||
1721 | | ||||
1722 | if (cfg.className.isEmpty()) { | | |||
1723 | cerr << "Class name missing" << endl; | | |||
1724 | return 1; | | |||
1725 | } | | |||
1726 | | ||||
1727 | if (cfg.singleton && !parameters.isEmpty()) { | | |||
1728 | cerr << "Singleton class can not have parameters" << endl; | | |||
1729 | return 1; | | |||
1730 | } | | |||
1731 | | ||||
1732 | if (!cfgFileName.isEmpty() && cfgFileNameArg) { | | |||
1733 | cerr << "Having both a fixed filename and a filename as argument is not possible." << endl; | | |||
1734 | return 1; | | |||
1735 | } | | |||
1736 | | ||||
1737 | if (entries.isEmpty()) { | | |||
1738 | cerr << "No entries." << endl; | | |||
1739 | } | | |||
1740 | | ||||
1741 | #if 0 | | |||
1742 | CfgEntry *cfg; | | |||
1743 | for (cfg = entries.first(); cfg; cfg = entries.next()) { | | |||
1744 | cfg->dump(); | | |||
1745 | } | | |||
1746 | #endif | | |||
1747 | | ||||
1748 | QString headerFileName = baseName + '.' + cfg.headerExtension; | | |||
1749 | QString implementationFileName = baseName + '.' + cfg.sourceExtension; | | |||
1750 | QString mocFileName = baseName + ".moc"; | | |||
1751 | QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values | | |||
1752 | | ||||
1753 | QFile header(baseDir + headerFileName); | | |||
1754 | if (!header.open(QIODevice::WriteOnly)) { | | |||
1755 | cerr << "Can not open '" << baseDir << headerFileName << "for writing." << endl; | | |||
1756 | return 1; | | |||
1757 | } | | |||
1758 | | ||||
1759 | QTextStream h(&header); | | |||
1760 | | ||||
1761 | h.setCodec("utf-8"); | | |||
1762 | | ||||
1763 | h << "// This file is generated by kconfig_compiler_kf5 from " << QFileInfo(inputFilename).fileName() << "." << endl; | | |||
1764 | h << "// All changes you do to this file will be lost." << endl; | | |||
1765 | | ||||
1766 | h << "#ifndef " << (!cfg.nameSpace.isEmpty() ? QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_")).toUpper() + '_') : QLatin1String("")) | | |||
1767 | << cfg.className.toUpper() << "_H" << endl; | | |||
1768 | h << "#define " << (!cfg.nameSpace.isEmpty() ? QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_")).toUpper() + '_') : QLatin1String("")) | | |||
1769 | << cfg.className.toUpper() << "_H" << endl << endl; | | |||
1770 | | ||||
1771 | // Includes | | |||
1772 | QStringList::ConstIterator it; | | |||
1773 | for (it = cfg.headerIncludes.constBegin(); it != cfg.headerIncludes.constEnd(); ++it) { | | |||
1774 | if ((*it).startsWith('"')) { | | |||
1775 | h << "#include " << *it << endl; | | |||
1776 | } else { | | |||
1777 | h << "#include <" << *it << ">" << endl; | | |||
1778 | } | | |||
1779 | } | | |||
1780 | | ||||
1781 | if (!cfg.headerIncludes.isEmpty()) { | | |||
1782 | h << endl; | | |||
1783 | } | | |||
1784 | | ||||
1785 | if (!cfg.singleton && parameters.isEmpty()) { | | |||
1786 | h << "#include <qglobal.h>" << endl; | | |||
1787 | } | | |||
1788 | | ||||
1789 | if (cfg.inherits == QLatin1String("KCoreConfigSkeleton")) { | | |||
1790 | h << "#include <kcoreconfigskeleton.h>" << endl; | | |||
1791 | } else { | | |||
1792 | h << "#include <kconfigskeleton.h>" << endl; | | |||
1793 | } | | |||
1794 | | ||||
1795 | h << "#include <QCoreApplication>" << endl; | | |||
1796 | h << "#include <QDebug>" << endl << endl; | | |||
1797 | | ||||
1798 | // Includes | | |||
1799 | for (it = includes.constBegin(); it != includes.constEnd(); ++it) { | | |||
1800 | if ((*it).startsWith('"')) { | | |||
1801 | h << "#include " << *it << endl; | | |||
1802 | } else { | | |||
1803 | h << "#include <" << *it << ">" << endl; | | |||
1804 | } | | |||
1805 | } | | |||
1806 | | ||||
1807 | beginNamespaces(cfg.nameSpace, h); | | |||
1808 | | ||||
1809 | // Private class declaration | | |||
1810 | if (cfg.dpointer) { | | |||
1811 | h << "class " << cfg.className << "Private;" << endl << endl; | | |||
1812 | } | | |||
1813 | | ||||
1814 | // Class declaration header | | |||
1815 | h << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl; | | |||
1816 | | ||||
1817 | h << "{" << endl; | | |||
1818 | // Add Q_OBJECT macro if the config need signals. | | |||
1819 | if (!signalList.isEmpty() || cfg.generateProperties) { | | |||
1820 | h << " Q_OBJECT" << endl; | | |||
1821 | } | | |||
1822 | h << " public:" << endl; | | |||
1823 | | ||||
1824 | // enums | | |||
1825 | QList<CfgEntry *>::ConstIterator itEntry; | | |||
1826 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
1827 | const CfgEntry::Choices &choices = (*itEntry)->choices(); | | |||
1828 | const QList<CfgEntry::Choice> chlist = choices.choices; | | |||
1829 | if (!chlist.isEmpty()) { | | |||
1830 | QStringList values; | | |||
1831 | QList<CfgEntry::Choice>::ConstIterator itChoice; | | |||
1832 | for (itChoice = chlist.constBegin(); itChoice != chlist.constEnd(); ++itChoice) { | | |||
1833 | values.append(choices.prefix + (*itChoice).name); | | |||
1834 | } | | |||
1835 | if (choices.name().isEmpty()) { | | |||
1836 | if (cfg.globalEnums) { | | |||
1837 | h << " enum " << enumName((*itEntry)->name(), (*itEntry)->choices()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; | | |||
1838 | } else { | | |||
1839 | // Create an automatically named enum | | |||
1840 | h << " class " << enumName((*itEntry)->name(), (*itEntry)->choices()) << endl; | | |||
1841 | h << " {" << endl; | | |||
1842 | h << " public:" << endl; | | |||
1843 | h << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl; | | |||
1844 | h << " };" << endl; | | |||
1845 | } | | |||
1846 | } else if (!choices.external()) { | | |||
1847 | // Create a named enum | | |||
1848 | h << " enum " << enumName((*itEntry)->name(), (*itEntry)->choices()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; | | |||
1849 | } | | |||
1850 | } | | |||
1851 | const QStringList values = (*itEntry)->paramValues(); | | |||
1852 | if (!values.isEmpty()) { | | |||
1853 | if (cfg.globalEnums) { | | |||
1854 | // ### FIXME!! | | |||
1855 | // make the following string table an index-based string search! | | |||
1856 | // ### | | |||
1857 | h << " enum " << enumName((*itEntry)->param()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; | | |||
1858 | h << " static const char* const " << enumName((*itEntry)->param()) << "ToString[];" << endl; | | |||
1859 | cppPreamble += "const char* const " + cfg.className + "::" + enumName((*itEntry)->param()) + | | |||
1860 | "ToString[] = { \"" + values.join(QStringLiteral("\", \"")) + "\" };\n"; | | |||
1861 | } else { | | |||
1862 | h << " class " << enumName((*itEntry)->param()) << endl; | | |||
1863 | h << " {" << endl; | | |||
1864 | h << " public:" << endl; | | |||
1865 | h << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl; | | |||
1866 | h << " static const char* const enumToString[];" << endl; | | |||
1867 | h << " };" << endl; | | |||
1868 | cppPreamble += "const char* const " + cfg.className + "::" + enumName((*itEntry)->param()) + | | |||
1869 | "::enumToString[] = { \"" + values.join(QStringLiteral("\", \"")) + "\" };\n"; | | |||
1870 | } | | |||
1871 | } | | |||
1872 | } | | |||
1873 | h << endl; | | |||
1874 | | ||||
1875 | | ||||
1876 | // Constructor or singleton accessor | | |||
1877 | if (!cfg.singleton) { | | |||
1878 | h << " " << cfg.className << "("; | | |||
1879 | if (cfgFileNameArg) { | | |||
1880 | if (cfg.forceStringFilename) | | |||
1881 | h << " const QString &cfgfilename" | | |||
1882 | << (parameters.isEmpty() ? " = QString()" : ", "); | | |||
1883 | else | | |||
1884 | h << " KSharedConfig::Ptr config" | | |||
1885 | << (parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", "); | | |||
1886 | } | | |||
1887 | for (QList<Param>::ConstIterator it = parameters.constBegin(); | | |||
1888 | it != parameters.constEnd(); ++it) { | | |||
1889 | if (it != parameters.constBegin()) { | | |||
1890 | h << ","; | | |||
1891 | } | | |||
1892 | h << " " << param((*it).type) << " " << (*it).name; | | |||
1893 | } | | |||
1894 | if (cfg.parentInConstructor) { | | |||
1895 | if (cfgFileNameArg || !parameters.isEmpty()) { | | |||
1896 | h << ","; | | |||
1897 | } | | |||
1898 | h << " QObject *parent = nullptr"; | | |||
1899 | } | | |||
1900 | h << " );" << endl; | | |||
1901 | } else { | | |||
1902 | h << " static " << cfg.className << " *self();" << endl; | | |||
1903 | if (cfgFileNameArg) { | | |||
1904 | h << " static void instance(const QString& cfgfilename);" << endl; | | |||
1905 | h << " static void instance(KSharedConfig::Ptr config);" << endl; | | |||
1906 | } | | |||
1907 | } | | |||
1908 | | ||||
1909 | // Destructor | | |||
1910 | h << " ~" << cfg.className << "();" << endl << endl; | | |||
1911 | | ||||
1912 | // global variables | | |||
1913 | if (cfg.staticAccessors) { | | |||
1914 | This = QStringLiteral("self()->"); | | |||
1915 | } else { | | |||
1916 | Const = QStringLiteral(" const"); | | |||
1917 | } | | |||
1918 | | ||||
1919 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
1920 | QString n = (*itEntry)->name(); | | |||
1921 | QString t = (*itEntry)->type(); | | |||
1922 | | ||||
1923 | // Manipulator | | |||
1924 | if (cfg.allMutators || cfg.mutators.contains(n)) { | | |||
1925 | h << " /**" << endl; | | |||
1926 | h << " Set " << (*itEntry)->label() << endl; | | |||
1927 | h << " */" << endl; | | |||
1928 | if (cfg.staticAccessors) { | | |||
1929 | h << " static" << endl; | | |||
1930 | } | | |||
1931 | h << " void " << setFunction(n) << "( "; | | |||
1932 | if (!(*itEntry)->param().isEmpty()) { | | |||
1933 | h << cppType((*itEntry)->paramType()) << " i, "; | | |||
1934 | } | | |||
1935 | if (cfg.useEnumTypes && t == QLatin1String("Enum")) { | | |||
1936 | h << enumType(*itEntry, cfg.globalEnums); | | |||
1937 | } else { | | |||
1938 | h << param(t); | | |||
1939 | } | | |||
1940 | h << " v )"; | | |||
1941 | // function body inline only if not using dpointer | | |||
1942 | // for BC mode | | |||
1943 | if (!cfg.dpointer) { | | |||
1944 | h << endl << " {" << endl; | | |||
1945 | h << indent(memberMutatorBody(*itEntry, cfg), 6); | | |||
1946 | h << " }" << endl; | | |||
1947 | } else { | | |||
1948 | h << ";" << endl; | | |||
1949 | } | | |||
1950 | } | | |||
1951 | h << endl; | | |||
1952 | | ||||
1953 | QString returnType; | | |||
1954 | if (cfg.useEnumTypes && t == QLatin1String("Enum")) { | | |||
1955 | returnType = enumType(*itEntry, cfg.globalEnums); | | |||
1956 | } else { | | |||
1957 | returnType = cppType(t); | | |||
1958 | } | | |||
1959 | | ||||
1960 | if (cfg.generateProperties) { | | |||
1961 | h << " Q_PROPERTY(" << returnType << ' ' << getFunction(n); | | |||
1962 | h << " READ " << getFunction(n); | | |||
1963 | if (cfg.allMutators || cfg.mutators.contains(n)) { | | |||
1964 | const QString signal = changeSignalName(n); | | |||
1965 | h << " WRITE " << setFunction(n); | | |||
1966 | h << " NOTIFY " << signal; | | |||
1967 | | ||||
1968 | //If we have the modified signal, we'll also need | | |||
1969 | //the changed signal as well | | |||
1970 | Signal s; | | |||
1971 | s.name = signal; | | |||
1972 | s.modify = true; | | |||
1973 | signalList.append(s); | | |||
1974 | } else { | | |||
1975 | h << " CONSTANT"; | | |||
1976 | } | | |||
1977 | h << ")" << endl; | | |||
1978 | } | | |||
1979 | // Accessor | | |||
1980 | h << " /**" << endl; | | |||
1981 | h << " Get " << (*itEntry)->label() << endl; | | |||
1982 | h << " */" << endl; | | |||
1983 | if (cfg.staticAccessors) { | | |||
1984 | h << " static" << endl; | | |||
1985 | } | | |||
1986 | h << " "; | | |||
1987 | h << returnType; | | |||
1988 | h << " " << getFunction(n) << "("; | | |||
1989 | if (!(*itEntry)->param().isEmpty()) { | | |||
1990 | h << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
1991 | } | | |||
1992 | h << ")" << Const; | | |||
1993 | // function body inline only if not using dpointer | | |||
1994 | // for BC mode | | |||
1995 | if (!cfg.dpointer) { | | |||
1996 | h << endl << " {" << endl; | | |||
1997 | h << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 6); | | |||
1998 | h << " }" << endl; | | |||
1999 | } else { | | |||
2000 | h << ";" << endl; | | |||
2001 | } | | |||
2002 | | ||||
2003 | // Default value Accessor | | |||
2004 | if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) { | | |||
2005 | h << endl; | | |||
2006 | h << " /**" << endl; | | |||
2007 | h << " Get " << (*itEntry)->label() << " default value" << endl; | | |||
2008 | h << " */" << endl; | | |||
2009 | if (cfg.staticAccessors) { | | |||
2010 | h << " static" << endl; | | |||
2011 | } | | |||
2012 | h << " "; | | |||
2013 | if (cfg.useEnumTypes && t == QLatin1String("Enum")) { | | |||
2014 | h << enumType(*itEntry, cfg.globalEnums); | | |||
2015 | } else { | | |||
2016 | h << cppType(t); | | |||
2017 | } | | |||
2018 | h << " " << getDefaultFunction(n) << "("; | | |||
2019 | if (!(*itEntry)->param().isEmpty()) { | | |||
2020 | h << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
2021 | } | | |||
2022 | h << ")" << Const << endl; | | |||
2023 | h << " {" << endl; | | |||
2024 | h << " return "; | | |||
2025 | if (cfg.useEnumTypes && t == QLatin1String("Enum")) { | | |||
2026 | h << "static_cast<" << enumType(*itEntry, cfg.globalEnums) << ">("; | | |||
2027 | } | | |||
2028 | h << getDefaultFunction(n) << "_helper("; | | |||
2029 | if (!(*itEntry)->param().isEmpty()) { | | |||
2030 | h << " i "; | | |||
2031 | } | | |||
2032 | h << ")"; | | |||
2033 | if (cfg.useEnumTypes && t == QLatin1String("Enum")) { | | |||
2034 | h << ")"; | | |||
2035 | } | | |||
2036 | h << ";" << endl; | | |||
2037 | h << " }" << endl; | | |||
2038 | } | | |||
2039 | | ||||
2040 | // Item accessor | | |||
2041 | if (cfg.itemAccessors) { | | |||
2042 | h << endl; | | |||
2043 | h << " /**" << endl; | | |||
2044 | h << " Get Item object corresponding to " << n << "()" | | |||
2045 | << endl; | | |||
2046 | h << " */" << endl; | | |||
2047 | h << " Item" << itemType((*itEntry)->type()) << " *" | | |||
2048 | << getFunction(n) << "Item("; | | |||
2049 | if (!(*itEntry)->param().isEmpty()) { | | |||
2050 | h << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
2051 | } | | |||
2052 | h << ")"; | | |||
2053 | if (!cfg.dpointer) { | | |||
2054 | h << endl << " {" << endl; | | |||
2055 | h << indent(itemAccessorBody((*itEntry), cfg), 6); | | |||
2056 | h << " }" << endl; | | |||
2057 | } else { | | |||
2058 | h << ";" << endl; | | |||
2059 | } | | |||
2060 | } | | |||
2061 | | ||||
2062 | h << endl; | | |||
2063 | } | | |||
2064 | | ||||
2065 | // Signal definition. | | |||
2066 | const bool hasSignals = !signalList.isEmpty(); | | |||
2067 | bool hasNonModifySignals = false; | | |||
2068 | if (hasSignals) { | | |||
2069 | h << "\n enum {" << endl; | | |||
2070 | unsigned val = 1; | | |||
2071 | QList<Signal>::ConstIterator it, itEnd = signalList.constEnd(); | | |||
2072 | for (it = signalList.constBegin(); it != itEnd; val <<= 1) { | | |||
2073 | hasNonModifySignals |= !it->modify; | | |||
2074 | if (!val) { | | |||
2075 | cerr << "Too many signals to create unique bit masks" << endl; | | |||
2076 | exit(1); | | |||
2077 | } | | |||
2078 | Signal signal = *it; | | |||
2079 | h << " " << signalEnumName(signal.name) << " = 0x" << | | |||
2080 | #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) | | |||
2081 | hex | | |||
2082 | #else | | |||
2083 | Qt::hex | | |||
2084 | #endif | | |||
2085 | << val; | | |||
2086 | if (++it != itEnd) { | | |||
2087 | h << ","; | | |||
2088 | } | | |||
2089 | h << endl; | | |||
2090 | } | | |||
2091 | h << " };" << | | |||
2092 | #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) | | |||
2093 | dec | | |||
2094 | #else | | |||
2095 | Qt::dec | | |||
2096 | #endif | | |||
2097 | << endl << endl; | | |||
2098 | | ||||
2099 | h << " Q_SIGNALS:"; | | |||
2100 | for (const Signal &signal : qAsConst(signalList)) { | | |||
2101 | h << endl; | | |||
2102 | if (!signal.label.isEmpty()) { | | |||
2103 | h << " /**" << endl; | | |||
2104 | h << " " << signal.label << endl; | | |||
2105 | h << " */" << endl; | | |||
2106 | } | | |||
2107 | h << " void " << signal.name << "("; | | |||
2108 | QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd(); | | |||
2109 | for (it = signal.arguments.constBegin(); it != itEnd;) { | | |||
2110 | SignalArguments argument = *it; | | |||
2111 | QString type = param(argument.type); | | |||
2112 | if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) { | | |||
2113 | for (int i = 0, end = entries.count(); i < end; ++i) { | | |||
2114 | if (entries[i]->name() == argument.variableName) { | | |||
2115 | type = enumType(entries[i], cfg.globalEnums); | | |||
2116 | break; | | |||
2117 | } | | |||
2118 | } | | |||
2119 | } | | |||
2120 | h << type << " " << argument.variableName; | | |||
2121 | if (++it != itEnd) { | | |||
2122 | h << ", "; | | |||
2123 | } | | |||
2124 | } | | |||
2125 | h << ");" << endl; | | |||
2126 | } | | |||
2127 | h << endl; | | |||
2128 | | ||||
2129 | h << " private:" << endl; | | |||
2130 | h << " void itemChanged(quint64 flags);" << endl; | | |||
2131 | h << endl; | | |||
2132 | } | | |||
2133 | | ||||
2134 | h << " protected:" << endl; | | |||
2135 | | ||||
2136 | // Private constructor for singleton | | |||
2137 | if (cfg.singleton) { | | |||
2138 | h << " " << cfg.className << "("; | | |||
2139 | if (cfgFileNameArg) { | | |||
2140 | h << "KSharedConfig::Ptr config"; | | |||
2141 | } | | |||
2142 | if (cfg.parentInConstructor) { | | |||
2143 | if (cfgFileNameArg) { | | |||
2144 | h << ", "; | | |||
2145 | } | | |||
2146 | h << "QObject *parent = nullptr"; | | |||
2147 | } | | |||
2148 | h << ");" << endl; | | |||
2149 | h << " friend class " << cfg.className << "Helper;" << endl << endl; | | |||
2150 | } | | |||
2151 | | ||||
2152 | if (hasNonModifySignals) { | | |||
2153 | h << " bool usrSave() override;" << endl; | | |||
2154 | } | | |||
2155 | | ||||
2156 | // Member variables | | |||
2157 | if (!cfg.memberVariables.isEmpty() && cfg.memberVariables != QLatin1String("private") && cfg.memberVariables != QLatin1String("dpointer")) { | | |||
2158 | h << " " << cfg.memberVariables << ":" << endl; | | |||
2159 | } | | |||
2160 | | ||||
2161 | // Class Parameters | | |||
2162 | for (QList<Param>::ConstIterator it = parameters.constBegin(); | | |||
2163 | it != parameters.constEnd(); ++it) { | | |||
2164 | h << " " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl; | | |||
2165 | } | | |||
2166 | 753 | | |||
2167 | if (cfg.memberVariables != QLatin1String("dpointer")) { | 754 | KConfigXmlParser xmlParser(cfg, inputFilename); | ||
2168 | QString group; | | |||
2169 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2170 | if ((*itEntry)->group() != group) { | | |||
2171 | group = (*itEntry)->group(); | | |||
2172 | h << endl; | | |||
2173 | h << " // " << group << endl; | | |||
2174 | } | | |||
2175 | h << " " << cppType((*itEntry)->type()) << " " << varName((*itEntry)->name(), cfg); | | |||
2176 | if (!(*itEntry)->param().isEmpty()) { | | |||
2177 | h << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); | | |||
2178 | } | | |||
2179 | h << ";" << endl; | | |||
2180 | 755 | | |||
2181 | if (cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name())) { | 756 | // The Xml Parser aborts in the case of an error, so if we get | ||
2182 | h << " "; | 757 | // to parseResult, we have a working Xml file. | ||
2183 | if (cfg.staticAccessors) { | 758 | xmlParser.start(); | ||
2184 | h << "static "; | | |||
2185 | } | | |||
2186 | h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper("; | | |||
2187 | if (!(*itEntry)->param().isEmpty()) { | | |||
2188 | h << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
2189 | } | | |||
2190 | h << ")" << Const << ";" << endl; | | |||
2191 | } | | |||
2192 | } | | |||
2193 | 759 | | |||
2194 | h << endl << " private:" << endl; | 760 | ParseResult parseResult = xmlParser.getParseResult(); | ||
dfaure: const ... ? | |||||
that was a bit harder than I want, but done. Inside of the code generation there was code that manipulated the ParseResult. I think this is one of the good spots that show that this rewrite is really needed. tcanabrava: that was a bit harder than I want, but done. Inside of the code generation there was code that… | |||||
aaaaaand no, this introduced regressions, I'll try to solve it later but it's not as simple. this will unfortunately still be modified inside of the generator files. :/ tcanabrava: aaaaaand no, this introduced regressions, I'll try to solve it later but it's not as simple. | |||||
2195 | if (cfg.itemAccessors) { | | |||
2196 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2197 | h << " Item" << itemType((*itEntry)->type()) << " *" << itemVar(*itEntry, cfg); | | |||
2198 | if (!(*itEntry)->param().isEmpty()) { | | |||
2199 | h << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); | | |||
2200 | } | | |||
2201 | h << ";" << endl; | | |||
2202 | } | | |||
2203 | } | | |||
2204 | if (hasNonModifySignals) { | | |||
2205 | h << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl; | | |||
2206 | } | | |||
2207 | 761 | | |||
2208 | } else { | 762 | if (hasErrors(xmlParser, parseResult, cfg)) { | ||
2209 | // use a private class for both member variables and items | | |||
2210 | h << " private:" << endl; | | |||
2211 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2212 | if (cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name())) { | | |||
2213 | h << " "; | | |||
2214 | if (cfg.staticAccessors) { | | |||
2215 | h << "static "; | | |||
2216 | } | | |||
2217 | h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper("; | | |||
2218 | if (!(*itEntry)->param().isEmpty()) { | | |||
2219 | h << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
2220 | } | | |||
2221 | h << ")" << Const << ";" << endl; | | |||
2222 | } | | |||
2223 | } | | |||
2224 | h << " " + cfg.className + "Private *d;" << endl; | | |||
2225 | } | | |||
2226 | | ||||
2227 | if (cfg.customAddons) { | | |||
2228 | h << " // Include custom additions" << endl; | | |||
2229 | h << " #include \"" << baseName << "_addons." << cfg.headerExtension << '"' << endl; | | |||
2230 | } | | |||
2231 | | ||||
2232 | h << "};" << endl << endl; | | |||
2233 | | ||||
2234 | endNamespaces(cfg.nameSpace, h); | | |||
2235 | | ||||
2236 | h << "#endif" << endl << endl; | | |||
2237 | | ||||
2238 | header.close(); | | |||
2239 | | ||||
2240 | QFile implementation(baseDir + implementationFileName); | | |||
2241 | if (!implementation.open(QIODevice::WriteOnly)) { | | |||
2242 | cerr << "Can not open '" << implementationFileName << "for writing." | | |||
2243 | << endl; | | |||
2244 | return 1; | 763 | return 1; | ||
2245 | } | 764 | } | ||
2246 | 765 | | |||
2247 | QTextStream cpp(&implementation); | 766 | // TODO: Move this to somewhere saner. | ||
2248 | 767 | for (const auto &signal : qAsConst(parseResult.signalList)) { | |||
2249 | cpp.setCodec("utf-8"); | 768 | parseResult.hasNonModifySignals |= !signal.modify; | ||
2250 | | ||||
2251 | cpp << "// This file is generated by kconfig_compiler_kf5 from " << QFileInfo(inputFilename).fileName() << "." << endl; | | |||
2252 | cpp << "// All changes you do to this file will be lost." << endl << endl; | | |||
2253 | | ||||
2254 | cpp << "#include \"" << headerFileName << "\"" << endl << endl; | | |||
2255 | | ||||
2256 | for (it = cfg.sourceIncludes.constBegin(); it != cfg.sourceIncludes.constEnd(); ++it) { | | |||
2257 | if ((*it).startsWith('"')) { | | |||
2258 | cpp << "#include " << *it << endl; | | |||
2259 | } else { | | |||
2260 | cpp << "#include <" << *it << ">" << endl; | | |||
2261 | } | | |||
2262 | } | 769 | } | ||
2263 | 770 | | |||
2264 | if (!cfg.sourceIncludes.isEmpty()) { | 771 | // remove '.kcfg' from the name. | ||
2265 | cpp << endl; | 772 | const QString baseName = inputFilename.mid(0, inputFilename.size()-5); | ||
dfaure: ^ | |||||
2266 | } | 773 | KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult); | ||
2267 | 774 | headerGenerator.start(); | |||
2268 | if (cfg.setUserTexts && cfg.translationSystem == CfgConfig::KdeTranslation) { | 775 | headerGenerator.save(); | ||
2269 | cpp << "#include <klocalizedstring.h>" << endl << endl; | | |||
2270 | } | | |||
2271 | | ||||
2272 | // Header required by singleton implementation | | |||
2273 | if (cfg.singleton) { | | |||
2274 | cpp << "#include <qglobal.h>" << endl << "#include <QFile>" << endl << endl; | | |||
2275 | } | | |||
2276 | if (cfg.singleton && cfgFileNameArg) { | | |||
2277 | cpp << "#include <QDebug>" << endl << endl; | | |||
2278 | } | | |||
2279 | | ||||
2280 | if (!cfg.nameSpace.isEmpty()) { | | |||
2281 | cpp << "using namespace " << cfg.nameSpace << ";" << endl << endl; | | |||
2282 | } | | |||
2283 | | ||||
2284 | QString group; | | |||
2285 | | ||||
2286 | // private class implementation | | |||
2287 | if (cfg.dpointer) { | | |||
2288 | beginNamespaces(cfg.nameSpace, cpp); | | |||
2289 | cpp << "class " << cfg.className << "Private" << endl; | | |||
2290 | cpp << "{" << endl; | | |||
2291 | cpp << " public:" << endl; | | |||
2292 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2293 | if ((*itEntry)->group() != group) { | | |||
2294 | group = (*itEntry)->group(); | | |||
2295 | cpp << endl; | | |||
2296 | cpp << " // " << group << endl; | | |||
2297 | } | | |||
2298 | cpp << " " << cppType((*itEntry)->type()) << " " << varName((*itEntry)->name(), cfg); | | |||
2299 | if (!(*itEntry)->param().isEmpty()) { | | |||
2300 | cpp << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); | | |||
2301 | } | | |||
2302 | cpp << ";" << endl; | | |||
2303 | } | | |||
2304 | cpp << endl << " // items" << endl; | | |||
2305 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2306 | const QString declType = (*itEntry)->signalList().isEmpty() | | |||
2307 | ? QString(cfg.inherits + "::Item" + itemType((*itEntry)->type())) | | |||
2308 | : QStringLiteral("KConfigCompilerSignallingItem"); | | |||
2309 | cpp << " " << declType << " *" << itemVar( *itEntry, cfg ); | | |||
2310 | if (!(*itEntry)->param().isEmpty()) { | | |||
2311 | cpp << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); | | |||
2312 | } | | |||
2313 | cpp << ";" << endl; | | |||
2314 | } | | |||
2315 | if (hasNonModifySignals) { | | |||
2316 | cpp << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl; | | |||
2317 | } | | |||
2318 | | ||||
2319 | cpp << "};" << endl << endl; | | |||
2320 | endNamespaces(cfg.nameSpace, cpp); | | |||
2321 | } | | |||
2322 | | ||||
2323 | // Singleton implementation | | |||
2324 | if (cfg.singleton) { | | |||
2325 | beginNamespaces(cfg.nameSpace, cpp); | | |||
2326 | cpp << "class " << cfg.className << "Helper" << endl; | | |||
2327 | cpp << '{' << endl; | | |||
2328 | cpp << " public:" << endl; | | |||
2329 | cpp << " " << cfg.className << "Helper() : q(nullptr) {}" << endl; | | |||
2330 | cpp << " ~" << cfg.className << "Helper() { delete q; }" << endl; | | |||
2331 | cpp << " " << cfg.className << "Helper(const " << cfg.className << "Helper&) = delete;" << endl; | | |||
2332 | cpp << " " << cfg.className << "Helper& operator=(const " << cfg.className << "Helper&) = delete;" << endl; | | |||
2333 | cpp << " " << cfg.className << " *q;" << endl; | | |||
2334 | cpp << "};" << endl; | | |||
2335 | endNamespaces(cfg.nameSpace, cpp); | | |||
2336 | cpp << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl; | | |||
2337 | | ||||
2338 | cpp << cfg.className << " *" << cfg.className << "::self()" << endl; | | |||
2339 | cpp << "{" << endl; | | |||
2340 | if (cfgFileNameArg) { | | |||
2341 | cpp << " if (!s_global" << cfg.className << "()->q)" << endl; | | |||
2342 | cpp << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl; | | |||
2343 | } else { | | |||
2344 | cpp << " if (!s_global" << cfg.className << "()->q) {" << endl; | | |||
2345 | cpp << " new " << cfg.className << ';' << endl; | | |||
2346 | cpp << " s_global" << cfg.className << "()->q->read();" << endl; | | |||
2347 | cpp << " }" << endl << endl; | | |||
2348 | } | | |||
2349 | cpp << " return s_global" << cfg.className << "()->q;" << endl; | | |||
2350 | cpp << "}" << endl << endl; | | |||
2351 | | ||||
2352 | if (cfgFileNameArg) { | | |||
2353 | auto instance = [&cfg, &cpp] (const QString &type, const QString &arg, bool isString) { | | |||
2354 | cpp << "void " << cfg.className << "::instance(" << type << " " << arg << ")" << endl; | | |||
2355 | cpp << "{" << endl; | | |||
2356 | cpp << " if (s_global" << cfg.className << "()->q) {" << endl; | | |||
2357 | cpp << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl; | | |||
2358 | cpp << " return;" << endl; | | |||
2359 | cpp << " }" << endl; | | |||
2360 | cpp << " new " << cfg.className << "("; | | |||
2361 | if (isString) { | | |||
2362 | cpp << "KSharedConfig::openConfig(" << arg << ")"; | | |||
2363 | } else { | | |||
2364 | cpp << "std::move(" << arg << ")"; | | |||
2365 | } | | |||
2366 | cpp << ");" << endl; | | |||
2367 | cpp << " s_global" << cfg.className << "()->q->read();" << endl; | | |||
2368 | cpp << "}" << endl << endl; | | |||
2369 | }; | | |||
2370 | instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true); | | |||
2371 | instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false); | | |||
2372 | } | | |||
2373 | } | | |||
2374 | | ||||
2375 | if (!cppPreamble.isEmpty()) { | | |||
2376 | cpp << cppPreamble << endl; | | |||
2377 | } | | |||
2378 | | ||||
2379 | // Constructor | | |||
2380 | cpp << cfg.className << "::" << cfg.className << "("; | | |||
2381 | if (cfgFileNameArg) { | | |||
2382 | if (! cfg.forceStringFilename) { | | |||
2383 | cpp << " KSharedConfig::Ptr config"; | | |||
2384 | } else { | | |||
2385 | cpp << " const QString& config"; | | |||
2386 | } | | |||
2387 | cpp << (parameters.isEmpty() ? "" : ","); | | |||
2388 | } | | |||
2389 | | ||||
2390 | for (QList<Param>::ConstIterator it = parameters.constBegin(); | | |||
2391 | it != parameters.constEnd(); ++it) { | | |||
2392 | if (it != parameters.constBegin()) { | | |||
2393 | cpp << ","; | | |||
2394 | } | | |||
2395 | cpp << " " << param((*it).type) << " " << (*it).name; | | |||
2396 | } | | |||
2397 | | ||||
2398 | if (cfg.parentInConstructor) { | | |||
2399 | if (cfgFileNameArg || !parameters.isEmpty()) { | | |||
2400 | cpp << ","; | | |||
2401 | } | | |||
2402 | cpp << " QObject *parent"; | | |||
2403 | } | | |||
2404 | cpp << " )" << endl; | | |||
2405 | | ||||
2406 | cpp << " : " << cfg.inherits << "("; | | |||
2407 | if (!cfgFileName.isEmpty()) { | | |||
2408 | cpp << " QStringLiteral( \"" << cfgFileName << "\" "; | | |||
2409 | } | | |||
2410 | if (cfgFileNameArg) { | | |||
2411 | if (! cfg.forceStringFilename) { | | |||
2412 | cpp << " std::move( config ) "; | | |||
2413 | } else { | | |||
2414 | cpp << " config "; | | |||
2415 | } | | |||
2416 | } | | |||
2417 | if (!cfgFileName.isEmpty()) { | | |||
2418 | cpp << ") "; | | |||
2419 | } | | |||
2420 | cpp << ")" << endl; | | |||
2421 | | ||||
2422 | // Store parameters | | |||
2423 | for (QList<Param>::ConstIterator it = parameters.constBegin(); | | |||
2424 | it != parameters.constEnd(); ++it) { | | |||
2425 | cpp << " , mParam" << (*it).name << "(" << (*it).name << ")" << endl; | | |||
2426 | } | | |||
2427 | | ||||
2428 | if (hasNonModifySignals && !cfg.dpointer) { | | |||
2429 | cpp << " , " << varName(QStringLiteral("settingsChanged"), cfg) << "(0)" << endl; | | |||
2430 | } | | |||
2431 | | ||||
2432 | cpp << "{" << endl; | | |||
2433 | | ||||
2434 | if (cfg.parentInConstructor) { | | |||
2435 | cpp << " setParent(parent);" << endl; | | |||
2436 | } | | |||
2437 | | ||||
2438 | if (cfg.dpointer) { | | |||
2439 | cpp << " d = new " + cfg.className + "Private;" << endl; | | |||
2440 | if (hasNonModifySignals) { | | |||
2441 | cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; | | |||
2442 | } | | |||
2443 | } | | |||
2444 | // Needed in case the singleton class is used as baseclass for | | |||
2445 | // another singleton. | | |||
2446 | if (cfg.singleton) { | | |||
2447 | cpp << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl; | | |||
2448 | cpp << " s_global" << cfg.className << "()->q = this;" << endl; | | |||
2449 | } | | |||
2450 | | ||||
2451 | group.clear(); | | |||
2452 | | ||||
2453 | if (hasSignals) { | | |||
2454 | // this cast to base-class pointer-to-member is valid C++ | | |||
2455 | // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/ | | |||
2456 | cpp << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction =" | | |||
2457 | << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&" | | |||
2458 | << cfg.className << "::itemChanged);" << endl << endl; | | |||
2459 | } | | |||
2460 | | ||||
2461 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2462 | if ((*itEntry)->group() != group) { | | |||
2463 | if (!group.isEmpty()) { | | |||
2464 | cpp << endl; | | |||
2465 | } | | |||
2466 | group = (*itEntry)->group(); | | |||
2467 | cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl; | | |||
2468 | } | | |||
2469 | | ||||
2470 | QString key = paramString((*itEntry)->key(), parameters); | | |||
2471 | if (!(*itEntry)->code().isEmpty()) { | | |||
2472 | cpp << (*itEntry)->code() << endl; | | |||
2473 | } | | |||
2474 | if ((*itEntry)->type() == QLatin1String("Enum")) { | | |||
2475 | cpp << " QList<" + cfg.inherits + "::ItemEnum::Choice> values" | | |||
2476 | << (*itEntry)->name() << ";" << endl; | | |||
2477 | const QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices; | | |||
2478 | QList<CfgEntry::Choice>::ConstIterator it; | | |||
2479 | for (it = choices.constBegin(); it != choices.constEnd(); ++it) { | | |||
2480 | cpp << " {" << endl; | | |||
2481 | cpp << " " + cfg.inherits + "::ItemEnum::Choice choice;" << endl; | | |||
2482 | cpp << " choice.name = QStringLiteral(\"" << (*it).name << "\");" << endl; | | |||
2483 | if (cfg.setUserTexts) { | | |||
2484 | if (!(*it).label.isEmpty()) { | | |||
2485 | cpp << " choice.label = " | | |||
2486 | << translatedString(cfg, (*it).label, (*it).context) | | |||
2487 | << ";" << endl; | | |||
2488 | } | | |||
2489 | if (!(*it).toolTip.isEmpty()) { | | |||
2490 | cpp << " choice.toolTip = " | | |||
2491 | << translatedString(cfg, (*it).toolTip, (*it).context) | | |||
2492 | << ";" << endl; | | |||
2493 | } | | |||
2494 | if (!(*it).whatsThis.isEmpty()) { | | |||
2495 | cpp << " choice.whatsThis = " | | |||
2496 | << translatedString(cfg, (*it).whatsThis, (*it).context) | | |||
2497 | << ";" << endl; | | |||
2498 | } | | |||
2499 | } | | |||
2500 | cpp << " values" << (*itEntry)->name() << ".append( choice );" << endl; | | |||
2501 | cpp << " }" << endl; | | |||
2502 | } | | |||
2503 | } | | |||
2504 | | ||||
2505 | if (!cfg.dpointer) { | | |||
2506 | cpp << itemDeclaration(*itEntry, cfg); | | |||
2507 | } | | |||
2508 | | ||||
2509 | if ((*itEntry)->param().isEmpty()) { | | |||
2510 | // Normal case | | |||
2511 | cpp << " " << itemPath(*itEntry, cfg) << " = " | | |||
2512 | << newItem((*itEntry), key, (*itEntry)->defaultValue(), cfg) << endl; | | |||
2513 | | ||||
2514 | if (!(*itEntry)->minValue().isEmpty()) { | | |||
2515 | cpp << " " << itemPath(*itEntry, cfg) << "->setMinValue(" << (*itEntry)->minValue() << ");" << endl; | | |||
2516 | } | | |||
2517 | if (!(*itEntry)->maxValue().isEmpty()) { | | |||
2518 | cpp << " " << itemPath(*itEntry, cfg) << "->setMaxValue(" << (*itEntry)->maxValue() << ");" << endl; | | |||
2519 | } | | |||
2520 | | ||||
2521 | if (cfg.setUserTexts) { | | |||
2522 | cpp << userTextsFunctions((*itEntry), cfg); | | |||
2523 | } | | |||
2524 | | ||||
2525 | if (cfg.allNotifiers || cfg.notifiers.contains((*itEntry)->name())) { | | |||
2526 | cpp << " " << itemPath(*itEntry, cfg) << "->setWriteFlags(KConfigBase::Notify);" << endl; | | |||
2527 | } | | |||
2528 | | ||||
2529 | cpp << " addItem( " << itemPath(*itEntry, cfg); | | |||
2530 | QString quotedName = (*itEntry)->name(); | | |||
2531 | addQuotes(quotedName); | | |||
2532 | if (quotedName != key) { | | |||
2533 | cpp << ", QStringLiteral( \"" << (*itEntry)->name() << "\" )"; | | |||
2534 | } | | |||
2535 | cpp << " );" << endl; | | |||
2536 | } else { | | |||
2537 | // Indexed | | |||
2538 | for (int i = 0; i <= (*itEntry)->paramMax(); i++) { | | |||
2539 | QString defaultStr; | | |||
2540 | QString itemVarStr(itemPath(*itEntry, cfg) + QStringLiteral("[%1]").arg(i)); | | |||
2541 | | ||||
2542 | if (!(*itEntry)->paramDefaultValue(i).isEmpty()) { | | |||
2543 | defaultStr = (*itEntry)->paramDefaultValue(i); | | |||
2544 | } else if (!(*itEntry)->defaultValue().isEmpty()) { | | |||
2545 | defaultStr = paramString((*itEntry)->defaultValue(), (*itEntry), i); | | |||
2546 | } else { | | |||
2547 | defaultStr = defaultValue((*itEntry)->type()); | | |||
2548 | } | | |||
2549 | | ||||
2550 | cpp << " " << itemVarStr << " = " | | |||
2551 | << newItem((*itEntry), paramString(key, *itEntry, i), defaultStr, cfg, QStringLiteral("[%1]").arg(i)) << endl; | | |||
2552 | | ||||
2553 | if (cfg.setUserTexts) { | | |||
2554 | cpp << userTextsFunctions(*itEntry, cfg, itemVarStr, (*itEntry)->paramName()); | | |||
2555 | } | | |||
2556 | | ||||
2557 | // Make mutators for enum parameters work by adding them with $(..) replaced by the | | |||
2558 | // param name. The check for isImmutable in the set* functions doesn't have the param | | |||
2559 | // name available, just the corresponding enum value (int), so we need to store the | | |||
2560 | // param names in a separate static list!. | | |||
2561 | cpp << " addItem( " << itemVarStr << ", QStringLiteral( \""; | | |||
2562 | if ((*itEntry)->paramType() == QLatin1String("Enum")) { | | |||
2563 | cpp << (*itEntry)->paramName().replace("$(" + (*itEntry)->param() + ')', QLatin1String("%1")).arg((*itEntry)->paramValues()[i]); | | |||
2564 | } else { | | |||
2565 | cpp << (*itEntry)->paramName().replace("$(" + (*itEntry)->param() + ')', QLatin1String("%1")).arg(i); | | |||
2566 | } | | |||
2567 | cpp << "\" ) );" << endl; | | |||
2568 | } | | |||
2569 | } | | |||
2570 | } | | |||
2571 | | ||||
2572 | cpp << "}" << endl << endl; | | |||
2573 | | ||||
2574 | if (cfg.dpointer) { | | |||
2575 | // setters and getters go in Cpp if in dpointer mode | | |||
2576 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2577 | QString n = (*itEntry)->name(); | | |||
2578 | QString t = (*itEntry)->type(); | | |||
2579 | | ||||
2580 | // Manipulator | | |||
2581 | if (cfg.allMutators || cfg.mutators.contains(n)) { | | |||
2582 | cpp << "void " << setFunction(n, cfg.className) << "( "; | | |||
2583 | if (!(*itEntry)->param().isEmpty()) { | | |||
2584 | cpp << cppType((*itEntry)->paramType()) << " i, "; | | |||
2585 | } | | |||
2586 | if (cfg.useEnumTypes && t == QLatin1String("Enum")) { | | |||
2587 | cpp << enumType(*itEntry, cfg.globalEnums); | | |||
2588 | } else { | | |||
2589 | cpp << param(t); | | |||
2590 | } | | |||
2591 | cpp << " v )" << endl; | | |||
2592 | // function body inline only if not using dpointer | | |||
2593 | // for BC mode | | |||
2594 | cpp << "{" << endl; | | |||
2595 | cpp << indent(memberMutatorBody(*itEntry, cfg), 6); | | |||
2596 | cpp << "}" << endl << endl; | | |||
2597 | } | | |||
2598 | | ||||
2599 | // Accessor | | |||
2600 | if (cfg.useEnumTypes && t == QLatin1String("Enum")) { | | |||
2601 | cpp << enumType(*itEntry, cfg.globalEnums); | | |||
2602 | } else { | | |||
2603 | cpp << cppType(t); | | |||
2604 | } | | |||
2605 | cpp << " " << getFunction(n, cfg.className) << "("; | | |||
2606 | if (!(*itEntry)->param().isEmpty()) { | | |||
2607 | cpp << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
2608 | } | | |||
2609 | cpp << ")" << Const << endl; | | |||
2610 | // function body inline only if not using dpointer | | |||
2611 | // for BC mode | | |||
2612 | cpp << "{" << endl; | | |||
2613 | cpp << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 2); | | |||
2614 | cpp << "}" << endl << endl; | | |||
2615 | | ||||
2616 | // Default value Accessor -- written by the loop below | | |||
2617 | | ||||
2618 | // Item accessor | | |||
2619 | if (cfg.itemAccessors) { | | |||
2620 | cpp << endl; | | |||
2621 | cpp << cfg.inherits + "::Item" << itemType((*itEntry)->type()) << " *" | | |||
2622 | << getFunction(n, cfg.className) << "Item("; | | |||
2623 | if (!(*itEntry)->param().isEmpty()) { | | |||
2624 | cpp << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
2625 | } | | |||
2626 | cpp << ")" << endl; | | |||
2627 | cpp << "{" << endl; | | |||
2628 | cpp << indent(itemAccessorBody(*itEntry, cfg), 2); | | |||
2629 | cpp << "}" << endl; | | |||
2630 | } | | |||
2631 | | ||||
2632 | cpp << endl; | | |||
2633 | } | | |||
2634 | } | | |||
2635 | | ||||
2636 | // default value getters always go in Cpp | | |||
2637 | for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { | | |||
2638 | QString n = (*itEntry)->name(); | | |||
2639 | QString t = (*itEntry)->type(); | | |||
2640 | | ||||
2641 | // Default value Accessor, as "helper" function | | |||
2642 | if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) { | | |||
2643 | cpp << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper("; | | |||
2644 | if (!(*itEntry)->param().isEmpty()) { | | |||
2645 | cpp << " " << cppType((*itEntry)->paramType()) << " i "; | | |||
2646 | } | | |||
2647 | cpp << ")" << Const << endl; | | |||
2648 | cpp << "{" << endl; | | |||
2649 | cpp << memberGetDefaultBody(*itEntry) << endl; | | |||
2650 | cpp << "}" << endl << endl; | | |||
2651 | } | | |||
2652 | } | | |||
2653 | | ||||
2654 | // Destructor | | |||
2655 | cpp << cfg.className << "::~" << cfg.className << "()" << endl; | | |||
2656 | cpp << "{" << endl; | | |||
2657 | if (cfg.dpointer) { | | |||
2658 | cpp << " delete d;" << endl; | | |||
2659 | } | | |||
2660 | if (cfg.singleton) { | | |||
2661 | cpp << " s_global" << cfg.className << "()->q = nullptr;" << endl; | | |||
2662 | } | | |||
2663 | cpp << "}" << endl << endl; | | |||
2664 | | ||||
2665 | if (hasNonModifySignals) { | | |||
2666 | cpp << "bool " << cfg.className << "::" << "usrSave()" << endl; | | |||
2667 | cpp << "{" << endl; | | |||
2668 | cpp << " const bool res = " << cfg.inherits << "::usrSave();" << endl; | | |||
2669 | cpp << " if (!res) return false;" << endl << endl; | | |||
2670 | for (const Signal &signal : qAsConst(signalList)) { | | |||
2671 | if (signal.modify) { | | |||
2672 | continue; | | |||
2673 | } | | |||
2674 | | ||||
2675 | cpp << " if ( " << varPath(QStringLiteral("settingsChanged"), cfg) << " & " << signalEnumName(signal.name) << " )" << endl; | | |||
2676 | cpp << " Q_EMIT " << signal.name << "("; | | |||
2677 | QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd(); | | |||
2678 | for (it = signal.arguments.constBegin(); it != itEnd;) { | | |||
2679 | SignalArguments argument = *it; | | |||
2680 | bool cast = false; | | |||
2681 | if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) { | | |||
2682 | for (int i = 0, end = entries.count(); i < end; ++i) { | | |||
2683 | if (entries[i]->name() == argument.variableName) { | | |||
2684 | cpp << "static_cast<" << enumType(entries[i], cfg.globalEnums) << ">("; | | |||
2685 | cast = true; | | |||
2686 | break; | | |||
2687 | } | | |||
2688 | } | | |||
2689 | } | | |||
2690 | cpp << varPath(argument.variableName, cfg); | | |||
2691 | if (cast) { | | |||
2692 | cpp << ")"; | | |||
2693 | } | | |||
2694 | if (++it != itEnd) { | | |||
2695 | cpp << ", "; | | |||
2696 | } | | |||
2697 | } | | |||
2698 | cpp << ");" << endl; | | |||
2699 | } | | |||
2700 | | ||||
2701 | cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; | | |||
2702 | cpp << " return true;" << endl; | | |||
2703 | cpp << "}" << endl; | | |||
2704 | } | | |||
2705 | | ||||
2706 | if (hasSignals) { | | |||
2707 | cpp << endl; | | |||
2708 | cpp << "void " << cfg.className << "::" << "itemChanged(quint64 flags) {" << endl; | | |||
2709 | if (hasNonModifySignals) | | |||
2710 | cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " |= flags;" << endl; | | |||
2711 | | ||||
2712 | if (!signalList.isEmpty()) | | |||
2713 | cpp << endl; | | |||
2714 | | ||||
2715 | for (const Signal &signal : qAsConst(signalList)) { | | |||
2716 | if (signal.modify) { | | |||
2717 | cpp << " if ( flags & " << signalEnumName(signal.name) << " ) {" << endl; | | |||
2718 | cpp << " Q_EMIT " << signal.name << "();" << endl; | | |||
2719 | cpp << " }" << endl; | | |||
2720 | } | | |||
2721 | } | | |||
2722 | | ||||
2723 | cpp << "}" << endl; | | |||
2724 | } | | |||
2725 | | ||||
2726 | if (hasSignals || cfg.generateProperties) { | | |||
2727 | // Add includemoc if they are signals defined. | | |||
2728 | cpp << endl; | | |||
2729 | cpp << "#include \"" << mocFileName << "\"" << endl; | | |||
2730 | cpp << endl; | | |||
2731 | } | | |||
2732 | 776 | | |||
2733 | // clear entries list | 777 | KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult); | ||
2734 | qDeleteAll(entries); | 778 | sourceGenerator.start(); | ||
779 | sourceGenerator.save(); | ||||
2735 | 780 | | |||
2736 | implementation.close(); | 781 | qDeleteAll(parseResult.entries); | ||
2737 | } | 782 | } |
Space before & not after