diff options
author | Tomaz Canabrava <tcanabrava@kde.org> | 2020-01-14 18:52:43 +0000 |
---|---|---|
committer | Tomaz Canabrava <tcanabrava@kde.org> | 2020-01-16 10:15:36 +0000 |
commit | 98c32e29f50465d4d4e16bafdf0491edbfb422b0 (patch) | |
tree | 06898a9ff9a5ed2e385b25a6b7fe258bb9eacb9c /src/kconfig_compiler/kconfig_compiler.cpp | |
parent | a601ac563d33681569befd22c9182cddaecf30b1 (diff) | |
download | kconfig-98c32e29f50465d4d4e16bafdf0491edbfb422b0.tar.gz kconfig-98c32e29f50465d4d4e16bafdf0491edbfb422b0.tar.bz2 |
WIP: Refactor KConfigXT
Summary:
The current KConfigXT compiler is in a sad state:
It's a massive file with loads of global variables that handle state, the generator is done within the main() function and it seems to have grown organically. There are no classes to separate logic / state / generation, what exists is code that generates code from a xml / ini pair, but it's hard to even discover what a bit of code is doing. The code istyle is C++ / Java from the nineties, which is not bad per see but it also uses quite a few things that are going to be deprecated in Qt 6 so I'm also taking the time make the code more streamlined with newer code style (no iterators, lambdas, auto usage, etc).
The code that generates the files simplly pushes strings to a text stream, and it's hard to figure out when something starts or something ends: for instance, the code that generates the Constructor has more than sixty lines of code englobing some nested if - for - if - for constructs.
Currently the code is "done" - there's one bug that I still need to find & fix regarding Translations, but the rest seems sane.
The current testcode generates incorrect *whitespaces* regarding the old code (there's some parts that I feel that it's important to fix before merging, but overall, the whitespace changes are not bad and easier to handle, old code had a hand-counted amount of spaces before each line, new code has a function whitespace() that adds the current-and-correct amount of whitespaces based on indentation level that you start by startScope() and ends with endScope(). rest of the code still needs to be ported to it.
I plan to fix the testcases whitespace by manually adding them, I'v fougth with the code for a while and added a few hacks there but I don't want to make the code hackish again.
New code is not perfect by any means, but is a good step in the right direction.
This code tries to Separate the compiler code into many different files / classes to be more obvious what's happening, and each class also has many helper methods to minimize copypaste.
- CodeGenerator: Has base code for the header and source files that can be shared
- HeaderGenerator: Logic for generating the header file
- SourceGenerator: Logic for generating the source file
- KcfgParser: Logic for parsing the kcfg file and extracting the information from the Xml file
- CommonStructs: a header that contains the structs that are currently used everywhere.
- KConfigParameters: (was CfgConfig - ConfigConfig, wat) - Has information passed via the kcfgc file
- kcfg_compiler - will be renamed to main - start the other classes and generates the files.
This code here currently has the begining of this separation, with the CodeGenerator and the HeaderGenerator in a ~good~ state, but unfinished.
Test Plan:
- Run the test cases,
- Compare the diffs generated by the testcases and fix in the code the errors / differences
- Run and compare real kde source with the new and old generators to look for errors
Reviewers: #frameworks, ervin, bport, dfaure
Reviewed By: dfaure
Subscribers: bport, ngraham, kde-frameworks-devel
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D26202
Diffstat (limited to 'src/kconfig_compiler/kconfig_compiler.cpp')
-rw-r--r-- | src/kconfig_compiler/kconfig_compiler.cpp | 2208 |
1 files changed, 120 insertions, 2088 deletions
diff --git a/src/kconfig_compiler/kconfig_compiler.cpp b/src/kconfig_compiler/kconfig_compiler.cpp index 848595f2..00699c36 100644 --- a/src/kconfig_compiler/kconfig_compiler.cpp +++ b/src/kconfig_compiler/kconfig_compiler.cpp @@ -34,15 +34,19 @@ #include <QDomAttr> #include <QRegularExpression> #include <QStringList> - -#include <qcommandlineparser.h> -#include <qcommandlineoption.h> +#include <QCommandLineParser> +#include <QCommandLineOption> #include <ostream> #include <iostream> #include <stdlib.h> #include "../../kconfig_version.h" +#include "KConfigXTParameters.h" +#include "KConfigCommonStructs.h" +#include "KConfigHeaderGenerator.h" +#include "KConfigSourceGenerator.h" +#include "KCFGXmlParser.h" namespace { @@ -50,444 +54,7 @@ QTextStream cout(stdout); QTextStream cerr(stderr); } -QStringList allNames; -QRegularExpression *validNameRegexp; -QString This; -QString Const; - -/** - Configuration Compiler Configuration -*/ -class CfgConfig -{ -public: - CfgConfig(const QString &codegenFilename) - { - // Configure the compiler with some settings - QSettings codegenConfig(codegenFilename, QSettings::IniFormat); - - nameSpace = codegenConfig.value(QStringLiteral("NameSpace")).toString(); - className = codegenConfig.value(QStringLiteral("ClassName")).toString(); - if (className.isEmpty()) { - cerr << "Class name missing" << endl; - exit(1); - } - inherits = codegenConfig.value(QStringLiteral("Inherits")).toString(); - if (inherits.isEmpty()) { - inherits = QStringLiteral("KConfigSkeleton"); - } - visibility = codegenConfig.value(QStringLiteral("Visibility")).toString(); - if (!visibility.isEmpty()) { - visibility += ' '; - } - parentInConstructor = codegenConfig.value(QStringLiteral("ParentInConstructor"), false).toBool(); - forceStringFilename = codegenConfig.value(QStringLiteral("ForceStringFilename"), false).toBool(); - singleton = codegenConfig.value(QStringLiteral("Singleton"), false).toBool(); - staticAccessors = singleton; - customAddons = codegenConfig.value(QStringLiteral("CustomAdditions"), false).toBool(); - memberVariables = codegenConfig.value(QStringLiteral("MemberVariables")).toString(); - dpointer = (memberVariables == QLatin1String("dpointer")); - headerIncludes = codegenConfig.value(QStringLiteral("IncludeFiles"), QStringList()).toStringList(); - sourceIncludes = codegenConfig.value(QStringLiteral("SourceIncludeFiles"), QStringList()).toStringList(); - mutators = codegenConfig.value(QStringLiteral("Mutators"), QStringList()).toStringList(); - allMutators = ((mutators.count() == 1) && (mutators.at(0).toLower() == QLatin1String("true"))); - itemAccessors = codegenConfig.value(QStringLiteral("ItemAccessors"), false).toBool(); - setUserTexts = codegenConfig.value(QStringLiteral("SetUserTexts"), false).toBool(); - defaultGetters = codegenConfig.value(QStringLiteral("DefaultValueGetters"), QStringList()).toStringList(); - allDefaultGetters = (defaultGetters.count() == 1) && (defaultGetters.at(0).toLower() == QLatin1String("true")); - notifiers = codegenConfig.value(QStringLiteral("Notifiers"), QStringList()).toStringList(); - allNotifiers = ((notifiers.count() == 1) && (notifiers.at(0).toLower() == QLatin1String("true"))); - globalEnums = codegenConfig.value(QStringLiteral("GlobalEnums"), false).toBool(); - useEnumTypes = codegenConfig.value(QStringLiteral("UseEnumTypes"), false).toBool(); - const QString trString = codegenConfig.value(QStringLiteral("TranslationSystem")).toString().toLower(); - generateProperties = codegenConfig.value(QStringLiteral("GenerateProperties"), false).toBool(); - if (trString == QLatin1String("kde")) { - translationSystem = KdeTranslation; - translationDomain = codegenConfig.value(QStringLiteral("TranslationDomain")).toString(); - } else { - if (!trString.isEmpty() && trString != QLatin1String("qt")) { - cerr << "Unknown translation system, falling back to Qt tr()" << endl; - } - translationSystem = QtTranslation; - } - qCategoryLoggingName = codegenConfig.value(QStringLiteral("CategoryLoggingName"), QString()).toString(); - headerExtension = codegenConfig.value(QStringLiteral("HeaderExtension"), QStringLiteral("h")).toString(); - sourceExtension = codegenConfig.value(QStringLiteral("SourceExtension"), QStringLiteral("cpp")).toString(); - } - -public: - enum TranslationSystem { - QtTranslation, - KdeTranslation - }; - - // These are read from the .kcfgc configuration file - QString nameSpace; // The namespace for the class to be generated - QString className; // The class name to be generated - QString inherits; // The class the generated class inherits (if empty, from KConfigSkeleton) - QString visibility; - bool parentInConstructor; // The class has the optional parent parameter in its constructor - bool forceStringFilename; - bool singleton; // The class will be a singleton - bool staticAccessors; // provide or not static accessors - bool customAddons; - QString memberVariables; - QStringList headerIncludes; - QStringList sourceIncludes; - QStringList mutators; - QStringList defaultGetters; - QStringList notifiers; - QString qCategoryLoggingName; - QString headerExtension; - QString sourceExtension; - bool allMutators; - bool setUserTexts; - bool allDefaultGetters; - bool dpointer; - bool globalEnums; - bool useEnumTypes; - bool itemAccessors; - bool allNotifiers; - TranslationSystem translationSystem; - QString translationDomain; - bool generateProperties; -}; - -struct SignalArguments { - QString type; - QString variableName; -}; - -class Signal -{ -public: - Signal() : modify(false) {} - - QString name; - QString label; - QList<SignalArguments> arguments; - bool modify; -}; - -class CfgEntry -{ -public: - struct Choice { - QString name; - QString context; - QString label; - QString toolTip; - QString whatsThis; - }; - class Choices - { - public: - Choices() {} - Choices(const QList<Choice> &d, const QString &n, const QString &p) - : prefix(p), choices(d), mName(n) - { - int i = n.indexOf(QLatin1String("::")); - if (i >= 0) { - mExternalQual = n.left(i + 2); - } - } - QString prefix; - QList<Choice> choices; - const QString &name() const - { - return mName; - } - const QString &externalQualifier() const - { - return mExternalQual; - } - bool external() const - { - return !mExternalQual.isEmpty(); - } - private: - QString mName; - QString mExternalQual; - }; - - CfgEntry(const QString &group, const QString &type, const QString &key, - const QString &name, const QString &labelContext, const QString &label, - const QString &toolTipContext, const QString &toolTip, const QString &whatsThisContext, const QString &whatsThis, const QString &code, - const QString &defaultValue, const Choices &choices, const QList<Signal> &signalList, - bool hidden) - : mGroup(group), mType(type), mKey(key), mName(name), - mLabelContext(labelContext), mLabel(label), mToolTipContext(toolTipContext), mToolTip(toolTip), - mWhatsThisContext(whatsThisContext), mWhatsThis(whatsThis), - mCode(code), mDefaultValue(defaultValue), mChoices(choices), - mSignalList(signalList), mParamMax(0), mHidden(hidden) - { - } - - void setGroup(const QString &group) - { - mGroup = group; - } - QString group() const - { - return mGroup; - } - - void setType(const QString &type) - { - mType = type; - } - QString type() const - { - return mType; - } - - void setKey(const QString &key) - { - mKey = key; - } - QString key() const - { - return mKey; - } - - void setName(const QString &name) - { - mName = name; - } - QString name() const - { - return mName; - } - - void setLabelContext(const QString &labelContext) - { - mLabelContext = labelContext; - } - QString labelContext() const - { - return mLabelContext; - } - - void setLabel(const QString &label) - { - mLabel = label; - } - QString label() const - { - return mLabel; - } - - void setToolTipContext(const QString &toolTipContext) - { - mToolTipContext = toolTipContext; - } - QString toolTipContext() const - { - return mToolTipContext; - } - - void setToolTip(const QString &toolTip) - { - mToolTip = toolTip; - } - QString toolTip() const - { - return mToolTip; - } - - void setWhatsThisContext(const QString &whatsThisContext) - { - mWhatsThisContext = whatsThisContext; - } - QString whatsThisContext() const - { - return mWhatsThisContext; - } - - void setWhatsThis(const QString &whatsThis) - { - mWhatsThis = whatsThis; - } - QString whatsThis() const - { - return mWhatsThis; - } - - void setDefaultValue(const QString &d) - { - mDefaultValue = d; - } - QString defaultValue() const - { - return mDefaultValue; - } - - void setCode(const QString &d) - { - mCode = d; - } - QString code() const - { - return mCode; - } - - void setMinValue(const QString &d) - { - mMin = d; - } - QString minValue() const - { - return mMin; - } - - void setMaxValue(const QString &d) - { - mMax = d; - } - QString maxValue() const - { - return mMax; - } - - void setParam(const QString &d) - { - mParam = d; - } - QString param() const - { - return mParam; - } - - void setParamName(const QString &d) - { - mParamName = d; - } - QString paramName() const - { - return mParamName; - } - - void setParamType(const QString &d) - { - mParamType = d; - } - QString paramType() const - { - return mParamType; - } - - void setChoices(const QList<Choice> &d, const QString &n, const QString &p) - { - mChoices = Choices(d, n, p); - } - Choices choices() const - { - return mChoices; - } - - void setParamValues(const QStringList &d) - { - mParamValues = d; - } - QStringList paramValues() const - { - return mParamValues; - } - - void setParamDefaultValues(const QStringList &d) - { - mParamDefaultValues = d; - } - QString paramDefaultValue(int i) const - { - return mParamDefaultValues[i]; - } - - void setParamMax(int d) - { - mParamMax = d; - } - int paramMax() const - { - return mParamMax; - } - - void setSignalList(const QList<Signal> &value) - { - mSignalList = value; - } - QList<Signal> signalList() const - { - return mSignalList; - } - - bool hidden() const - { - return mHidden; - } - - void dump() const - { - cerr << "<entry>" << endl; - cerr << " group: " << mGroup << endl; - cerr << " type: " << mType << endl; - cerr << " key: " << mKey << endl; - cerr << " name: " << mName << endl; - cerr << " label context: " << mLabelContext << endl; - cerr << " label: " << mLabel << endl; -// whatsthis - cerr << " code: " << mCode << endl; -// cerr << " values: " << mValues.join(":") << endl; - - if (!param().isEmpty()) { - cerr << " param name: " << mParamName << endl; - cerr << " param type: " << mParamType << endl; - cerr << " paramvalues: " << mParamValues.join(QChar::fromLatin1(':')) << endl; - } - cerr << " default: " << mDefaultValue << endl; - cerr << " hidden: " << mHidden << endl; - cerr << " min: " << mMin << endl; - cerr << " max: " << mMax << endl; - cerr << "</entry>" << endl; - } - -private: - QString mGroup; - QString mType; - QString mKey; - QString mName; - QString mLabelContext; - QString mLabel; - QString mToolTipContext; - QString mToolTip; - QString mWhatsThisContext; - QString mWhatsThis; - QString mCode; - QString mDefaultValue; - QString mParam; - QString mParamName; - QString mParamType; - Choices mChoices; - QList<Signal> mSignalList; - QStringList mParamValues; - QStringList mParamDefaultValues; - int mParamMax; - bool mHidden; - QString mMin; - QString mMax; -}; - -class Param -{ -public: - QString name; - QString type; -}; - -// returns the name of an member variable -// use itemPath to know the full path -// like using d-> in case of dpointer -static QString varName(const QString &n, const CfgConfig &cfg) +QString varName(const QString &n, const KConfigXTParameters &cfg) { QString result; if (!cfg.dpointer) { @@ -500,7 +67,7 @@ static QString varName(const QString &n, const CfgConfig &cfg) return result; } -static QString varPath(const QString &n, const CfgConfig &cfg) +QString varPath(const QString &n, const KConfigXTParameters &cfg) { QString result; if (cfg.dpointer) { @@ -511,14 +78,14 @@ static QString varPath(const QString &n, const CfgConfig &cfg) return result; } -static QString enumName(const QString &n) +QString enumName(const QString &n) { QString result = QLatin1String("Enum") + n; result[4] = result[4].toUpper(); return result; } -static QString enumName(const QString &n, const CfgEntry::Choices &c) +QString enumName(const QString &n, const CfgEntry::Choices &c) { QString result = c.name(); if (result.isEmpty()) { @@ -528,11 +95,11 @@ static QString enumName(const QString &n, const CfgEntry::Choices &c) return result; } -static QString enumType(const CfgEntry *e, bool globalEnums) +QString enumType(const CfgEntry *e, bool globalEnums) { - QString result = e->choices().name(); + QString result = e->choices.name(); if (result.isEmpty()) { - result = QLatin1String("Enum") + e->name(); + result = QLatin1String("Enum") + e->name; if (!globalEnums) { result += QLatin1String("::type"); } @@ -541,7 +108,7 @@ static QString enumType(const CfgEntry *e, bool globalEnums) return result; } -static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) +QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) { QString result = c.name(); if (result.isEmpty()) { @@ -555,7 +122,7 @@ static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) return result; } -static QString setFunction(const QString &n, const QString &className = QString()) +QString setFunction(const QString &n, const QString &className) { QString result = QLatin1String("set") + n; result[3] = result[3].toUpper(); @@ -566,12 +133,12 @@ static QString setFunction(const QString &n, const QString &className = QString( return result; } -static QString changeSignalName(const QString &n) +QString changeSignalName(const QString &n) { return n+QStringLiteral("Changed"); } -static QString getDefaultFunction(const QString &n, const QString &className = QString()) +QString getDefaultFunction(const QString &n, const QString &className) { QString result = QLatin1String("default") + n + QLatin1String("Value"); result[7] = result[7].toUpper(); @@ -582,7 +149,7 @@ static QString getDefaultFunction(const QString &n, const QString &className = Q return result; } -static QString getFunction(const QString &n, const QString &className = QString()) +QString getFunction(const QString &n, const QString &className) { QString result = n; result[0] = result[0].toLower(); @@ -593,7 +160,7 @@ static QString getFunction(const QString &n, const QString &className = QString( return result; } -static void addQuotes(QString &s) +void addQuotes(QString &s) { if (!s.startsWith(QLatin1Char('"'))) { s.prepend(QLatin1Char('"')); @@ -613,7 +180,7 @@ static QString quoteString(const QString &s) return QLatin1Char('\"') + r + QLatin1Char('\"'); } -static QString literalString(const QString &s) +QString literalString(const QString &s) { bool isAscii = true; for (int i = s.length(); i--;) @@ -628,20 +195,8 @@ static QString literalString(const QString &s) } } -static QString dumpNode(const QDomNode &node) -{ - QString msg; - QTextStream s(&msg, QIODevice::WriteOnly); - node.save(s, 0); - msg = msg.simplified(); - if (msg.length() > 40) { - return msg.left(37) + QLatin1String("..."); - } - return msg; -} - -static QString signalEnumName(const QString &signalName) +QString signalEnumName(const QString &signalName) { QString result; result = QLatin1String("signal") + signalName; @@ -650,345 +205,8 @@ static QString signalEnumName(const QString &signalName) return result; } -static void preProcessDefault(QString &defaultValue, const QString &name, - const QString &type, - const CfgEntry::Choices &choices, - QString &code, const CfgConfig &cfg) -{ - if (type == QLatin1String("String") && !defaultValue.isEmpty()) { - defaultValue = literalString(defaultValue); - - } else if (type == QLatin1String("Path") && !defaultValue.isEmpty()) { - defaultValue = literalString(defaultValue); - } else if (type == QLatin1String("Url") && !defaultValue.isEmpty()) { - // Use fromUserInput in order to support absolute paths and absolute urls, like KDE4's KUrl(QString) did. - defaultValue = QLatin1String("QUrl::fromUserInput( ") + literalString(defaultValue) + QLatin1Char(')'); - } else if ((type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty()) { - QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); - if (!code.isEmpty()) { - cpp << endl; - } - if (type == QLatin1String("UrlList")) { - cpp << " QList<QUrl> default" << name << ";" << endl; - } else { - cpp << " QStringList default" << name << ";" << endl; - } - const QStringList defaults = defaultValue.split(QLatin1Char(',')); - QStringList::ConstIterator it; - for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) { - cpp << " default" << name << ".append( "; - if (type == QLatin1String("UrlList")) { - cpp << "QUrl::fromUserInput("; - } - cpp << "QString::fromUtf8( \"" << *it << "\" ) "; - if (type == QLatin1String("UrlList")) { - cpp << ") "; - } - cpp << ");" << endl; - } - defaultValue = QLatin1String("default") + name; - - } else if (type == QLatin1String("Color") && !defaultValue.isEmpty()) { - const QRegularExpression colorRe(QRegularExpression::anchoredPattern( - QStringLiteral("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?"))); - - if (colorRe.match(defaultValue).hasMatch()) { - defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )"); - } else { - defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )"); - } - - } else if (type == QLatin1String("Enum")) { - QList<CfgEntry::Choice>::ConstIterator it; - for (it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it) { - if ((*it).name == defaultValue) { - if (cfg.globalEnums && choices.name().isEmpty()) { - defaultValue.prepend(choices.prefix); - } else { - defaultValue.prepend(enumTypeQualifier(name, choices) + choices.prefix); - } - break; - } - } - - } else if (type == QLatin1String("IntList")) { - QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); - if (!code.isEmpty()) { - cpp << endl; - } - - cpp << " QList<int> default" << name << ";" << endl; - if (!defaultValue.isEmpty()) { - const QStringList defaults = defaultValue.split(QLatin1Char(',')); - QStringList::ConstIterator it; - for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) { - cpp << " default" << name << ".append( " << *it << " );" - << endl; - } - } - defaultValue = QLatin1String("default") + name; - } -} - -CfgEntry *parseEntry(const QString &group, const QDomElement &element, const CfgConfig &cfg) -{ - bool defaultCode = false; - QString type = element.attribute(QStringLiteral("type")); - QString name = element.attribute(QStringLiteral("name")); - QString key = element.attribute(QStringLiteral("key")); - QString hidden = element.attribute(QStringLiteral("hidden")); - QString labelContext; - QString label; - QString toolTipContext; - QString toolTip; - QString whatsThisContext; - QString whatsThis; - QString defaultValue; - QString code; - QString param; - QString paramName; - QString paramType; - CfgEntry::Choices choices; - QList<Signal> signalList; - QStringList paramValues; - QStringList paramDefaultValues; - QString minValue; - QString maxValue; - int paramMax = 0; - - for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { - QString tag = e.tagName(); - if (tag == QLatin1String("label")) { - label = e.text(); - labelContext = e.attribute(QStringLiteral("context")); - } else if (tag == QLatin1String("tooltip")) { - toolTip = e.text(); - toolTipContext = e.attribute(QStringLiteral("context")); - } else if (tag == QLatin1String("whatsthis")) { - whatsThis = e.text(); - whatsThisContext = e.attribute(QStringLiteral("context")); - } else if (tag == QLatin1String("min")) { - minValue = e.text(); - } else if (tag == QLatin1String("max")) { - maxValue = e.text(); - } else if (tag == QLatin1String("code")) { - code = e.text(); - } else if (tag == QLatin1String("parameter")) { - param = e.attribute(QStringLiteral("name")); - paramType = e.attribute(QStringLiteral("type")); - if (param.isEmpty()) { - cerr << "Parameter must have a name: " << dumpNode(e) << endl; - return nullptr; - } - if (paramType.isEmpty()) { - cerr << "Parameter must have a type: " << dumpNode(e) << endl; - return nullptr; - } - if ((paramType == QLatin1String("Int")) || (paramType == QLatin1String("UInt"))) { - bool ok; - paramMax = e.attribute(QStringLiteral("max")).toInt(&ok); - if (!ok) { - cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): " - << dumpNode(e) << endl; - return nullptr; - } - } else if (paramType == QLatin1String("Enum")) { - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() == QLatin1String("values")) { - for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) { - if (e3.tagName() == QLatin1String("value")) { - paramValues.append(e3.text()); - } - } - break; - } - } - if (paramValues.isEmpty()) { - cerr << "No values specified for parameter '" << param - << "'." << endl; - return nullptr; - } - paramMax = paramValues.count() - 1; - } else { - cerr << "Parameter '" << param << "' has type " << paramType - << " but must be of type int, uint or Enum." << endl; - return nullptr; - } - } else if (tag == QLatin1String("default")) { - if (e.attribute(QStringLiteral("param")).isEmpty()) { - defaultValue = e.text(); - if (e.attribute(QStringLiteral("code")) == QLatin1String("true")) { - defaultCode = true; - } - } - } else if (tag == QLatin1String("choices")) { - QString name = e.attribute(QStringLiteral("name")); - QString prefix = e.attribute(QStringLiteral("prefix")); - QList<CfgEntry::Choice> chlist; - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() == QLatin1String("choice")) { - CfgEntry::Choice choice; - choice.name = e2.attribute(QStringLiteral("name")); - if (choice.name.isEmpty()) { - cerr << "Tag <choice> requires attribute 'name'." << endl; - } - for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) { - if (e3.tagName() == QLatin1String("label")) { - choice.label = e3.text(); - choice.context = e3.attribute(QStringLiteral("context")); - } - if (e3.tagName() == QLatin1String("tooltip")) { - choice.toolTip = e3.text(); - choice.context = e3.attribute(QStringLiteral("context")); - } - if (e3.tagName() == QLatin1String("whatsthis")) { - choice.whatsThis = e3.text(); - choice.context = e3.attribute(QStringLiteral("context")); - } - } - chlist.append(choice); - } - } - choices = CfgEntry::Choices(chlist, name, prefix); - } else if (tag == QLatin1String("emit")) { - Signal signal; - signal.name = e.attribute(QStringLiteral("signal")); - signalList.append(signal); - } - } - - if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.contains(name))) { - Signal s; - s.name = changeSignalName(name); - s.modify = true; - signalList.append(s); - } - - bool nameIsEmpty = name.isEmpty(); - if (nameIsEmpty && key.isEmpty()) { - cerr << "Entry must have a name or a key: " << dumpNode(element) << endl; - return nullptr; - } - - if (key.isEmpty()) { - key = name; - } - - if (nameIsEmpty) { - name = key; - name.remove(' '); - } else if (name.contains(' ')) { - cout << "Entry '" << name << "' contains spaces! <name> elements can not contain spaces!" << endl; - name.remove(' '); - } - - if (name.contains(QStringLiteral("$("))) { - if (param.isEmpty()) { - cerr << "Name may not be parameterized: " << name << endl; - return nullptr; - } - } else { - if (!param.isEmpty()) { - cerr << "Name must contain '$(" << param << ")': " << name << endl; - return nullptr; - } - } - - if (label.isEmpty()) { - label = key; - } - - if (type.isEmpty()) { - type = QStringLiteral("String"); // XXX : implicit type might be bad - } - - if (!param.isEmpty()) { - // Adjust name - paramName = name; - name.remove("$(" + param + ')'); - // Lookup defaults for indexed entries - for (int i = 0; i <= paramMax; i++) { - paramDefaultValues.append(QString()); - } - - for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { - QString tag = e.tagName(); - if (tag == QLatin1String("default")) { - QString index = e.attribute(QStringLiteral("param")); - if (index.isEmpty()) { - continue; - } - - bool ok; - int i = index.toInt(&ok); - if (!ok) { - i = paramValues.indexOf(index); - if (i == -1) { - cerr << "Index '" << index << "' for default value is unknown." << endl; - return nullptr; - } - } - - if ((i < 0) || (i > paramMax)) { - cerr << "Index '" << i << "' for default value is out of range [0, " << paramMax << "]." << endl; - return nullptr; - } - - QString tmpDefaultValue = e.text(); - - if (e.attribute(QStringLiteral("code")) != QLatin1String("true")) { - preProcessDefault(tmpDefaultValue, name, type, choices, code, cfg); - } - - paramDefaultValues[i] = tmpDefaultValue; - } - } - } - - if (!validNameRegexp->match(name).hasMatch()) { - if (nameIsEmpty) - cerr << "The key '" << key << "' can not be used as name for the entry because " - "it is not a valid name. You need to specify a valid name for this entry." << endl; - else { - cerr << "The name '" << name << "' is not a valid name for an entry." << endl; - } - return nullptr; - } - - if (allNames.contains(name)) { - if (nameIsEmpty) - cerr << "The key '" << key << "' can not be used as name for the entry because " - "it does not result in a unique name. You need to specify a unique name for this entry." << endl; - else { - cerr << "The name '" << name << "' is not unique." << endl; - } - return nullptr; - } - allNames.append(name); - - if (!defaultCode) { - preProcessDefault(defaultValue, name, type, choices, code, cfg); - } - - CfgEntry *result = new CfgEntry(group, type, key, name, labelContext, label, toolTipContext, toolTip, whatsThisContext, whatsThis, - code, defaultValue, choices, signalList, - hidden == QLatin1String("true")); - if (!param.isEmpty()) { - result->setParam(param); - result->setParamName(paramName); - result->setParamType(paramType); - result->setParamValues(paramValues); - result->setParamDefaultValues(paramDefaultValues); - result->setParamMax(paramMax); - } - result->setMinValue(minValue); - result->setMaxValue(maxValue); - - return result; -} - -static bool isUnsigned(const QString &type) +bool isUnsigned(const QString &type) { if (type == QLatin1String("UInt")) { return true; @@ -1168,47 +386,47 @@ QString itemType(const QString &type) return t; } -static QString itemDeclaration(const CfgEntry *e, const CfgConfig &cfg) +QString itemDeclaration(const CfgEntry *e, const KConfigXTParameters &cfg) { if (cfg.itemAccessors) { return QString(); } QString type; - if (!e->signalList().isEmpty()) { + if (!e->signalList.isEmpty()) { type = QStringLiteral("KConfigCompilerSignallingItem"); } else { - type = cfg.inherits + "::Item" + itemType(e->type()); + type = cfg.inherits + "::Item" + itemType(e->type); } - QString fCap = e->name(); + QString fCap = e->name; fCap[0] = fCap[0].toUpper(); return " " + type + " *item" + fCap + - ( (!e->param().isEmpty())?(QStringLiteral("[%1]").arg(e->paramMax()+1)) : QString()) + ";\n"; + ( (!e->param.isEmpty())?(QStringLiteral("[%1]").arg(e->paramMax+1)) : QString()) + ";\n"; } // returns the name of an item variable // use itemPath to know the full path // like using d-> in case of dpointer -static QString itemVar(const CfgEntry *e, const CfgConfig &cfg) +QString itemVar(const CfgEntry *e, const KConfigXTParameters &cfg) { QString result; if (cfg.itemAccessors) { if (!cfg.dpointer) { - result = 'm' + e->name() + "Item"; + result = 'm' + e->name + "Item"; result[1] = result[1].toUpper(); } else { - result = e->name() + "Item"; + result = e->name + "Item"; result[0] = result[0].toLower(); } } else { - result = "item" + e->name(); + result = "item" + e->name; result[4] = result[4].toUpper(); } return result; } -static QString itemPath(const CfgEntry *e, const CfgConfig &cfg) +QString itemPath(const CfgEntry *e, const KConfigXTParameters &cfg) { QString result; if (cfg.dpointer) { @@ -1220,18 +438,18 @@ static QString itemPath(const CfgEntry *e, const CfgConfig &cfg) } QString newItem(const CfgEntry* entry, const QString &key, const QString& defaultValue, - const CfgConfig &cfg, const QString ¶m = QString()) { + const KConfigXTParameters &cfg, const QString ¶m) { - QList<Signal> sigs = entry->signalList(); + QList<Signal> sigs = entry->signalList; QString t; if (!sigs.isEmpty()) { t += QLatin1String("new KConfigCompilerSignallingItem("); } - t += "new "+ cfg.inherits + "::Item" + itemType(entry->type()) + "( currentGroup(), " - + key + ", " + varPath( entry->name(), cfg ) + param; + t += "new "+ cfg.inherits + "::Item" + itemType(entry->type) + "( currentGroup(), " + + key + ", " + varPath( entry->name, cfg ) + param; - if (entry->type() == QLatin1String("Enum")) { - t += ", values" + entry->name(); + if (entry->type == QLatin1String("Enum")) { + t += ", values" + entry->name; } if (!defaultValue.isEmpty()) { t += QLatin1String(", ") + defaultValue; @@ -1255,11 +473,11 @@ QString newItem(const CfgEntry* entry, const QString &key, const QString& defaul QString paramString(const QString &s, const CfgEntry *e, int i) { QString result = s; - QString needle = "$(" + e->param() + ')'; + QString needle = "$(" + e->param + ')'; if (result.contains(needle)) { QString tmp; - if (e->paramType() == QLatin1String("Enum")) { - tmp = e->paramValues().at(i); + if (e->paramType == QLatin1String("Enum")) { + tmp = e->paramValues.at(i); } else { tmp = QString::number(i); } @@ -1289,12 +507,12 @@ QString paramString(const QString &group, const QList<Param> ¶meters) return "QStringLiteral( \"" + paramString + "\" )" + arguments; } -QString translatedString(const CfgConfig &cfg, const QString &string, const QString &context = QString(), const QString ¶m = QString(), const QString ¶mValue = QString()) +QString translatedString(const KConfigXTParameters &cfg, const QString &string, const QString &context, const QString ¶m, const QString ¶mValue) { QString result; switch (cfg.translationSystem) { - case CfgConfig::QtTranslation: + case KConfigXTParameters::QtTranslation: if (!context.isEmpty()) { result += "/*: " + context + " */ QCoreApplication::translate(\""; } else { @@ -1303,7 +521,7 @@ QString translatedString(const CfgConfig &cfg, const QString &string, const QStr result += cfg.className + "\", "; break; - case CfgConfig::KdeTranslation: + case KConfigXTParameters::KdeTranslation: if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) { result += "i18ndc(" + quoteString(cfg.translationDomain) + ", " + quoteString(context) + ", "; } else if (!cfg.translationDomain.isEmpty()) { @@ -1330,62 +548,36 @@ QString translatedString(const CfgConfig &cfg, const QString &string, const QStr } /* int i is the value of the parameter */ -QString userTextsFunctions(CfgEntry *e, const CfgConfig &cfg, QString itemVarStr = QString(), const QString &i = QString()) +QString userTextsFunctions(const CfgEntry *e, const KConfigXTParameters &cfg, QString itemVarStr, const QString &i) { QString txt; if (itemVarStr.isNull()) { itemVarStr = itemPath(e, cfg); } - if (!e->label().isEmpty()) { + if (!e->label.isEmpty()) { txt += " " + itemVarStr + "->setLabel( "; - txt += translatedString(cfg, e->label(), e->labelContext(), e->param(), i); + txt += translatedString(cfg, e->label, e->labelContext, e->param, i); txt += QLatin1String(" );\n"); } - if (!e->toolTip().isEmpty()) { + if (!e->toolTip.isEmpty()) { txt += " " + itemVarStr + "->setToolTip( "; - txt += translatedString(cfg, e->toolTip(), e->toolTipContext(), e->param(), i); + txt += translatedString(cfg, e->toolTip, e->toolTipContext, e->param, i); txt += QLatin1String(" );\n"); } - if (!e->whatsThis().isEmpty()) { + if (!e->whatsThis.isEmpty()) { txt += " " + itemVarStr + "->setWhatsThis( "; - txt += translatedString(cfg, e->whatsThis(), e->whatsThisContext(), e->param(), i); + txt += translatedString(cfg, e->whatsThis, e->whatsThisContext, e->param, i); txt += QLatin1String(" );\n"); } return txt; } -// returns the member accesor implementation -// which should go in the h file if inline -// or the cpp file if not inline -QString memberAccessorBody(CfgEntry *e, bool globalEnums, const CfgConfig &cfg) -{ - QString result; - QTextStream out(&result, QIODevice::WriteOnly); - QString n = e->name(); - QString t = e->type(); - bool useEnumType = cfg.useEnumTypes && t == QLatin1String("Enum"); - - out << "return "; - if (useEnumType) { - out << "static_cast<" << enumType(e, globalEnums) << ">("; - } - out << This << varPath(n, cfg); - if (!e->param().isEmpty()) { - out << "[i]"; - } - if (useEnumType) { - out << ")"; - } - out << ";" << endl; - - return result; -} // returns the member mutator implementation // which should go in the h file if inline // or the cpp file if not inline - -void addDebugMethod(QTextStream &out, const CfgConfig &cfg, const QString &n) +//TODO: Fix add Debug Method, it should also take the debug string. +void addDebugMethod(QTextStream &out, const KConfigXTParameters &cfg, const QString &n) { if (cfg.qCategoryLoggingName.isEmpty()) { out << " qDebug() << \"" << setFunction(n); @@ -1394,101 +586,30 @@ void addDebugMethod(QTextStream &out, const CfgConfig &cfg, const QString &n) } } -QString memberMutatorBody(CfgEntry *e, const CfgConfig &cfg) -{ - QString result; - QTextStream out(&result, QIODevice::WriteOnly); - QString n = e->name(); - QString t = e->type(); - - if (!e->minValue().isEmpty()) { - if (e->minValue() != QLatin1String("0") || !isUnsigned(t)) { // skip writing "if uint<0" (#187579) - out << "if (v < " << e->minValue() << ")" << endl; - out << "{" << endl; - addDebugMethod(out, cfg, n); - out << ": value \" << v << \" is less than the minimum value of "; - out << e->minValue() << "\";" << endl; - out << " v = " << e->minValue() << ";" << endl; - out << "}" << endl; - } - } - - if (!e->maxValue().isEmpty()) { - out << endl << "if (v > " << e->maxValue() << ")" << endl; - out << "{" << endl; - addDebugMethod(out, cfg, n); - out << ": value \" << v << \" is greater than the maximum value of "; - out << e->maxValue() << "\";" << endl; - out << " v = " << e->maxValue() << ";" << endl; - out << "}" << endl << endl; - } - - const QString varExpression = This + varPath(n, cfg) + (e->param().isEmpty() ? QString() : QStringLiteral("[i]")); - - const bool hasBody = !e->signalList().empty() || cfg.generateProperties; - out << "if ("; - if (hasBody) { - out << "v != " << varExpression << " && "; - } - out << "!" << This << "isImmutable( QStringLiteral( \""; - if (!e->param().isEmpty()) { - out << e->paramName().replace("$(" + e->param() + ")", QLatin1String("%1")) << "\" ).arg( "; - if (e->paramType() == QLatin1String("Enum")) { - out << "QLatin1String( "; - - if (cfg.globalEnums) { - out << enumName(e->param()) << "ToString[i]"; - } else { - out << enumName(e->param()) << "::enumToString[i]"; - } - - out << " )"; - } else { - out << "i"; - } - out << " )"; - } else { - out << n << "\" )"; - } - out << " ))" << (hasBody ? " {" : "") << endl; - out << " " << varExpression << " = v;" << endl; - - const auto listSignal = e->signalList(); - for (const Signal &signal : listSignal) { - if (signal.modify) { - out << " Q_EMIT " << This << signal.name << "();" << endl; - } else { - out << " " << This << varPath(QStringLiteral("settingsChanged"), cfg) << " |= " << signalEnumName(signal.name) << ";" << endl; - } - } - if (hasBody) { - out << "}" << endl; - } - - return result; -} // returns the member get default implementation // which should go in the h file if inline // or the cpp file if not inline -QString memberGetDefaultBody(CfgEntry *e) +QString memberGetDefaultBody(const CfgEntry *e) { - QString result = e->code(); + QString result = e->code; QTextStream out(&result, QIODevice::WriteOnly); out << endl; - if (!e->param().isEmpty()) { + if (!e->param.isEmpty()) { out << " switch (i) {" << endl; - for (int i = 0; i <= e->paramMax(); ++i) { - if (!e->paramDefaultValue(i).isEmpty()) { - out << " case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl; + for (int i = 0; i <= e->paramMax; ++i) { + if (!e->paramDefaultValues[i].isEmpty()) { + out << " case " << i << ": return " << e->paramDefaultValues[i] << ';' << endl; } } + QString defaultValue = e->defaultValue; + out << " default:" << endl; - out << " return " << e->defaultValue().replace("$(" + e->param() + ')', QLatin1String("i")) << ';' << endl; + out << " return " << defaultValue.replace("$(" + e->param + ')', QLatin1String("i")) << ';' << endl; out << " }" << endl; } else { - out << " return " << e->defaultValue() << ';'; + out << " return " << e->defaultValue << ';'; } return result; @@ -1497,13 +618,13 @@ QString memberGetDefaultBody(CfgEntry *e) // returns the item accesor implementation // which should go in the h file if inline // or the cpp file if not inline -QString itemAccessorBody(CfgEntry *e, const CfgConfig &cfg) +QString itemAccessorBody(const CfgEntry *e, const KConfigXTParameters &cfg) { QString result; QTextStream out(&result, QIODevice::WriteOnly); out << "return " << itemPath(e, cfg); - if (!e->param().isEmpty()) { + if (!e->param.isEmpty()) { out << "[i]"; } out << ";" << endl; @@ -1529,30 +650,29 @@ QString indent(QString text, int spaces) return result; } -// adds as many 'namespace foo {' lines to p_out as -// there are namespaces in p_ns -void beginNamespaces(const QString &p_ns, QTextStream &p_out) +bool hasErrors(KCFGXmlParser &parser, const ParseResult& parseResult, const KConfigXTParameters &cfg) { - if (!p_ns.isEmpty()) { - const QStringList nameSpaces = p_ns.split(QStringLiteral("::")); - for (const QString &ns : nameSpaces) { - p_out << "namespace " << ns << " {" << endl; - } - p_out << endl; + if (cfg.className.isEmpty()) { + cerr << "Class name missing" << endl; + return true; } -} -// adds as many '}' lines to p_out as -// there are namespaces in p_ns -void endNamespaces(const QString &p_ns, QTextStream &p_out) -{ - if (!p_ns.isEmpty()) { - const int namespaceCount = p_ns.count(QStringLiteral("::")) + 1; - for (int i = 0; i < namespaceCount; ++i) { - p_out << "}" << endl; - } - p_out << endl; + if (cfg.singleton && !parseResult.parameters.isEmpty()) { + cerr << "Singleton class can not have parameters" << endl; + return true; + } + + if (!parseResult.cfgFileName.isEmpty() && parseResult.cfgFileNameArg) { + cerr << "Having both a fixed filename and a filename as argument is not possible." << endl; + return true; } + + if (parseResult.entries.isEmpty()) { + cerr << "No entries." << endl; + return true; + } + + return false; } int main(int argc, char **argv) @@ -1561,22 +681,22 @@ int main(int argc, char **argv) app.setApplicationName(QStringLiteral("kconfig_compiler")); app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING)); - validNameRegexp = new QRegularExpression(QRegularExpression::anchoredPattern( - QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*"))); - QString inputFilename, codegenFilename; + QCommandLineOption targetDirectoryOption(QStringList { QStringLiteral("d"), QStringLiteral("directory") }, + QCoreApplication::translate("main", "Directory to generate files in [.]"), + QCoreApplication::translate("main", "directory"), QStringLiteral(".")); + + QCommandLineOption licenseOption ( + QStringList { QStringLiteral("l"), QStringLiteral("license") }, + QCoreApplication::translate("main", "Display software license.")); + QCommandLineParser parser; parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file")); parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file")); - QCommandLineOption targetDirectoryOption(QStringList { QStringLiteral("d"), QStringLiteral("directory") }, - QCoreApplication::translate("main", "Directory to generate files in [.]"), - QCoreApplication::translate("main", "directory"), QStringLiteral(".")); parser.addOption(targetDirectoryOption); - - QCommandLineOption licenseOption (QStringList { QStringLiteral("l"), QStringLiteral("license") }, QCoreApplication::translate("main", "Display software license.")); parser.addOption (licenseOption); parser.addVersionOption(); @@ -1584,7 +704,7 @@ int main(int argc, char **argv) parser.process(app); if (parser.isSet(licenseOption)) { - cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl; + cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl; cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << endl; cout << "This program comes with ABSOLUTELY NO WARRANTY." << endl; cout << "You may redistribute copies of this program" << endl; @@ -1595,16 +715,18 @@ int main(int argc, char **argv) const QStringList args = parser.positionalArguments(); if (args.count() < 2) { - cerr << "Too few arguments." << endl; - return 1; + cerr << "Too few arguments." << endl; + return 1; } + if (args.count() > 2) { - cerr << "Too many arguments." << endl; - return 1; + cerr << "Too many arguments." << endl; + return 1; } inputFilename = args.at(0); codegenFilename = args.at(1); + // TODO: Transform baseDir into a helper. QString baseDir = parser.value(targetDirectoryOption); #ifdef Q_OS_WIN @@ -1614,1124 +736,34 @@ int main(int argc, char **argv) #endif baseDir.append("/"); - if (!codegenFilename.endsWith(QLatin1String(".kcfgc"))) { - cerr << "Codegen options file must have extension .kcfgc" << endl; - return 1; - } - QString baseName = QFileInfo(codegenFilename).fileName(); - baseName = baseName.left(baseName.length() - 6); - - CfgConfig cfg = CfgConfig(codegenFilename); + KConfigXTParameters cfg(codegenFilename); - QFile input(inputFilename); + KCFGXmlParser xmlParser(cfg, inputFilename); + + // The Xml Parser aborts in the case of an error, so if we get + // to parseResult, we have a working Xml file. + xmlParser.start(); - QDomDocument doc; - QString errorMsg; - int errorRow; - int errorCol; - if (!doc.setContent(&input, &errorMsg, &errorRow, &errorCol)) { - cerr << "Unable to load document." << endl; - cerr << "Parse error in " << inputFilename << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl; - return 1; - } + ParseResult parseResult = xmlParser.getParseResult(); - QDomElement cfgElement = doc.documentElement(); - - if (cfgElement.isNull()) { - cerr << "No document in kcfg file" << endl; + if (hasErrors(xmlParser, parseResult, cfg)) { return 1; } - QString cfgFileName; - bool cfgFileNameArg = false; - QList<Param> parameters; - QList<Signal> signalList; - QStringList includes; - - QList<CfgEntry *> entries; - - for (QDomElement e = cfgElement.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { - QString tag = e.tagName(); - - if (tag == QLatin1String("include")) { - QString includeFile = e.text(); - if (!includeFile.isEmpty()) { - includes.append(includeFile); - } - - } else if (tag == QLatin1String("kcfgfile")) { - cfgFileName = e.attribute(QStringLiteral("name")); - cfgFileNameArg = e.attribute(QStringLiteral("arg")).toLower() == QLatin1String("true"); - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() == QLatin1String("parameter")) { - Param p; - p.name = e2.attribute(QStringLiteral("name")); - p.type = e2.attribute(QStringLiteral("type")); - if (p.type.isEmpty()) { - p.type = QStringLiteral("String"); - } - parameters.append(p); - } - } - - } else if (tag == QLatin1String("group")) { - QString group = e.attribute(QStringLiteral("name")); - if (group.isEmpty()) { - cerr << "Group without name" << endl; - return 1; - } - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() != QLatin1String("entry")) { - continue; - } - CfgEntry *entry = parseEntry(group, e2, cfg); - if (entry) { - entries.append(entry); - } else { - cerr << "Can not parse entry." << endl; - return 1; - } - } - } else if (tag == QLatin1String("signal")) { - QString signalName = e.attribute(QStringLiteral("name")); - if (signalName.isEmpty()) { - cerr << "Signal without name." << endl; - return 1; - } - Signal theSignal; - theSignal.name = signalName; - - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() == QLatin1String("argument")) { - SignalArguments argument; - argument.type = e2.attribute(QStringLiteral("type")); - if (argument.type.isEmpty()) { - cerr << "Signal argument without type." << endl; - return 1; - } - argument.variableName = e2.text(); - theSignal.arguments.append(argument); - } else if (e2.tagName() == QLatin1String("label")) { - theSignal.label = e2.text(); - } - } - signalList.append(theSignal); - } - } - - if (cfg.className.isEmpty()) { - cerr << "Class name missing" << endl; - return 1; + // TODO: Move this to somewhere saner. + for (const auto &signal : qAsConst(parseResult.signalList)) { + parseResult.hasNonModifySignals |= !signal.modify; } - if (cfg.singleton && !parameters.isEmpty()) { - cerr << "Singleton class can not have parameters" << endl; - return 1; - } - - if (!cfgFileName.isEmpty() && cfgFileNameArg) { - cerr << "Having both a fixed filename and a filename as argument is not possible." << endl; - return 1; - } - - if (entries.isEmpty()) { - cerr << "No entries." << endl; - } - -#if 0 - CfgEntry *cfg; - for (cfg = entries.first(); cfg; cfg = entries.next()) { - cfg->dump(); - } -#endif - - QString headerFileName = baseName + '.' + cfg.headerExtension; - QString implementationFileName = baseName + '.' + cfg.sourceExtension; - QString mocFileName = baseName + ".moc"; - QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values - - QFile header(baseDir + headerFileName); - if (!header.open(QIODevice::WriteOnly)) { - cerr << "Can not open '" << baseDir << headerFileName << "for writing." << endl; - return 1; - } - - QTextStream h(&header); - - h.setCodec("utf-8"); - - h << "// This file is generated by kconfig_compiler_kf5 from " << QFileInfo(inputFilename).fileName() << "." << endl; - h << "// All changes you do to this file will be lost." << endl; - - h << "#ifndef " << (!cfg.nameSpace.isEmpty() ? QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_")).toUpper() + '_') : QLatin1String("")) - << cfg.className.toUpper() << "_H" << endl; - h << "#define " << (!cfg.nameSpace.isEmpty() ? QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_")).toUpper() + '_') : QLatin1String("")) - << cfg.className.toUpper() << "_H" << endl << endl; - - // Includes - QStringList::ConstIterator it; - for (it = cfg.headerIncludes.constBegin(); it != cfg.headerIncludes.constEnd(); ++it) { - if ((*it).startsWith('"')) { - h << "#include " << *it << endl; - } else { - h << "#include <" << *it << ">" << endl; - } - } - - if (!cfg.headerIncludes.isEmpty()) { - h << endl; - } - - if (!cfg.singleton && parameters.isEmpty()) { - h << "#include <qglobal.h>" << endl; - } - - if (cfg.inherits == QLatin1String("KCoreConfigSkeleton")) { - h << "#include <kcoreconfigskeleton.h>" << endl; - } else { - h << "#include <kconfigskeleton.h>" << endl; - } - - h << "#include <QCoreApplication>" << endl; - h << "#include <QDebug>" << endl << endl; - - // Includes - for (it = includes.constBegin(); it != includes.constEnd(); ++it) { - if ((*it).startsWith('"')) { - h << "#include " << *it << endl; - } else { - h << "#include <" << *it << ">" << endl; - } - } - - beginNamespaces(cfg.nameSpace, h); - - // Private class declaration - if (cfg.dpointer) { - h << "class " << cfg.className << "Private;" << endl << endl; - } - - // Class declaration header - h << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl; - - h << "{" << endl; - // Add Q_OBJECT macro if the config need signals. - if (!signalList.isEmpty() || cfg.generateProperties) { - h << " Q_OBJECT" << endl; - } - h << " public:" << endl; - - // enums - QList<CfgEntry *>::ConstIterator itEntry; - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - const CfgEntry::Choices &choices = (*itEntry)->choices(); - const QList<CfgEntry::Choice> chlist = choices.choices; - if (!chlist.isEmpty()) { - QStringList values; - QList<CfgEntry::Choice>::ConstIterator itChoice; - for (itChoice = chlist.constBegin(); itChoice != chlist.constEnd(); ++itChoice) { - values.append(choices.prefix + (*itChoice).name); - } - if (choices.name().isEmpty()) { - if (cfg.globalEnums) { - h << " enum " << enumName((*itEntry)->name(), (*itEntry)->choices()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; - } else { - // Create an automatically named enum - h << " class " << enumName((*itEntry)->name(), (*itEntry)->choices()) << endl; - h << " {" << endl; - h << " public:" << endl; - h << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl; - h << " };" << endl; - } - } else if (!choices.external()) { - // Create a named enum - h << " enum " << enumName((*itEntry)->name(), (*itEntry)->choices()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; - } - } - const QStringList values = (*itEntry)->paramValues(); - if (!values.isEmpty()) { - if (cfg.globalEnums) { - // ### FIXME!! - // make the following string table an index-based string search! - // ### - h << " enum " << enumName((*itEntry)->param()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; - h << " static const char* const " << enumName((*itEntry)->param()) << "ToString[];" << endl; - cppPreamble += "const char* const " + cfg.className + "::" + enumName((*itEntry)->param()) + - "ToString[] = { \"" + values.join(QStringLiteral("\", \"")) + "\" };\n"; - } else { - h << " class " << enumName((*itEntry)->param()) << endl; - h << " {" << endl; - h << " public:" << endl; - h << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl; - h << " static const char* const enumToString[];" << endl; - h << " };" << endl; - cppPreamble += "const char* const " + cfg.className + "::" + enumName((*itEntry)->param()) + - "::enumToString[] = { \"" + values.join(QStringLiteral("\", \"")) + "\" };\n"; - } - } - } - h << endl; - - - // Constructor or singleton accessor - if (!cfg.singleton) { - h << " " << cfg.className << "("; - if (cfgFileNameArg) { - if (cfg.forceStringFilename) - h << " const QString &cfgfilename" - << (parameters.isEmpty() ? " = QString()" : ", "); - else - h << " KSharedConfig::Ptr config" - << (parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", "); - } - for (QList<Param>::ConstIterator it = parameters.constBegin(); - it != parameters.constEnd(); ++it) { - if (it != parameters.constBegin()) { - h << ","; - } - h << " " << param((*it).type) << " " << (*it).name; - } - if (cfg.parentInConstructor) { - if (cfgFileNameArg || !parameters.isEmpty()) { - h << ","; - } - h << " QObject *parent = nullptr"; - } - h << " );" << endl; - } else { - h << " static " << cfg.className << " *self();" << endl; - if (cfgFileNameArg) { - h << " static void instance(const QString& cfgfilename);" << endl; - h << " static void instance(KSharedConfig::Ptr config);" << endl; - } - } - - // Destructor - h << " ~" << cfg.className << "();" << endl << endl; - - // global variables - if (cfg.staticAccessors) { - This = QStringLiteral("self()->"); - } else { - Const = QStringLiteral(" const"); - } - - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - QString n = (*itEntry)->name(); - QString t = (*itEntry)->type(); - - // Manipulator - if (cfg.allMutators || cfg.mutators.contains(n)) { - h << " /**" << endl; - h << " Set " << (*itEntry)->label() << endl; - h << " */" << endl; - if (cfg.staticAccessors) { - h << " static" << endl; - } - h << " void " << setFunction(n) << "( "; - if (!(*itEntry)->param().isEmpty()) { - h << cppType((*itEntry)->paramType()) << " i, "; - } - if (cfg.useEnumTypes && t == QLatin1String("Enum")) { - h << enumType(*itEntry, cfg.globalEnums); - } else { - h << param(t); - } - h << " v )"; - // function body inline only if not using dpointer - // for BC mode - if (!cfg.dpointer) { - h << endl << " {" << endl; - h << indent(memberMutatorBody(*itEntry, cfg), 6); - h << " }" << endl; - } else { - h << ";" << endl; - } - } - h << endl; - - QString returnType; - if (cfg.useEnumTypes && t == QLatin1String("Enum")) { - returnType = enumType(*itEntry, cfg.globalEnums); - } else { - returnType = cppType(t); - } - - if (cfg.generateProperties) { - h << " Q_PROPERTY(" << returnType << ' ' << getFunction(n); - h << " READ " << getFunction(n); - if (cfg.allMutators || cfg.mutators.contains(n)) { - const QString signal = changeSignalName(n); - h << " WRITE " << setFunction(n); - h << " NOTIFY " << signal; - - //If we have the modified signal, we'll also need - //the changed signal as well - Signal s; - s.name = signal; - s.modify = true; - signalList.append(s); - } else { - h << " CONSTANT"; - } - h << ")" << endl; - } - // Accessor - h << " /**" << endl; - h << " Get " << (*itEntry)->label() << endl; - h << " */" << endl; - if (cfg.staticAccessors) { - h << " static" << endl; - } - h << " "; - h << returnType; - h << " " << getFunction(n) << "("; - if (!(*itEntry)->param().isEmpty()) { - h << " " << cppType((*itEntry)->paramType()) << " i "; - } - h << ")" << Const; - // function body inline only if not using dpointer - // for BC mode - if (!cfg.dpointer) { - h << endl << " {" << endl; - h << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 6); - h << " }" << endl; - } else { - h << ";" << endl; - } - - // Default value Accessor - if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) { - h << endl; - h << " /**" << endl; - h << " Get " << (*itEntry)->label() << " default value" << endl; - h << " */" << endl; - if (cfg.staticAccessors) { - h << " static" << endl; - } - h << " "; - if (cfg.useEnumTypes && t == QLatin1String("Enum")) { - h << enumType(*itEntry, cfg.globalEnums); - } else { - h << cppType(t); - } - h << " " << getDefaultFunction(n) << "("; - if (!(*itEntry)->param().isEmpty()) { - h << " " << cppType((*itEntry)->paramType()) << " i "; - } - h << ")" << Const << endl; - h << " {" << endl; - h << " return "; - if (cfg.useEnumTypes && t == QLatin1String("Enum")) { - h << "static_cast<" << enumType(*itEntry, cfg.globalEnums) << ">("; - } - h << getDefaultFunction(n) << "_helper("; - if (!(*itEntry)->param().isEmpty()) { - h << " i "; - } - h << ")"; - if (cfg.useEnumTypes && t == QLatin1String("Enum")) { - h << ")"; - } - h << ";" << endl; - h << " }" << endl; - } - - // Item accessor - if (cfg.itemAccessors) { - h << endl; - h << " /**" << endl; - h << " Get Item object corresponding to " << n << "()" - << endl; - h << " */" << endl; - h << " Item" << itemType((*itEntry)->type()) << " *" - << getFunction(n) << "Item("; - if (!(*itEntry)->param().isEmpty()) { - h << " " << cppType((*itEntry)->paramType()) << " i "; - } - h << ")"; - if (!cfg.dpointer) { - h << endl << " {" << endl; - h << indent(itemAccessorBody((*itEntry), cfg), 6); - h << " }" << endl; - } else { - h << ";" << endl; - } - } - - h << endl; - } - - // Signal definition. - const bool hasSignals = !signalList.isEmpty(); - bool hasNonModifySignals = false; - if (hasSignals) { - h << "\n enum {" << endl; - unsigned val = 1; - QList<Signal>::ConstIterator it, itEnd = signalList.constEnd(); - for (it = signalList.constBegin(); it != itEnd; val <<= 1) { - hasNonModifySignals |= !it->modify; - if (!val) { - cerr << "Too many signals to create unique bit masks" << endl; - exit(1); - } - Signal signal = *it; - h << " " << signalEnumName(signal.name) << " = 0x" << - #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - hex - #else - Qt::hex - #endif - << val; - if (++it != itEnd) { - h << ","; - } - h << endl; - } - h << " };" << - #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - dec - #else - Qt::dec - #endif - << endl << endl; - - h << " Q_SIGNALS:"; - for (const Signal &signal : qAsConst(signalList)) { - h << endl; - if (!signal.label.isEmpty()) { - h << " /**" << endl; - h << " " << signal.label << endl; - h << " */" << endl; - } - h << " void " << signal.name << "("; - QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd(); - for (it = signal.arguments.constBegin(); it != itEnd;) { - SignalArguments argument = *it; - QString type = param(argument.type); - if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) { - for (int i = 0, end = entries.count(); i < end; ++i) { - if (entries[i]->name() == argument.variableName) { - type = enumType(entries[i], cfg.globalEnums); - break; - } - } - } - h << type << " " << argument.variableName; - if (++it != itEnd) { - h << ", "; - } - } - h << ");" << endl; - } - h << endl; - - h << " private:" << endl; - h << " void itemChanged(quint64 flags);" << endl; - h << endl; - } - - h << " protected:" << endl; - - // Private constructor for singleton - if (cfg.singleton) { - h << " " << cfg.className << "("; - if (cfgFileNameArg) { - h << "KSharedConfig::Ptr config"; - } - if (cfg.parentInConstructor) { - if (cfgFileNameArg) { - h << ", "; - } - h << "QObject *parent = nullptr"; - } - h << ");" << endl; - h << " friend class " << cfg.className << "Helper;" << endl << endl; - } - - if (hasNonModifySignals) { - h << " bool usrSave() override;" << endl; - } - - // Member variables - if (!cfg.memberVariables.isEmpty() && cfg.memberVariables != QLatin1String("private") && cfg.memberVariables != QLatin1String("dpointer")) { - h << " " << cfg.memberVariables << ":" << endl; - } - - // Class Parameters - for (QList<Param>::ConstIterator it = parameters.constBegin(); - it != parameters.constEnd(); ++it) { - h << " " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl; - } - - if (cfg.memberVariables != QLatin1String("dpointer")) { - QString group; - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - if ((*itEntry)->group() != group) { - group = (*itEntry)->group(); - h << endl; - h << " // " << group << endl; - } - h << " " << cppType((*itEntry)->type()) << " " << varName((*itEntry)->name(), cfg); - if (!(*itEntry)->param().isEmpty()) { - h << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); - } - h << ";" << endl; - - if (cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name())) { - h << " "; - if (cfg.staticAccessors) { - h << "static "; - } - h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper("; - if (!(*itEntry)->param().isEmpty()) { - h << " " << cppType((*itEntry)->paramType()) << " i "; - } - h << ")" << Const << ";" << endl; - } - } - - h << endl << " private:" << endl; - if (cfg.itemAccessors) { - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - h << " Item" << itemType((*itEntry)->type()) << " *" << itemVar(*itEntry, cfg); - if (!(*itEntry)->param().isEmpty()) { - h << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); - } - h << ";" << endl; - } - } - if (hasNonModifySignals) { - h << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl; - } - - } else { - // use a private class for both member variables and items - h << " private:" << endl; - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - if (cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name())) { - h << " "; - if (cfg.staticAccessors) { - h << "static "; - } - h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper("; - if (!(*itEntry)->param().isEmpty()) { - h << " " << cppType((*itEntry)->paramType()) << " i "; - } - h << ")" << Const << ";" << endl; - } - } - h << " " + cfg.className + "Private *d;" << endl; - } - - if (cfg.customAddons) { - h << " // Include custom additions" << endl; - h << " #include \"" << baseName << "_addons." << cfg.headerExtension << '"' << endl; - } - - h << "};" << endl << endl; - - endNamespaces(cfg.nameSpace, h); - - h << "#endif" << endl << endl; - - header.close(); - - QFile implementation(baseDir + implementationFileName); - if (!implementation.open(QIODevice::WriteOnly)) { - cerr << "Can not open '" << implementationFileName << "for writing." - << endl; - return 1; - } - - QTextStream cpp(&implementation); - - cpp.setCodec("utf-8"); - - cpp << "// This file is generated by kconfig_compiler_kf5 from " << QFileInfo(inputFilename).fileName() << "." << endl; - cpp << "// All changes you do to this file will be lost." << endl << endl; - - cpp << "#include \"" << headerFileName << "\"" << endl << endl; - - for (it = cfg.sourceIncludes.constBegin(); it != cfg.sourceIncludes.constEnd(); ++it) { - if ((*it).startsWith('"')) { - cpp << "#include " << *it << endl; - } else { - cpp << "#include <" << *it << ">" << endl; - } - } - - if (!cfg.sourceIncludes.isEmpty()) { - cpp << endl; - } - - if (cfg.setUserTexts && cfg.translationSystem == CfgConfig::KdeTranslation) { - cpp << "#include <klocalizedstring.h>" << endl << endl; - } - - // Header required by singleton implementation - if (cfg.singleton) { - cpp << "#include <qglobal.h>" << endl << "#include <QFile>" << endl << endl; - } - if (cfg.singleton && cfgFileNameArg) { - cpp << "#include <QDebug>" << endl << endl; - } - - if (!cfg.nameSpace.isEmpty()) { - cpp << "using namespace " << cfg.nameSpace << ";" << endl << endl; - } - - QString group; - - // private class implementation - if (cfg.dpointer) { - beginNamespaces(cfg.nameSpace, cpp); - cpp << "class " << cfg.className << "Private" << endl; - cpp << "{" << endl; - cpp << " public:" << endl; - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - if ((*itEntry)->group() != group) { - group = (*itEntry)->group(); - cpp << endl; - cpp << " // " << group << endl; - } - cpp << " " << cppType((*itEntry)->type()) << " " << varName((*itEntry)->name(), cfg); - if (!(*itEntry)->param().isEmpty()) { - cpp << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); - } - cpp << ";" << endl; - } - cpp << endl << " // items" << endl; - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - const QString declType = (*itEntry)->signalList().isEmpty() - ? QString(cfg.inherits + "::Item" + itemType((*itEntry)->type())) - : QStringLiteral("KConfigCompilerSignallingItem"); - cpp << " " << declType << " *" << itemVar( *itEntry, cfg ); - if (!(*itEntry)->param().isEmpty()) { - cpp << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1); - } - cpp << ";" << endl; - } - if (hasNonModifySignals) { - cpp << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl; - } - - cpp << "};" << endl << endl; - endNamespaces(cfg.nameSpace, cpp); - } - - // Singleton implementation - if (cfg.singleton) { - beginNamespaces(cfg.nameSpace, cpp); - cpp << "class " << cfg.className << "Helper" << endl; - cpp << '{' << endl; - cpp << " public:" << endl; - cpp << " " << cfg.className << "Helper() : q(nullptr) {}" << endl; - cpp << " ~" << cfg.className << "Helper() { delete q; }" << endl; - cpp << " " << cfg.className << "Helper(const " << cfg.className << "Helper&) = delete;" << endl; - cpp << " " << cfg.className << "Helper& operator=(const " << cfg.className << "Helper&) = delete;" << endl; - cpp << " " << cfg.className << " *q;" << endl; - cpp << "};" << endl; - endNamespaces(cfg.nameSpace, cpp); - cpp << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl; - - cpp << cfg.className << " *" << cfg.className << "::self()" << endl; - cpp << "{" << endl; - if (cfgFileNameArg) { - cpp << " if (!s_global" << cfg.className << "()->q)" << endl; - cpp << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl; - } else { - cpp << " if (!s_global" << cfg.className << "()->q) {" << endl; - cpp << " new " << cfg.className << ';' << endl; - cpp << " s_global" << cfg.className << "()->q->read();" << endl; - cpp << " }" << endl << endl; - } - cpp << " return s_global" << cfg.className << "()->q;" << endl; - cpp << "}" << endl << endl; - - if (cfgFileNameArg) { - auto instance = [&cfg, &cpp] (const QString &type, const QString &arg, bool isString) { - cpp << "void " << cfg.className << "::instance(" << type << " " << arg << ")" << endl; - cpp << "{" << endl; - cpp << " if (s_global" << cfg.className << "()->q) {" << endl; - cpp << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl; - cpp << " return;" << endl; - cpp << " }" << endl; - cpp << " new " << cfg.className << "("; - if (isString) { - cpp << "KSharedConfig::openConfig(" << arg << ")"; - } else { - cpp << "std::move(" << arg << ")"; - } - cpp << ");" << endl; - cpp << " s_global" << cfg.className << "()->q->read();" << endl; - cpp << "}" << endl << endl; - }; - instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true); - instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false); - } - } - - if (!cppPreamble.isEmpty()) { - cpp << cppPreamble << endl; - } - - // Constructor - cpp << cfg.className << "::" << cfg.className << "("; - if (cfgFileNameArg) { - if (! cfg.forceStringFilename) { - cpp << " KSharedConfig::Ptr config"; - } else { - cpp << " const QString& config"; - } - cpp << (parameters.isEmpty() ? "" : ","); - } - - for (QList<Param>::ConstIterator it = parameters.constBegin(); - it != parameters.constEnd(); ++it) { - if (it != parameters.constBegin()) { - cpp << ","; - } - cpp << " " << param((*it).type) << " " << (*it).name; - } - - if (cfg.parentInConstructor) { - if (cfgFileNameArg || !parameters.isEmpty()) { - cpp << ","; - } - cpp << " QObject *parent"; - } - cpp << " )" << endl; - - cpp << " : " << cfg.inherits << "("; - if (!cfgFileName.isEmpty()) { - cpp << " QStringLiteral( \"" << cfgFileName << "\" "; - } - if (cfgFileNameArg) { - if (! cfg.forceStringFilename) { - cpp << " std::move( config ) "; - } else { - cpp << " config "; - } - } - if (!cfgFileName.isEmpty()) { - cpp << ") "; - } - cpp << ")" << endl; - - // Store parameters - for (QList<Param>::ConstIterator it = parameters.constBegin(); - it != parameters.constEnd(); ++it) { - cpp << " , mParam" << (*it).name << "(" << (*it).name << ")" << endl; - } - - if (hasNonModifySignals && !cfg.dpointer) { - cpp << " , " << varName(QStringLiteral("settingsChanged"), cfg) << "(0)" << endl; - } - - cpp << "{" << endl; - - if (cfg.parentInConstructor) { - cpp << " setParent(parent);" << endl; - } - - if (cfg.dpointer) { - cpp << " d = new " + cfg.className + "Private;" << endl; - if (hasNonModifySignals) { - cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; - } - } - // Needed in case the singleton class is used as baseclass for - // another singleton. - if (cfg.singleton) { - cpp << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl; - cpp << " s_global" << cfg.className << "()->q = this;" << endl; - } - - group.clear(); - - if (hasSignals) { - // this cast to base-class pointer-to-member is valid C++ - // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/ - cpp << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction =" - << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&" - << cfg.className << "::itemChanged);" << endl << endl; - } - - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - if ((*itEntry)->group() != group) { - if (!group.isEmpty()) { - cpp << endl; - } - group = (*itEntry)->group(); - cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl; - } - - QString key = paramString((*itEntry)->key(), parameters); - if (!(*itEntry)->code().isEmpty()) { - cpp << (*itEntry)->code() << endl; - } - if ((*itEntry)->type() == QLatin1String("Enum")) { - cpp << " QList<" + cfg.inherits + "::ItemEnum::Choice> values" - << (*itEntry)->name() << ";" << endl; - const QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices; - QList<CfgEntry::Choice>::ConstIterator it; - for (it = choices.constBegin(); it != choices.constEnd(); ++it) { - cpp << " {" << endl; - cpp << " " + cfg.inherits + "::ItemEnum::Choice choice;" << endl; - cpp << " choice.name = QStringLiteral(\"" << (*it).name << "\");" << endl; - if (cfg.setUserTexts) { - if (!(*it).label.isEmpty()) { - cpp << " choice.label = " - << translatedString(cfg, (*it).label, (*it).context) - << ";" << endl; - } - if (!(*it).toolTip.isEmpty()) { - cpp << " choice.toolTip = " - << translatedString(cfg, (*it).toolTip, (*it).context) - << ";" << endl; - } - if (!(*it).whatsThis.isEmpty()) { - cpp << " choice.whatsThis = " - << translatedString(cfg, (*it).whatsThis, (*it).context) - << ";" << endl; - } - } - cpp << " values" << (*itEntry)->name() << ".append( choice );" << endl; - cpp << " }" << endl; - } - } - - if (!cfg.dpointer) { - cpp << itemDeclaration(*itEntry, cfg); - } - - if ((*itEntry)->param().isEmpty()) { - // Normal case - cpp << " " << itemPath(*itEntry, cfg) << " = " - << newItem((*itEntry), key, (*itEntry)->defaultValue(), cfg) << endl; - - if (!(*itEntry)->minValue().isEmpty()) { - cpp << " " << itemPath(*itEntry, cfg) << "->setMinValue(" << (*itEntry)->minValue() << ");" << endl; - } - if (!(*itEntry)->maxValue().isEmpty()) { - cpp << " " << itemPath(*itEntry, cfg) << "->setMaxValue(" << (*itEntry)->maxValue() << ");" << endl; - } - - if (cfg.setUserTexts) { - cpp << userTextsFunctions((*itEntry), cfg); - } - - if (cfg.allNotifiers || cfg.notifiers.contains((*itEntry)->name())) { - cpp << " " << itemPath(*itEntry, cfg) << "->setWriteFlags(KConfigBase::Notify);" << endl; - } - - cpp << " addItem( " << itemPath(*itEntry, cfg); - QString quotedName = (*itEntry)->name(); - addQuotes(quotedName); - if (quotedName != key) { - cpp << ", QStringLiteral( \"" << (*itEntry)->name() << "\" )"; - } - cpp << " );" << endl; - } else { - // Indexed - for (int i = 0; i <= (*itEntry)->paramMax(); i++) { - QString defaultStr; - QString itemVarStr(itemPath(*itEntry, cfg) + QStringLiteral("[%1]").arg(i)); - - if (!(*itEntry)->paramDefaultValue(i).isEmpty()) { - defaultStr = (*itEntry)->paramDefaultValue(i); - } else if (!(*itEntry)->defaultValue().isEmpty()) { - defaultStr = paramString((*itEntry)->defaultValue(), (*itEntry), i); - } else { - defaultStr = defaultValue((*itEntry)->type()); - } - - cpp << " " << itemVarStr << " = " - << newItem((*itEntry), paramString(key, *itEntry, i), defaultStr, cfg, QStringLiteral("[%1]").arg(i)) << endl; - - if (cfg.setUserTexts) { - cpp << userTextsFunctions(*itEntry, cfg, itemVarStr, (*itEntry)->paramName()); - } - - // Make mutators for enum parameters work by adding them with $(..) replaced by the - // param name. The check for isImmutable in the set* functions doesn't have the param - // name available, just the corresponding enum value (int), so we need to store the - // param names in a separate static list!. - cpp << " addItem( " << itemVarStr << ", QStringLiteral( \""; - if ((*itEntry)->paramType() == QLatin1String("Enum")) { - cpp << (*itEntry)->paramName().replace("$(" + (*itEntry)->param() + ')', QLatin1String("%1")).arg((*itEntry)->paramValues()[i]); - } else { - cpp << (*itEntry)->paramName().replace("$(" + (*itEntry)->param() + ')', QLatin1String("%1")).arg(i); - } - cpp << "\" ) );" << endl; - } - } - } - - cpp << "}" << endl << endl; - - if (cfg.dpointer) { - // setters and getters go in Cpp if in dpointer mode - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - QString n = (*itEntry)->name(); - QString t = (*itEntry)->type(); - - // Manipulator - if (cfg.allMutators || cfg.mutators.contains(n)) { - cpp << "void " << setFunction(n, cfg.className) << "( "; - if (!(*itEntry)->param().isEmpty()) { - cpp << cppType((*itEntry)->paramType()) << " i, "; - } - if (cfg.useEnumTypes && t == QLatin1String("Enum")) { - cpp << enumType(*itEntry, cfg.globalEnums); - } else { - cpp << param(t); - } - cpp << " v )" << endl; - // function body inline only if not using dpointer - // for BC mode - cpp << "{" << endl; - cpp << indent(memberMutatorBody(*itEntry, cfg), 6); - cpp << "}" << endl << endl; - } - - // Accessor - if (cfg.useEnumTypes && t == QLatin1String("Enum")) { - cpp << enumType(*itEntry, cfg.globalEnums); - } else { - cpp << cppType(t); - } - cpp << " " << getFunction(n, cfg.className) << "("; - if (!(*itEntry)->param().isEmpty()) { - cpp << " " << cppType((*itEntry)->paramType()) << " i "; - } - cpp << ")" << Const << endl; - // function body inline only if not using dpointer - // for BC mode - cpp << "{" << endl; - cpp << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 2); - cpp << "}" << endl << endl; - - // Default value Accessor -- written by the loop below - - // Item accessor - if (cfg.itemAccessors) { - cpp << endl; - cpp << cfg.inherits + "::Item" << itemType((*itEntry)->type()) << " *" - << getFunction(n, cfg.className) << "Item("; - if (!(*itEntry)->param().isEmpty()) { - cpp << " " << cppType((*itEntry)->paramType()) << " i "; - } - cpp << ")" << endl; - cpp << "{" << endl; - cpp << indent(itemAccessorBody(*itEntry, cfg), 2); - cpp << "}" << endl; - } - - cpp << endl; - } - } - - // default value getters always go in Cpp - for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { - QString n = (*itEntry)->name(); - QString t = (*itEntry)->type(); - - // Default value Accessor, as "helper" function - if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) { - cpp << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper("; - if (!(*itEntry)->param().isEmpty()) { - cpp << " " << cppType((*itEntry)->paramType()) << " i "; - } - cpp << ")" << Const << endl; - cpp << "{" << endl; - cpp << memberGetDefaultBody(*itEntry) << endl; - cpp << "}" << endl << endl; - } - } - - // Destructor - cpp << cfg.className << "::~" << cfg.className << "()" << endl; - cpp << "{" << endl; - if (cfg.dpointer) { - cpp << " delete d;" << endl; - } - if (cfg.singleton) { - cpp << " s_global" << cfg.className << "()->q = nullptr;" << endl; - } - cpp << "}" << endl << endl; - - if (hasNonModifySignals) { - cpp << "bool " << cfg.className << "::" << "usrSave()" << endl; - cpp << "{" << endl; - cpp << " const bool res = " << cfg.inherits << "::usrSave();" << endl; - cpp << " if (!res) return false;" << endl << endl; - for (const Signal &signal : qAsConst(signalList)) { - if (signal.modify) { - continue; - } - - cpp << " if ( " << varPath(QStringLiteral("settingsChanged"), cfg) << " & " << signalEnumName(signal.name) << " )" << endl; - cpp << " Q_EMIT " << signal.name << "("; - QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd(); - for (it = signal.arguments.constBegin(); it != itEnd;) { - SignalArguments argument = *it; - bool cast = false; - if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) { - for (int i = 0, end = entries.count(); i < end; ++i) { - if (entries[i]->name() == argument.variableName) { - cpp << "static_cast<" << enumType(entries[i], cfg.globalEnums) << ">("; - cast = true; - break; - } - } - } - cpp << varPath(argument.variableName, cfg); - if (cast) { - cpp << ")"; - } - if (++it != itEnd) { - cpp << ", "; - } - } - cpp << ");" << endl; - } - - cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; - cpp << " return true;" << endl; - cpp << "}" << endl; - } - - if (hasSignals) { - cpp << endl; - cpp << "void " << cfg.className << "::" << "itemChanged(quint64 flags) {" << endl; - if (hasNonModifySignals) - cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " |= flags;" << endl; - - if (!signalList.isEmpty()) - cpp << endl; - - for (const Signal &signal : qAsConst(signalList)) { - if (signal.modify) { - cpp << " if ( flags & " << signalEnumName(signal.name) << " ) {" << endl; - cpp << " Q_EMIT " << signal.name << "();" << endl; - cpp << " }" << endl; - } - } - - cpp << "}" << endl; - } - - if (hasSignals || cfg.generateProperties) { - // Add includemoc if they are signals defined. - cpp << endl; - cpp << "#include \"" << mocFileName << "\"" << endl; - cpp << endl; - } + // remove '.kcfg' from the name. + const QString baseName = inputFilename.mid(0, inputFilename.size()-5); + KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult); + headerGenerator.start(); + headerGenerator.save(); - // clear entries list - qDeleteAll(entries); + KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult); + sourceGenerator.start(); + sourceGenerator.save(); - implementation.close(); + qDeleteAll(parseResult.entries); } |