diff --git a/autotests/kconfig_compiler/kconfigcompiler_test.cpp b/autotests/kconfig_compiler/kconfigcompiler_test.cpp index 7ab4a92..383745b 100644 --- a/autotests/kconfig_compiler/kconfigcompiler_test.cpp +++ b/autotests/kconfig_compiler/kconfigcompiler_test.cpp @@ -1,186 +1,182 @@ /* Tests for KConfig Compiler Copyright (c) 2005 by Duncan Mac-Vicar Copyright (c) 2009 by Pino Toscano ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include #include #include #include #include #include #include "kconfigcompiler_test.h" // QT5 TODO QTEST_GUILESS_MAIN(KConfigCompiler_Test) QTEST_MAIN(KConfigCompiler_Test) typedef const char *CompilerTestSet[]; static CompilerTestSet testCases = { "test1.cpp", "test1.h", "test2.cpp", "test2.h", "test3.cpp", "test3.h", "test3a.cpp", "test3a.h", "test4.cpp", "test4.h", "test5.cpp", "test5.h", "test6.cpp", "test6.h", "test7.cpp", "test7.h", "test8a.cpp", "test8a.h", "test8b.cpp", "test8b.h", "test8c.cpp", "test8c.h", "test9.h", "test9.cpp", "test10.h", "test10.cpp", "test11.h", "test11.cpp", "test11a.h", "test11a.cpp", "test12.h", "test12.cpp", "test13.h", "test13.cpp", "test_dpointer.cpp", "test_dpointer.h", "test_qdebugcategory.cpp", "test_qdebugcategory.h", "test_signal.cpp", "test_signal.h", "test_notifiers.cpp", "test_notifiers.h", "test_translation_kde.cpp", "test_translation_kde.h", "test_translation_kde_domain.cpp", "test_translation_kde_domain.h", "test_translation_qt.cpp", "test_translation_qt.h", nullptr }; static CompilerTestSet testCasesToRun = { "test1", "test2", "test3", "test3a", "test4", "test5", "test6", "test7", "test8", "test9", "test10", "test11", "test12", "test13", "test_dpointer", "test_qdebugcategory", "test_signal", "test_translation_kde", "test_translation_kde_domain", "test_translation_qt", nullptr }; #if 0 static CompilerTestSet willFailCases = { // where is that QDir coming from? //"test9.cpp", NULL NULL }; #endif void KConfigCompiler_Test::initTestCase() { m_diffExe = QStandardPaths::findExecutable( QStringLiteral("diff") ); if (m_diffExe.isEmpty()) { qDebug() << "diff command not found, detailed info on comparison failure will not be available."; } } void KConfigCompiler_Test::testBaselineComparison_data() { QTest::addColumn("testName"); for (const char **it = testCases; *it; ++it) { QTest::newRow(*it) << QString::fromLatin1(*it); } } void KConfigCompiler_Test::testBaselineComparison() { QFETCH(QString, testName); QFile file(QFINDTESTDATA(testName)); QFile fileRef(QFINDTESTDATA(testName + QLatin1String(".ref"))); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Failed to open" << file.fileName() << "(" << testName << ")"; QFAIL("Can't open file for comparison"); } if (!fileRef.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Failed to open" << fileRef.fileName() << "(" << testName << ".ref )"; QFAIL("Can't open file for comparison"); } QString content = file.readAll(); QString contentRef = fileRef.readAll(); if (content != contentRef) { appendFileDiff(fileRef.fileName(), file.fileName()); } - + // use split('\n') to avoid + // the whole output shown inline + QCOMPARE(content.split('\n'), contentRef.split('\n')); QVERIFY(content == contentRef); } void KConfigCompiler_Test::testRunning_data() { QTest::addColumn("testName"); for (const char **it = testCasesToRun; *it; ++it) { QTest::newRow(*it) << QString::fromLatin1(*it); } } void KConfigCompiler_Test::testRunning() { QFETCH(QString, testName); #ifdef Q_OS_WIN testName += QStringLiteral(".exe"); #endif QString program = QFINDTESTDATA(testName); QVERIFY2(!program.isEmpty(), qPrintable(testName + QLatin1String(" must exist!"))); QVERIFY2(QFile::exists(program), qPrintable(program + QLatin1String(" must exist!"))); QProcess process; process.start(program, QStringList(), QIODevice::ReadOnly); if (process.waitForStarted()) { QVERIFY(process.waitForFinished()); } QCOMPARE((int)process.error(), (int)QProcess::UnknownError); QCOMPARE(process.exitCode(), 0); } void KConfigCompiler_Test::appendFileDiff(const QString &oldFile, const QString &newFile) { if (m_diffExe.isEmpty()) { return; } - QStringList args({ - QStringLiteral("-u"), - QFileInfo(oldFile).absoluteFilePath(), - QFileInfo(newFile).absoluteFilePath() }); + QStringList args; + args << QStringLiteral("-u"); + args << QFileInfo(oldFile).absoluteFilePath(); + args << QFileInfo(newFile).absoluteFilePath(); QProcess process; process.start(m_diffExe, args, QIODevice::ReadOnly); process.waitForStarted(); process.waitForFinished(); - if (process.exitCode() == 1) { - const QString diffFileName = oldFile + QStringLiteral(".diff"); - QFile diffFile(diffFileName); - QVERIFY2(diffFile.open(QIODevice::WriteOnly), qPrintable(QLatin1String("Could not save diff file for ") + oldFile)); - diffFile.write(process.readAllStandardOutput()); - - // force a failure to print the flename where we stored the diff. - QVERIFY2(false, qPrintable(QLatin1String("This test failed, look at the following file for details: ") + diffFileName)); + QByteArray out = process.readAllStandardOutput(); + qDebug() << '\n' << out; } } diff --git a/autotests/kconfig_compiler/test1.h.ref b/autotests/kconfig_compiler/test1.h.ref index 52921ac..77c3b65 100644 --- a/autotests/kconfig_compiler/test1.h.ref +++ b/autotests/kconfig_compiler/test1.h.ref @@ -1,198 +1,197 @@ // This file is generated by kconfig_compiler_kf5 from test1.kcfg. // All changes you do to this file will be lost. #ifndef TEST1_H #define TEST1_H #include #include #include #include - class Test1 : public KConfigSkeleton { public: class EnumListOption { public: enum type { One, Two, Three, COUNT }; }; Test1( const QString & transport, const QString & folder, QObject *parent = nullptr ); ~Test1(); /** Set One option */ void setOneOption( bool v ) { if (!isImmutable( QStringLiteral( "OneOption" ) )) mOneOption = v; } /** Get One option */ bool oneOption() const { return mOneOption; } /** Set Another option */ void setAnotherOption( int v ) { if (!isImmutable( QStringLiteral( "AnotherOption" ) )) mAnotherOption = v; } /** Get Another option */ int anotherOption() const { return mAnotherOption; } /** Set This is some funky option */ void setListOption( int v ) { if (!isImmutable( QStringLiteral( "ListOption" ) )) mListOption = v; } /** Get This is some funky option */ int listOption() const { return mListOption; } /** Set This is a string */ void setMyString( const QString & v ) { if (!isImmutable( QStringLiteral( "MyString" ) )) mMyString = v; } /** Get This is a string */ QString myString() const { return mMyString; } /** Set This is a path */ void setMyPath( const QString & v ) { if (!isImmutable( QStringLiteral( "MyPath" ) )) mMyPath = v; } /** Get This is a path */ QString myPath() const { return mMyPath; } /** Set Another option */ void setAnotherOption2( int v ) { if (!isImmutable( QStringLiteral( "AnotherOption2" ) )) mAnotherOption2 = v; } /** Get Another option */ int anotherOption2() const { return mAnotherOption2; } /** Set MyStringList */ void setMyStringList( const QStringList & v ) { if (!isImmutable( QStringLiteral( "MyStringList" ) )) mMyStringList = v; } /** Get MyStringList */ QStringList myStringList() const { return mMyStringList; } /** Set MyStringListHidden */ void setMyStringListHidden( const QStringList & v ) { if (!isImmutable( QStringLiteral( "MyStringListHidden" ) )) mMyStringListHidden = v; } /** Get MyStringListHidden */ QStringList myStringListHidden() const { return mMyStringListHidden; } /** Set List Number */ void setMyNumber( int v ) { if (!isImmutable( QStringLiteral( "MyNumber" ) )) mMyNumber = v; } /** Get List Number */ int myNumber() const { return mMyNumber; } protected: QString mParamtransport; QString mParamfolder; // General-$(folder) bool mOneOption; int mAnotherOption; int mListOption; // MyOptions QString mMyString; QString mMyPath; int mAnotherOption2; QStringList mMyStringList; QStringList mMyStringListHidden; int mMyNumber; private: }; #endif diff --git a/autotests/kconfig_compiler/test10.h.ref b/autotests/kconfig_compiler/test10.h.ref index 82bbab8..93839a5 100644 --- a/autotests/kconfig_compiler/test10.h.ref +++ b/autotests/kconfig_compiler/test10.h.ref @@ -1,48 +1,50 @@ // This file is generated by kconfig_compiler_kf5 from test10.kcfg. // All changes you do to this file will be lost. #ifndef TEST10_H #define TEST10_H #include #include #include class Test10 : public KConfigSkeleton { public: static Test10 *self(); ~Test10(); + /** Get foo bar */ static QUrl fooBar() { return self()->mFooBar; } + /** Get bar foo */ static QList barFoo() { return self()->mBarFoo; } protected: Test10(); friend class Test10Helper; // Foo QUrl mFooBar; QList mBarFoo; private: }; #endif diff --git a/autotests/kconfig_compiler/test11.h.ref b/autotests/kconfig_compiler/test11.h.ref index 2acbe9e..395810e 100644 --- a/autotests/kconfig_compiler/test11.h.ref +++ b/autotests/kconfig_compiler/test11.h.ref @@ -1,573 +1,572 @@ // This file is generated by kconfig_compiler_kf5 from test11.kcfg. // All changes you do to this file will be lost. #ifndef TEST11_H #define TEST11_H #include #include #include #include #include #include "test11_types.h" - class Test11 : public MyPrefs { public: class EnumDestination { public: enum type { standardDestination, askDestination, argl1, argl2, argl3, COUNT }; }; enum MailClient { sendmail, kmail }; Test11( QObject *parent = nullptr ); ~Test11(); /** Set Enable automatic saving of calendar */ void setAutoSave( bool v ) { if (!isImmutable( QStringLiteral( "AutoSave" ) )) mAutoSave = v; } /** Get Enable automatic saving of calendar */ bool autoSave() const { return mAutoSave; } /** Get Enable automatic saving of calendar default value */ bool defaultAutoSaveValue() const { return defaultAutoSaveValue_helper(); } /** Get Item object corresponding to AutoSave() */ ItemBool *autoSaveItem() { return mAutoSaveItem; } /** Set Auto Save Interval */ void setAutoSaveInterval( int v ) { if (!isImmutable( QStringLiteral( "AutoSaveInterval" ) )) mAutoSaveInterval = v; } /** Get Auto Save Interval */ int autoSaveInterval() const { return mAutoSaveInterval; } /** Get Auto Save Interval default value */ int defaultAutoSaveIntervalValue() const { return defaultAutoSaveIntervalValue_helper(); } /** Get Item object corresponding to AutoSaveInterval() */ ItemInt *autoSaveIntervalItem() { return mAutoSaveIntervalItem; } /** Set Confirm deletes */ void setConfirm( bool v ) { if (!isImmutable( QStringLiteral( "Confirm" ) )) mConfirm = v; } /** Get Confirm deletes */ bool confirm() const { return mConfirm; } /** Get Confirm deletes default value */ bool defaultConfirmValue() const { return defaultConfirmValue_helper(); } /** Get Item object corresponding to Confirm() */ ItemBool *confirmItem() { return mConfirmItem; } /** Set Archive File */ void setArchiveFile( const QString & v ) { if (!isImmutable( QStringLiteral( "ArchiveFile" ) )) mArchiveFile = v; } /** Get Archive File */ QString archiveFile() const { return mArchiveFile; } /** Get Item object corresponding to ArchiveFile() */ ItemString *archiveFileItem() { return mArchiveFileItem; } /** Set New Events/Todos Should */ void setDestination( EnumDestination::type v ) { if (!isImmutable( QStringLiteral( "Destination" ) )) mDestination = v; } /** Get New Events/Todos Should */ EnumDestination::type destination() const { return static_cast(mDestination); } /** Get New Events/Todos Should default value */ EnumDestination::type defaultDestinationValue() const { return static_cast(defaultDestinationValue_helper()); } /** Get Item object corresponding to Destination() */ ItemEnum *destinationItem() { return mDestinationItem; } /** Set Hour Size */ void setHourSize( int v ) { if (!isImmutable( QStringLiteral( "HourSize" ) )) mHourSize = v; } /** Get Hour Size */ int hourSize() const { return mHourSize; } /** Get Hour Size default value */ int defaultHourSizeValue() const { return defaultHourSizeValue_helper(); } /** Get Item object corresponding to HourSize() */ ItemInt *hourSizeItem() { return mHourSizeItem; } /** Set Time range selection in agenda view starts event editor */ void setSelectionStartsEditor( bool v ) { if (!isImmutable( QStringLiteral( "SelectionStartsEditor" ) )) mSelectionStartsEditor = v; } /** Get Time range selection in agenda view starts event editor */ bool selectionStartsEditor() const { return mSelectionStartsEditor; } /** Get Time range selection in agenda view starts event editor default value */ bool defaultSelectionStartsEditorValue() const { return defaultSelectionStartsEditorValue_helper(); } /** Get Item object corresponding to SelectionStartsEditor() */ ItemBool *selectionStartsEditorItem() { return mSelectionStartsEditorItem; } /** Set SelectedPlugins */ void setSelectedPlugins( const QStringList & v ) { if (!isImmutable( QStringLiteral( "SelectedPlugins" ) )) mSelectedPlugins = v; } /** Get SelectedPlugins */ QStringList selectedPlugins() const { return mSelectedPlugins; } /** Get SelectedPlugins default value */ QStringList defaultSelectedPluginsValue() const { return defaultSelectedPluginsValue_helper(); } /** Get Item object corresponding to SelectedPlugins() */ ItemStringList *selectedPluginsItem() { return mSelectedPluginsItem; } /** Set Highlight color */ void setHighlightColor( const QColor & v ) { if (!isImmutable( QStringLiteral( "HighlightColor" ) )) mHighlightColor = v; } /** Get Highlight color */ QColor highlightColor() const { return mHighlightColor; } /** Get Highlight color default value */ QColor defaultHighlightColorValue() const { return defaultHighlightColorValue_helper(); } /** Get Item object corresponding to HighlightColor() */ ItemColor *highlightColorItem() { return mHighlightColorItem; } /** Set Agenda view background color */ void setAgendaBgColor( const QColor & v ) { if (!isImmutable( QStringLiteral( "AgendaBgColor" ) )) mAgendaBgColor = v; } /** Get Agenda view background color */ QColor agendaBgColor() const { return mAgendaBgColor; } /** Get Agenda view background color default value */ QColor defaultAgendaBgColorValue() const { return defaultAgendaBgColorValue_helper(); } /** Get Item object corresponding to AgendaBgColor() */ ItemColor *agendaBgColorItem() { return mAgendaBgColorItem; } /** Set Time bar */ void setTimeBarFont( const QFont & v ) { if (!isImmutable( QStringLiteral( "TimeBarFont" ) )) mTimeBarFont = v; } /** Get Time bar */ QFont timeBarFont() const { return mTimeBarFont; } /** Get Item object corresponding to TimeBarFont() */ ItemFont *timeBarFontItem() { return mTimeBarFontItem; } /** Set Email client */ void setEmailClient( MailClient v ) { if (!isImmutable( QStringLiteral( "EmailClient" ) )) mEmailClient = v; } /** Get Email client */ MailClient emailClient() const { return static_cast(mEmailClient); } /** Get Email client default value */ MailClient defaultEmailClientValue() const { return static_cast(defaultEmailClientValue_helper()); } /** Get Item object corresponding to EmailClient() */ ItemEnum *emailClientItem() { return mEmailClientItem; } /** Set Reminder units */ void setDefaultReminderUnits( TimePeriod::Units v ) { if (!isImmutable( QStringLiteral( "DefaultReminderUnits" ) )) mDefaultReminderUnits = v; } /** Get Reminder units */ TimePeriod::Units defaultReminderUnits() const { return static_cast(mDefaultReminderUnits); } /** Get Reminder units default value */ TimePeriod::Units defaultDefaultReminderUnitsValue() const { return static_cast(defaultDefaultReminderUnitsValue_helper()); } /** Get Item object corresponding to DefaultReminderUnits() */ ItemEnum *defaultReminderUnitsItem() { return mDefaultReminderUnitsItem; } /** Set EmptyingRate $(QueueIndex) */ void setQueueRate( int i, const QList & v ) { if (!isImmutable( QStringLiteral( "queueRate%1" ).arg( i ) )) mQueueRate[i] = v; } /** Get EmptyingRate $(QueueIndex) */ QList queueRate( int i ) const { return mQueueRate[i]; } /** Get EmptyingRate $(QueueIndex) default value */ QList defaultQueueRateValue( int i ) const { return defaultQueueRateValue_helper( i ); } /** Get Item object corresponding to queueRate() */ ItemIntList *queueRateItem( int i ) { return mQueueRateItem[i]; } /** Set ShowQueueTuner */ void setShowQueueTuner( bool v ) { if (!isImmutable( QStringLiteral( "ShowQueueTuner" ) )) mShowQueueTuner = v; } /** Get ShowQueueTuner */ bool showQueueTuner() const { return mShowQueueTuner; } /** Get ShowQueueTuner default value */ bool defaultShowQueueTunerValue() const { return defaultShowQueueTunerValue_helper(); } /** Get Item object corresponding to ShowQueueTuner() */ ItemBool *showQueueTunerItem() { return mShowQueueTunerItem; } protected: public: // General bool mAutoSave; bool defaultAutoSaveValue_helper() const; int mAutoSaveInterval; int defaultAutoSaveIntervalValue_helper() const; bool mConfirm; bool defaultConfirmValue_helper() const; QString mArchiveFile; QString defaultArchiveFileValue_helper() const; int mDestination; int defaultDestinationValue_helper() const; // Views int mHourSize; int defaultHourSizeValue_helper() const; bool mSelectionStartsEditor; bool defaultSelectionStartsEditorValue_helper() const; // KOrganizer Plugins QStringList mSelectedPlugins; QStringList defaultSelectedPluginsValue_helper() const; // Colors QColor mHighlightColor; QColor defaultHighlightColorValue_helper() const; QColor mAgendaBgColor; QColor defaultAgendaBgColorValue_helper() const; // Fonts QFont mTimeBarFont; QFont defaultTimeBarFontValue_helper() const; // Email int mEmailClient; int defaultEmailClientValue_helper() const; int mDefaultReminderUnits; int defaultDefaultReminderUnitsValue_helper() const; // QueueRates QList mQueueRate[3]; QList defaultQueueRateValue_helper( int i ) const; bool mShowQueueTuner; bool defaultShowQueueTunerValue_helper() const; private: ItemBool *mAutoSaveItem; ItemInt *mAutoSaveIntervalItem; ItemBool *mConfirmItem; ItemString *mArchiveFileItem; ItemEnum *mDestinationItem; ItemInt *mHourSizeItem; ItemBool *mSelectionStartsEditorItem; ItemStringList *mSelectedPluginsItem; ItemColor *mHighlightColorItem; ItemColor *mAgendaBgColorItem; ItemFont *mTimeBarFontItem; ItemEnum *mEmailClientItem; ItemEnum *mDefaultReminderUnitsItem; ItemIntList *mQueueRateItem[3]; ItemBool *mShowQueueTunerItem; }; #endif diff --git a/autotests/kconfig_compiler/test11a.h.ref b/autotests/kconfig_compiler/test11a.h.ref index 62b5938..23c8371 100644 --- a/autotests/kconfig_compiler/test11a.h.ref +++ b/autotests/kconfig_compiler/test11a.h.ref @@ -1,481 +1,480 @@ // This file is generated by kconfig_compiler_kf5 from test11a.kcfg. // All changes you do to this file will be lost. #ifndef TEST11A_H #define TEST11A_H #include #include #include #include #include #include "test11_types.h" - class Test11a : public MyPrefs { public: class EnumDestination { public: enum type { standardDestination, askDestination, argl1, argl2, argl3, COUNT }; }; enum MailClient { sendmail, kmail }; Test11a( ); ~Test11a(); /** Set Enable automatic saving of calendar */ void setAutoSave( bool v ) { if (!isImmutable( QStringLiteral( "AutoSave" ) )) mAutoSave = v; } /** Get Enable automatic saving of calendar */ bool autoSave() const { return mAutoSave; } /** Get Item object corresponding to AutoSave() */ ItemBool *autoSaveItem() { return mAutoSaveItem; } /** Set Auto Save Interval */ void setAutoSaveInterval( int v ) { if (!isImmutable( QStringLiteral( "AutoSaveInterval" ) )) mAutoSaveInterval = v; } /** Get Auto Save Interval */ int autoSaveInterval() const { return mAutoSaveInterval; } /** Get Item object corresponding to AutoSaveInterval() */ ItemInt *autoSaveIntervalItem() { return mAutoSaveIntervalItem; } /** Set Confirm deletes */ void setConfirm( bool v ) { if (!isImmutable( QStringLiteral( "Confirm" ) )) mConfirm = v; } /** Get Confirm deletes */ bool confirm() const { return mConfirm; } /** Get Item object corresponding to Confirm() */ ItemBool *confirmItem() { return mConfirmItem; } /** Set Archive File */ void setArchiveFile( const QString & v ) { if (!isImmutable( QStringLiteral( "ArchiveFile" ) )) mArchiveFile = v; } /** Get Archive File */ QString archiveFile() const { return mArchiveFile; } /** Get Item object corresponding to ArchiveFile() */ ItemString *archiveFileItem() { return mArchiveFileItem; } /** Set New Events/Todos Should */ void setDestination( EnumDestination::type v ) { if (!isImmutable( QStringLiteral( "Destination" ) )) mDestination = v; } /** Get New Events/Todos Should */ EnumDestination::type destination() const { return static_cast(mDestination); } /** Get New Events/Todos Should default value */ EnumDestination::type defaultDestinationValue() const { return static_cast(defaultDestinationValue_helper()); } /** Get Item object corresponding to Destination() */ ItemEnum *destinationItem() { return mDestinationItem; } /** Set Hour Size */ void setHourSize( int v ) { if (!isImmutable( QStringLiteral( "HourSize" ) )) mHourSize = v; } /** Get Hour Size */ int hourSize() const { return mHourSize; } /** Get Item object corresponding to HourSize() */ ItemInt *hourSizeItem() { return mHourSizeItem; } /** Set Time range selection in agenda view starts event editor */ void setSelectionStartsEditor( bool v ) { if (!isImmutable( QStringLiteral( "SelectionStartsEditor" ) )) mSelectionStartsEditor = v; } /** Get Time range selection in agenda view starts event editor */ bool selectionStartsEditor() const { return mSelectionStartsEditor; } /** Get Time range selection in agenda view starts event editor default value */ bool defaultSelectionStartsEditorValue() const { return defaultSelectionStartsEditorValue_helper(); } /** Get Item object corresponding to SelectionStartsEditor() */ ItemBool *selectionStartsEditorItem() { return mSelectionStartsEditorItem; } /** Set SelectedPlugins */ void setSelectedPlugins( const QStringList & v ) { if (!isImmutable( QStringLiteral( "SelectedPlugins" ) )) mSelectedPlugins = v; } /** Get SelectedPlugins */ QStringList selectedPlugins() const { return mSelectedPlugins; } /** Get Item object corresponding to SelectedPlugins() */ ItemStringList *selectedPluginsItem() { return mSelectedPluginsItem; } /** Set Highlight color */ void setHighlightColor( const QColor & v ) { if (!isImmutable( QStringLiteral( "HighlightColor" ) )) mHighlightColor = v; } /** Get Highlight color */ QColor highlightColor() const { return mHighlightColor; } /** Get Item object corresponding to HighlightColor() */ ItemColor *highlightColorItem() { return mHighlightColorItem; } /** Set Agenda view background color */ void setAgendaBgColor( const QColor & v ) { if (!isImmutable( QStringLiteral( "AgendaBgColor" ) )) mAgendaBgColor = v; } /** Get Agenda view background color */ QColor agendaBgColor() const { return mAgendaBgColor; } /** Get Item object corresponding to AgendaBgColor() */ ItemColor *agendaBgColorItem() { return mAgendaBgColorItem; } /** Set Time bar */ void setTimeBarFont( const QFont & v ) { if (!isImmutable( QStringLiteral( "TimeBarFont" ) )) mTimeBarFont = v; } /** Get Time bar */ QFont timeBarFont() const { return mTimeBarFont; } /** Get Item object corresponding to TimeBarFont() */ ItemFont *timeBarFontItem() { return mTimeBarFontItem; } /** Set Email client */ void setEmailClient( MailClient v ) { if (!isImmutable( QStringLiteral( "EmailClient" ) )) mEmailClient = v; } /** Get Email client */ MailClient emailClient() const { return static_cast(mEmailClient); } /** Get Item object corresponding to EmailClient() */ ItemEnum *emailClientItem() { return mEmailClientItem; } /** Set Reminder units */ void setDefaultReminderUnits( TimePeriod::Units v ) { if (!isImmutable( QStringLiteral( "DefaultReminderUnits" ) )) mDefaultReminderUnits = v; } /** Get Reminder units */ TimePeriod::Units defaultReminderUnits() const { return static_cast(mDefaultReminderUnits); } /** Get Reminder units default value */ TimePeriod::Units defaultDefaultReminderUnitsValue() const { return static_cast(defaultDefaultReminderUnitsValue_helper()); } /** Get Item object corresponding to DefaultReminderUnits() */ ItemEnum *defaultReminderUnitsItem() { return mDefaultReminderUnitsItem; } /** Set EmptyingRate $(QueueIndex) */ void setQueueRate( int i, const QList & v ) { if (!isImmutable( QStringLiteral( "queueRate%1" ).arg( i ) )) mQueueRate[i] = v; } /** Get EmptyingRate $(QueueIndex) */ QList queueRate( int i ) const { return mQueueRate[i]; } /** Get Item object corresponding to queueRate() */ ItemIntList *queueRateItem( int i ) { return mQueueRateItem[i]; } /** Set ShowQueueTuner */ void setShowQueueTuner( bool v ) { if (!isImmutable( QStringLiteral( "ShowQueueTuner" ) )) mShowQueueTuner = v; } /** Get ShowQueueTuner */ bool showQueueTuner() const { return mShowQueueTuner; } /** Get Item object corresponding to ShowQueueTuner() */ ItemBool *showQueueTunerItem() { return mShowQueueTunerItem; } protected: public: // General bool mAutoSave; int mAutoSaveInterval; bool mConfirm; QString mArchiveFile; int mDestination; int defaultDestinationValue_helper() const; // Views int mHourSize; bool mSelectionStartsEditor; bool defaultSelectionStartsEditorValue_helper() const; // KOrganizer Plugins QStringList mSelectedPlugins; // Colors QColor mHighlightColor; QColor mAgendaBgColor; // Fonts QFont mTimeBarFont; // Email int mEmailClient; int mDefaultReminderUnits; int defaultDefaultReminderUnitsValue_helper() const; // QueueRates QList mQueueRate[3]; bool mShowQueueTuner; private: ItemBool *mAutoSaveItem; ItemInt *mAutoSaveIntervalItem; ItemBool *mConfirmItem; ItemString *mArchiveFileItem; ItemEnum *mDestinationItem; ItemInt *mHourSizeItem; ItemBool *mSelectionStartsEditorItem; ItemStringList *mSelectedPluginsItem; ItemColor *mHighlightColorItem; ItemColor *mAgendaBgColorItem; ItemFont *mTimeBarFontItem; ItemEnum *mEmailClientItem; ItemEnum *mDefaultReminderUnitsItem; ItemIntList *mQueueRateItem[3]; ItemBool *mShowQueueTunerItem; }; #endif diff --git a/autotests/kconfig_compiler/test12.h.ref b/autotests/kconfig_compiler/test12.h.ref index e395428..d96d460 100644 --- a/autotests/kconfig_compiler/test12.h.ref +++ b/autotests/kconfig_compiler/test12.h.ref @@ -1,35 +1,36 @@ // This file is generated by kconfig_compiler_kf5 from test12.kcfg. // All changes you do to this file will be lost. #ifndef TEST12_H #define TEST12_H #include #include #include #include class Test12 : public KConfigSkeleton { public: Test12( ); ~Test12(); + /** Get RnRSource */ QList rnRSource() const { return mRnRSource; } protected: // muon QList mRnRSource; private: }; #endif diff --git a/autotests/kconfig_compiler/test13.h.ref b/autotests/kconfig_compiler/test13.h.ref index 3a6e7f8..6c67fc5 100644 --- a/autotests/kconfig_compiler/test13.h.ref +++ b/autotests/kconfig_compiler/test13.h.ref @@ -1,79 +1,81 @@ // This file is generated by kconfig_compiler_kf5 from test13.kcfg. // All changes you do to this file will be lost. #ifndef TEST13_H #define TEST13_H #include #include #include #include class Test13 : public KConfigSkeleton { Q_OBJECT public: Test13( ); ~Test13(); + Q_PROPERTY(QUrl picturesDir READ picturesDir CONSTANT) /** Get picturesDir */ QUrl picturesDir() const { return mPicturesDir; } /** Set brightness */ void setBrightness( double v ) { if (v != mBrightness && !isImmutable( QStringLiteral( "brightness" ) )) { mBrightness = v; Q_EMIT brightnessChanged(); } } Q_PROPERTY(double brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged) /** Get brightness */ double brightness() const { return mBrightness; } + Q_PROPERTY(bool startsWithUppercase READ startsWithUppercase CONSTANT) /** Get StartsWithUppercase */ bool startsWithUppercase() const { return mStartsWithUppercase; } enum { signalBrightnessChanged = 0x1 }; Q_SIGNALS: void brightnessChanged(); private: void itemChanged(quint64 flags); protected: // kamoso QUrl mPicturesDir; double mBrightness; bool mStartsWithUppercase; private: }; #endif diff --git a/autotests/kconfig_compiler/test9.h.ref b/autotests/kconfig_compiler/test9.h.ref index 6e40cf4..9bcf000 100644 --- a/autotests/kconfig_compiler/test9.h.ref +++ b/autotests/kconfig_compiler/test9.h.ref @@ -1,84 +1,83 @@ // This file is generated by kconfig_compiler_kf5 from test9.kcfg. // All changes you do to this file will be lost. #ifndef TEST9_H #define TEST9_H #include #include #include #include - class Test9 : public KConfigSkeleton { public: Test9( const QString & transport, const QString & folder ); ~Test9(); /** Set MyStringList */ void setMyStringList( const QStringList & v ) { if (!isImmutable( QStringLiteral( "MyStringList" ) )) mMyStringList = v; } /** Get MyStringList */ QStringList myStringList() const { return mMyStringList; } /** Set This is a list of paths */ void setMyPathList( const QStringList & v ) { if (!isImmutable( QStringLiteral( "MyPathList" ) )) mMyPathList = v; } /** Get This is a list of paths */ QStringList myPathList() const { return mMyPathList; } /** Set This is an additional test for PathList */ void setMyPathsList2( const QStringList & v ) { if (!isImmutable( QStringLiteral( "MyPathsList2" ) )) mMyPathsList2 = v; } /** Get This is an additional test for PathList */ QStringList myPathsList2() const { return mMyPathsList2; } protected: public: QString mParamtransport; QString mParamfolder; // MyOptionsXX QStringList mMyStringList; QStringList mMyPathList; QStringList mMyPathsList2; private: }; #endif diff --git a/autotests/kconfig_compiler/test_dpointer.cpp.ref b/autotests/kconfig_compiler/test_dpointer.cpp.ref index 1bfb9f5..c69d38a 100644 --- a/autotests/kconfig_compiler/test_dpointer.cpp.ref +++ b/autotests/kconfig_compiler/test_dpointer.cpp.ref @@ -1,350 +1,350 @@ // This file is generated by kconfig_compiler_kf5 from test_dpointer.kcfg. // All changes you do to this file will be lost. #include "test_dpointer.h" #include #include class TestDPointerPrivate { public: // General bool autoSave; int autoSaveInterval; bool confirm; QString archiveFile; int destination; // Views int hourSize; bool selectionStartsEditor; // KOrganizer Plugins QStringList selectedPlugins; // Colors QColor highlightColor; QColor agendaBgColor; // Fonts QFont timeBarFont; // items KConfigSkeleton::ItemBool *autoSaveItem; KConfigSkeleton::ItemInt *autoSaveIntervalItem; KConfigSkeleton::ItemBool *confirmItem; KConfigSkeleton::ItemString *archiveFileItem; KConfigSkeleton::ItemEnum *destinationItem; KConfigSkeleton::ItemInt *hourSizeItem; KConfigSkeleton::ItemBool *selectionStartsEditorItem; KConfigSkeleton::ItemStringList *selectedPluginsItem; KConfigSkeleton::ItemColor *highlightColorItem; KConfigSkeleton::ItemColor *agendaBgColorItem; KConfigSkeleton::ItemFont *timeBarFontItem; }; class TestDPointerHelper { public: TestDPointerHelper() : q(nullptr) {} ~TestDPointerHelper() { delete q; } TestDPointerHelper(const TestDPointerHelper&) = delete; TestDPointerHelper& operator=(const TestDPointerHelper&) = delete; TestDPointer *q; }; Q_GLOBAL_STATIC(TestDPointerHelper, s_globalTestDPointer) TestDPointer *TestDPointer::self() { if (!s_globalTestDPointer()->q) { new TestDPointer; s_globalTestDPointer()->q->read(); } return s_globalTestDPointer()->q; } TestDPointer::TestDPointer( ) : KConfigSkeleton( QStringLiteral( "korganizerrc" ) ) { d = new TestDPointerPrivate; Q_ASSERT(!s_globalTestDPointer()->q); s_globalTestDPointer()->q = this; setCurrentGroup( QStringLiteral( "General" ) ); d->autoSaveItem = new KConfigSkeleton::ItemBool( currentGroup(), QStringLiteral( "Auto Save" ), d->autoSave, false ); d->autoSaveItem->setLabel( QCoreApplication::translate("TestDPointer", "Enable automatic saving of calendar") ); d->autoSaveItem->setWhatsThis( QCoreApplication::translate("TestDPointer", "WhatsThis text for AutoSave option") ); addItem( d->autoSaveItem, QStringLiteral( "AutoSave" ) ); d->autoSaveIntervalItem = new KConfigSkeleton::ItemInt( currentGroup(), QStringLiteral( "Auto Save Interval" ), d->autoSaveInterval, 10 ); d->autoSaveIntervalItem->setLabel( QCoreApplication::translate("TestDPointer", "Auto Save Interval") ); addItem( d->autoSaveIntervalItem, QStringLiteral( "AutoSaveInterval" ) ); d->confirmItem = new KConfigSkeleton::ItemBool( currentGroup(), QStringLiteral( "Confirm Deletes" ), d->confirm, true ); d->confirmItem->setLabel( QCoreApplication::translate("TestDPointer", "Confirm deletes") ); addItem( d->confirmItem, QStringLiteral( "Confirm" ) ); d->archiveFileItem = new KConfigSkeleton::ItemString( currentGroup(), QStringLiteral( "Archive File" ), d->archiveFile ); d->archiveFileItem->setLabel( QCoreApplication::translate("TestDPointer", "Archive File") ); addItem( d->archiveFileItem, QStringLiteral( "ArchiveFile" ) ); QList valuesDestination; { KConfigSkeleton::ItemEnum::Choice choice; choice.name = QStringLiteral("standardDestination"); valuesDestination.append( choice ); } { KConfigSkeleton::ItemEnum::Choice choice; choice.name = QStringLiteral("askDestination"); valuesDestination.append( choice ); } { KConfigSkeleton::ItemEnum::Choice choice; choice.name = QStringLiteral("argl1"); choice.label = QCoreApplication::translate("TestDPointer", "Argl1 Label"); valuesDestination.append( choice ); } { KConfigSkeleton::ItemEnum::Choice choice; choice.name = QStringLiteral("argl2"); choice.whatsThis = QCoreApplication::translate("TestDPointer", "Argl2 Whatsthis"); valuesDestination.append( choice ); } { KConfigSkeleton::ItemEnum::Choice choice; choice.name = QStringLiteral("argl3"); choice.label = QCoreApplication::translate("TestDPointer", "Argl3 Label"); choice.whatsThis = QCoreApplication::translate("TestDPointer", "Argl3 Whatsthis"); valuesDestination.append( choice ); } d->destinationItem = new KConfigSkeleton::ItemEnum( currentGroup(), QStringLiteral( "Destination" ), d->destination, valuesDestination, EnumDestination::standardDestination ); d->destinationItem->setLabel( QCoreApplication::translate("TestDPointer", "New Events/Todos Should") ); addItem( d->destinationItem, QStringLiteral( "Destination" ) ); setCurrentGroup( QStringLiteral( "Views" ) ); d->hourSizeItem = new KConfigSkeleton::ItemInt( currentGroup(), QStringLiteral( "Hour Size" ), d->hourSize, 10 ); d->hourSizeItem->setLabel( QCoreApplication::translate("TestDPointer", "Hour Size") ); addItem( d->hourSizeItem, QStringLiteral( "HourSize" ) ); d->selectionStartsEditorItem = new KConfigSkeleton::ItemBool( currentGroup(), QStringLiteral( "SelectionStartsEditor" ), d->selectionStartsEditor, false ); d->selectionStartsEditorItem->setLabel( QCoreApplication::translate("TestDPointer", "Time range selection in agenda view starts event editor") ); addItem( d->selectionStartsEditorItem, QStringLiteral( "SelectionStartsEditor" ) ); setCurrentGroup( QStringLiteral( "KOrganizer Plugins" ) ); QStringList defaultSelectedPlugins; defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) ); defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) ); d->selectedPluginsItem = new KConfigSkeleton::ItemStringList( currentGroup(), QStringLiteral( "SelectedPlugins" ), d->selectedPlugins, defaultSelectedPlugins ); d->selectedPluginsItem->setLabel( QCoreApplication::translate("TestDPointer", "SelectedPlugins") ); addItem( d->selectedPluginsItem, QStringLiteral( "SelectedPlugins" ) ); setCurrentGroup( QStringLiteral( "Colors" ) ); d->highlightColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QStringLiteral( "Highlight Color" ), d->highlightColor, QColor( 100, 100, 255 ) ); d->highlightColorItem->setLabel( QCoreApplication::translate("TestDPointer", "Highlight color") ); addItem( d->highlightColorItem, QStringLiteral( "HighlightColor" ) ); d->agendaBgColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QStringLiteral( "Agenda Background Color" ), d->agendaBgColor, QColor( 255, 255, 255 ) ); d->agendaBgColorItem->setLabel( QCoreApplication::translate("TestDPointer", "Agenda view background color") ); addItem( d->agendaBgColorItem, QStringLiteral( "AgendaBgColor" ) ); setCurrentGroup( QStringLiteral( "Fonts" ) ); d->timeBarFontItem = new KConfigSkeleton::ItemFont( currentGroup(), QStringLiteral( "TimeBar Font" ), d->timeBarFont ); d->timeBarFontItem->setLabel( QCoreApplication::translate("TestDPointer", "Time bar") ); addItem( d->timeBarFontItem, QStringLiteral( "TimeBarFont" ) ); } void TestDPointer::setAutoSave( bool v ) { - if (!self()->isImmutable( QStringLiteral( "AutoSave" ) )) - self()->d->autoSave = v; + if (!self()->isImmutable( QStringLiteral( "AutoSave" ) )) + self()->d->autoSave = v; } bool TestDPointer::autoSave() { return self()->d->autoSave; } KConfigSkeleton::ItemBool *TestDPointer::autoSaveItem() { return d->autoSaveItem; } void TestDPointer::setAutoSaveInterval( int v ) { - if (!self()->isImmutable( QStringLiteral( "AutoSaveInterval" ) )) - self()->d->autoSaveInterval = v; + if (!self()->isImmutable( QStringLiteral( "AutoSaveInterval" ) )) + self()->d->autoSaveInterval = v; } int TestDPointer::autoSaveInterval() { return self()->d->autoSaveInterval; } KConfigSkeleton::ItemInt *TestDPointer::autoSaveIntervalItem() { return d->autoSaveIntervalItem; } void TestDPointer::setConfirm( bool v ) { - if (!self()->isImmutable( QStringLiteral( "Confirm" ) )) - self()->d->confirm = v; + if (!self()->isImmutable( QStringLiteral( "Confirm" ) )) + self()->d->confirm = v; } bool TestDPointer::confirm() { return self()->d->confirm; } KConfigSkeleton::ItemBool *TestDPointer::confirmItem() { return d->confirmItem; } void TestDPointer::setArchiveFile( const QString & v ) { - if (!self()->isImmutable( QStringLiteral( "ArchiveFile" ) )) - self()->d->archiveFile = v; + if (!self()->isImmutable( QStringLiteral( "ArchiveFile" ) )) + self()->d->archiveFile = v; } QString TestDPointer::archiveFile() { return self()->d->archiveFile; } KConfigSkeleton::ItemString *TestDPointer::archiveFileItem() { return d->archiveFileItem; } void TestDPointer::setDestination( int v ) { - if (!self()->isImmutable( QStringLiteral( "Destination" ) )) - self()->d->destination = v; + if (!self()->isImmutable( QStringLiteral( "Destination" ) )) + self()->d->destination = v; } int TestDPointer::destination() { return self()->d->destination; } KConfigSkeleton::ItemEnum *TestDPointer::destinationItem() { return d->destinationItem; } void TestDPointer::setHourSize( int v ) { - if (!self()->isImmutable( QStringLiteral( "HourSize" ) )) - self()->d->hourSize = v; + if (!self()->isImmutable( QStringLiteral( "HourSize" ) )) + self()->d->hourSize = v; } int TestDPointer::hourSize() { return self()->d->hourSize; } KConfigSkeleton::ItemInt *TestDPointer::hourSizeItem() { return d->hourSizeItem; } void TestDPointer::setSelectionStartsEditor( bool v ) { - if (!self()->isImmutable( QStringLiteral( "SelectionStartsEditor" ) )) - self()->d->selectionStartsEditor = v; + if (!self()->isImmutable( QStringLiteral( "SelectionStartsEditor" ) )) + self()->d->selectionStartsEditor = v; } bool TestDPointer::selectionStartsEditor() { return self()->d->selectionStartsEditor; } KConfigSkeleton::ItemBool *TestDPointer::selectionStartsEditorItem() { return d->selectionStartsEditorItem; } void TestDPointer::setSelectedPlugins( const QStringList & v ) { - if (!self()->isImmutable( QStringLiteral( "SelectedPlugins" ) )) - self()->d->selectedPlugins = v; + if (!self()->isImmutable( QStringLiteral( "SelectedPlugins" ) )) + self()->d->selectedPlugins = v; } QStringList TestDPointer::selectedPlugins() { return self()->d->selectedPlugins; } KConfigSkeleton::ItemStringList *TestDPointer::selectedPluginsItem() { return d->selectedPluginsItem; } void TestDPointer::setHighlightColor( const QColor & v ) { - if (!self()->isImmutable( QStringLiteral( "HighlightColor" ) )) - self()->d->highlightColor = v; + if (!self()->isImmutable( QStringLiteral( "HighlightColor" ) )) + self()->d->highlightColor = v; } QColor TestDPointer::highlightColor() { return self()->d->highlightColor; } KConfigSkeleton::ItemColor *TestDPointer::highlightColorItem() { return d->highlightColorItem; } void TestDPointer::setAgendaBgColor( const QColor & v ) { - if (!self()->isImmutable( QStringLiteral( "AgendaBgColor" ) )) - self()->d->agendaBgColor = v; + if (!self()->isImmutable( QStringLiteral( "AgendaBgColor" ) )) + self()->d->agendaBgColor = v; } QColor TestDPointer::agendaBgColor() { return self()->d->agendaBgColor; } KConfigSkeleton::ItemColor *TestDPointer::agendaBgColorItem() { return d->agendaBgColorItem; } void TestDPointer::setTimeBarFont( const QFont & v ) { - if (!self()->isImmutable( QStringLiteral( "TimeBarFont" ) )) - self()->d->timeBarFont = v; + if (!self()->isImmutable( QStringLiteral( "TimeBarFont" ) )) + self()->d->timeBarFont = v; } QFont TestDPointer::timeBarFont() { return self()->d->timeBarFont; } KConfigSkeleton::ItemFont *TestDPointer::timeBarFontItem() { return d->timeBarFontItem; } TestDPointer::~TestDPointer() { delete d; s_globalTestDPointer()->q = nullptr; } diff --git a/autotests/kconfig_compiler/test_translation_kde.h.ref b/autotests/kconfig_compiler/test_translation_kde.h.ref index 0e50b5a..f9b582c 100644 --- a/autotests/kconfig_compiler/test_translation_kde.h.ref +++ b/autotests/kconfig_compiler/test_translation_kde.h.ref @@ -1,39 +1,40 @@ // This file is generated by kconfig_compiler_kf5 from test_translation.kcfg. // All changes you do to this file will be lost. #ifndef TESTNAMESPACE_TESTTRANSLATIONKDE_H #define TESTNAMESPACE_TESTTRANSLATIONKDE_H #include #include #include #include namespace TestNameSpace { class TestTranslationKde : public KConfigSkeleton { public: TestTranslationKde( ); ~TestTranslationKde(); + /** Get Enable automatic saving of calendar */ bool autoSave() const { return mAutoSave; } protected: // General bool mAutoSave; private: }; } #endif diff --git a/autotests/kconfig_compiler/test_translation_kde_domain.h.ref b/autotests/kconfig_compiler/test_translation_kde_domain.h.ref index 4ed5d9b..2fa42c7 100644 --- a/autotests/kconfig_compiler/test_translation_kde_domain.h.ref +++ b/autotests/kconfig_compiler/test_translation_kde_domain.h.ref @@ -1,39 +1,40 @@ // This file is generated by kconfig_compiler_kf5 from test_translation.kcfg. // All changes you do to this file will be lost. #ifndef TESTNAMESPACE_TESTTRANSLATIONKDEDOMAIN_H #define TESTNAMESPACE_TESTTRANSLATIONKDEDOMAIN_H #include #include #include #include namespace TestNameSpace { class TestTranslationKdeDomain : public KConfigSkeleton { public: TestTranslationKdeDomain( ); ~TestTranslationKdeDomain(); + /** Get Enable automatic saving of calendar */ bool autoSave() const { return mAutoSave; } protected: // General bool mAutoSave; private: }; } #endif diff --git a/autotests/kconfig_compiler/test_translation_qt.h.ref b/autotests/kconfig_compiler/test_translation_qt.h.ref index 2fe3274..9831468 100644 --- a/autotests/kconfig_compiler/test_translation_qt.h.ref +++ b/autotests/kconfig_compiler/test_translation_qt.h.ref @@ -1,39 +1,40 @@ // This file is generated by kconfig_compiler_kf5 from test_translation.kcfg. // All changes you do to this file will be lost. #ifndef TESTNAMESPACE_TESTTRANSLATIONQT_H #define TESTNAMESPACE_TESTTRANSLATIONQT_H #include #include #include #include namespace TestNameSpace { class TestTranslationQt : public KConfigSkeleton { public: TestTranslationQt( ); ~TestTranslationQt(); + /** Get Enable automatic saving of calendar */ bool autoSave() const { return mAutoSave; } protected: // General bool mAutoSave; private: }; } #endif diff --git a/autotests/kconfigtest.h b/autotests/kconfigtest.h index 9963d47..26d8e7f 100644 --- a/autotests/kconfigtest.h +++ b/autotests/kconfigtest.h @@ -1,94 +1,93 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - #ifndef KCONFIGTEST_H #define KCONFIGTEST_H #include class KConfigTest : public QObject { Q_OBJECT public: enum Testing { Ones = 1, Tens = 10, Hundreds = 100}; Q_ENUM(Testing) enum bits { bit0 = 1, bit1 = 2, bit2 = 4, bit3 = 8 }; Q_DECLARE_FLAGS(Flags, bits) Q_FLAG(Flags) private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void testSimple(); void testDefaults(); void testLists(); void testLocale(); void testEncoding(); void testPath(); void testPathQtHome(); void testPersistenceOfExpandFlagForPath(); void testComplex(); void testEnums(); void testEntryMap(); void testInvalid(); void testDeleteEntry(); void testDelete(); void testDeleteWhenLocalized(); void testDefaultGroup(); void testEmptyGroup(); void testCascadingWithLocale(); void testMerge(); void testImmutable(); void testGroupEscape(); void testRevertAllEntries(); void testChangeGroup(); void testGroupCopyTo(); void testConfigCopyTo(); void testConfigCopyToSync(); void testReparent(); void testAnonymousConfig(); void testQByteArrayUtf8(); void testQStringUtf8_data(); void testQStringUtf8(); void testSubGroup(); void testAddConfigSources(); void testWriteOnSync(); void testFailOnReadOnlyFileSync(); void testDirtyOnEqual(); void testDirtyOnEqualOverdo(); void testCreateDir(); void testSharedConfig(); void testOptionOrder(); void testLocaleConfig(); void testDirtyAfterRevert(); void testKdeGlobals(); void testNewlines(); void testXdgListEntry(); void testNotify(); void testThreads(); // should be last void testSyncOnExit(); }; Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigTest::Flags) #endif /* KCONFIGTEST_H */ diff --git a/src/kconfig_compiler/CMakeLists.txt b/src/kconfig_compiler/CMakeLists.txt index 3543dfa..dc0a08d 100644 --- a/src/kconfig_compiler/CMakeLists.txt +++ b/src/kconfig_compiler/CMakeLists.txt @@ -1,30 +1,23 @@ -set(kconfig_compiler_SRCS - KConfigXTParameters.cpp - KConfigCodeGeneratorBase.cpp - KConfigHeaderGenerator.cpp - KConfigSourceGenerator.cpp - KCFGXmlParser.cpp - kconfig_compiler.cpp -) +set(kconfig_compiler_SRCS kconfig_compiler.cpp) add_executable(kconfig_compiler ${kconfig_compiler_SRCS}) set_target_properties(kconfig_compiler PROPERTIES OUTPUT_NAME "kconfig_compiler_kf5" ) if(CMAKE_TOOLCHAIN_FILE) if(BUILD_TESTING) message(WARNING "Testing should be disabled on cross-compilation") endif() else() add_executable(KF5::kconfig_compiler ALIAS kconfig_compiler) endif() target_link_libraries(kconfig_compiler Qt5::Xml) ecm_mark_nongui_executable(kconfig_compiler) install(TARGETS kconfig_compiler EXPORT KF5ConfigCompilerTargets DESTINATION ${KDE_INSTALL_LIBEXECDIR_KF5}) diff --git a/src/kconfig_compiler/KCFGXmlParser.cpp b/src/kconfig_compiler/KCFGXmlParser.cpp deleted file mode 100644 index 214335c..0000000 --- a/src/kconfig_compiler/KCFGXmlParser.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "KCFGXmlParser.h" -#include "KConfigXTParameters.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace -{ -QTextStream cout(stdout); -QTextStream cerr(stderr); -} - -//TODO: Move preprocessDefault to Header / CPP implementation. -// it makes no sense for a parser to process those values and generate code. - -static void preProcessDefault(QString &defaultValue, const QString &name, - const QString &type, - const CfgEntry::Choices &choices, - QString &code, const KConfigXTParameters &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 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::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 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; - } -} - -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; -} - -void KCFGXmlParser::readParameterFromEntry(CfgEntry &readEntry, const QDomElement &e) -{ - readEntry.param = e.attribute(QStringLiteral("name")); - readEntry.paramType = e.attribute(QStringLiteral("type")); - - if (readEntry.param.isEmpty()) { - cerr << "Parameter must have a name: " << dumpNode(e) << endl; - exit (1); - } - - if (readEntry.paramType.isEmpty()) { - cerr << "Parameter must have a type: " << dumpNode(e) << endl; - exit(1); - } - - if ((readEntry.paramType == QLatin1String("Int")) || (readEntry.paramType == QLatin1String("UInt"))) { - bool ok; - readEntry.paramMax = e.attribute(QStringLiteral("max")).toInt(&ok); - if (!ok) { - cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl; - exit(1); - } - } else if (readEntry.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")) { - readEntry.paramValues.append(e3.text()); - } - } - break; - } - } - if (readEntry.paramValues.isEmpty()) { - cerr << "No values specified for parameter '" << readEntry.param << "'." << endl; - exit(1); - } - readEntry.paramMax = readEntry.paramValues.count() - 1; - } else { - cerr << "Parameter '" << readEntry.param << "' has type " << readEntry.paramType - << " but must be of type int, uint or Enum." << endl; - exit(1); - } -} - -bool KCFGXmlParser::hasDefaultCode(CfgEntry &readEntry, const QDomElement &element) -{ - for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { - if (e.attribute(QStringLiteral("param")).isEmpty()) { - if (e.attribute(QStringLiteral("code")) == QLatin1String("true")) { - return true; - } - } - } - return false; -} - - -void KCFGXmlParser::readChoicesFromEntry(CfgEntry &readEntry, const QDomElement &e) -{ - QList chlist; - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() != QLatin1String("choice")) { - continue; - } - CfgEntry::Choice choice; - choice.name = e2.attribute(QStringLiteral("name")); - if (choice.name.isEmpty()) { - cerr << "Tag 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); - } - - QString name = e.attribute(QStringLiteral("name")); - QString prefix = e.attribute(QStringLiteral("prefix")); - - readEntry.choices = CfgEntry::Choices(chlist, name, prefix); -} - -void KCFGXmlParser::readGroupElements(CfgEntry &readEntry, const QDomElement &element) -{ - for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { - QString tag = e.tagName(); - if (tag == QLatin1String("label")) { - readEntry.label = e.text(); - readEntry.labelContext = e.attribute(QStringLiteral("context")); - } else if (tag == QLatin1String("tooltip")) { - readEntry.toolTip = e.text(); - readEntry.toolTipContext = e.attribute(QStringLiteral("context")); - } else if (tag == QLatin1String("whatsthis")) { - readEntry.whatsThis = e.text(); - readEntry.whatsThisContext = e.attribute(QStringLiteral("context")); - } else if (tag == QLatin1String("min")) { - readEntry.min = e.text(); - } else if (tag == QLatin1String("max")) { - readEntry.max = e.text(); - } else if (tag == QLatin1String("code")) { - readEntry.code = e.text(); - } else if (tag == QLatin1String("parameter")) { - readParameterFromEntry(readEntry, e); - } else if (tag == QLatin1String("default")) { - if (e.attribute(QStringLiteral("param")).isEmpty()) { - readEntry.defaultValue = e.text(); - } - } else if (tag == QLatin1String("choices")) { - readChoicesFromEntry(readEntry, e); - } else if (tag == QLatin1String("emit")) { - Signal signal; - signal.name = e.attribute(QStringLiteral("signal")); - readEntry.signalList.append(signal); - } - } -} - -void KCFGXmlParser::createChangedSignal(CfgEntry &readEntry) -{ - if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.contains(readEntry.name))) { - Signal s; - s.name = changeSignalName(readEntry.name); - s.modify = true; - readEntry.signalList.append(s); - } -} - -void KCFGXmlParser::validateNameAndKey(CfgEntry &readEntry, const QDomElement &element) -{ - bool nameIsEmpty = readEntry.name.isEmpty(); - if (nameIsEmpty && readEntry.key.isEmpty()) { - cerr << "Entry must have a name or a key: " << dumpNode(element) << endl; - exit (1); - } - - if (readEntry.key.isEmpty()) { - readEntry.key = readEntry.name; - } - - if (nameIsEmpty) { - readEntry.name = readEntry.key; - readEntry.name.remove(QLatin1Char(' ')); - } else if (readEntry.name.contains(QLatin1Char(' '))) { - cout << "Entry '" << readEntry.name << "' contains spaces! elements can not contain spaces!" << endl; - readEntry.name.remove(QLatin1Char(' ')); - } - - if (readEntry.name.contains(QStringLiteral("$("))) { - if (readEntry.param.isEmpty()) { - cerr << "Name may not be parameterized: " << readEntry.name << endl; - exit (1); - } - } else { - if (!readEntry.param.isEmpty()) { - cerr << "Name must contain '$(" << readEntry.param << ")': " << readEntry.name << endl; - exit (1); - } - } -} - -void KCFGXmlParser::readParamDefaultValues(CfgEntry &readEntry, const QDomElement &element) -{ - if (readEntry.param.isEmpty()) { - return; - } - // Adjust name - readEntry.paramName = readEntry.name; - - readEntry.name.remove(QStringLiteral("$(") + readEntry.param + QLatin1Char(')')); - // Lookup defaults for indexed entries - for (int i = 0; i <= readEntry.paramMax; i++) { - readEntry.paramDefaultValues.append(QString()); - } - - for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { - QString tag = e.tagName(); - if (tag != QLatin1String("default")) { - continue; - } - QString index = e.attribute(QStringLiteral("param")); - if (index.isEmpty()) { - continue; - } - - bool ok; - int i = index.toInt(&ok); - if (!ok) { - i = readEntry.paramValues.indexOf(index); - if (i == -1) { - cerr << "Index '" << index << "' for default value is unknown." << endl; - exit (1); - } - } - - if ((i < 0) || (i > readEntry.paramMax)) { - cerr << "Index '" << i << "' for default value is out of range [0, " << readEntry.paramMax << "]." << endl; - exit (1); - } - - QString tmpDefaultValue = e.text(); - - if (e.attribute(QStringLiteral("code")) != QLatin1String("true")) { - preProcessDefault(tmpDefaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg); - } - - readEntry.paramDefaultValues[i] = tmpDefaultValue; - } -} - -CfgEntry *KCFGXmlParser::parseEntry(const QString &group, const QDomElement &element) -{ - CfgEntry readEntry; - readEntry.type = element.attribute(QStringLiteral("type")); - readEntry.name = element.attribute(QStringLiteral("name")); - readEntry.key = element.attribute(QStringLiteral("key")); - readEntry.hidden = element.attribute(QStringLiteral("hidden")) == QLatin1String("true");; - readEntry.group = group; - - const bool nameIsEmpty = readEntry.name.isEmpty(); - - readGroupElements(readEntry, element); - - createChangedSignal(readEntry); - validateNameAndKey(readEntry, element); - - if (readEntry.label.isEmpty()) { - readEntry.label = readEntry.key; - } - - if (readEntry.type.isEmpty()) { - readEntry.type = QStringLiteral("String"); // XXX : implicit type might be bad - } - - readParamDefaultValues(readEntry, element); - - if (!mValidNameRegexp.match(readEntry.name).hasMatch()) { - if (nameIsEmpty) - cerr << "The key '" << readEntry.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 '" << readEntry.name << "' is not a valid name for an entry." << endl; - } - exit (1); - } - - if (mAllNames.contains(readEntry.name)) { - if (nameIsEmpty) - cerr << "The key '" << readEntry.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 '" << readEntry.name << "' is not unique." << endl; - } - exit (1); - } - - mAllNames.append(readEntry.name); - - if (!hasDefaultCode(readEntry, element)) { - // TODO: Move all the options to CfgEntry. - preProcessDefault(readEntry.defaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg); - } - - // TODO: Try to Just return the CfgEntry we populated instead of - // creating another one to fill the code. - CfgEntry *result = new CfgEntry(); - result->group = readEntry.group; - result->type = readEntry.type; - result->key = readEntry.key; - result->name = readEntry.name; - result->labelContext = readEntry.labelContext; - result->label = readEntry.label; - result->toolTipContext = readEntry.toolTipContext; - result->toolTip = readEntry.toolTip; - result->whatsThisContext = readEntry.whatsThisContext; - result->whatsThis = readEntry.whatsThis; - result->code = readEntry.code; - result->defaultValue = readEntry.defaultValue; - result->choices = readEntry.choices; - result->signalList = readEntry.signalList; - result->hidden = readEntry.hidden; - - if (!readEntry.param.isEmpty()) { - result->param = readEntry.param; - result->paramName = readEntry.paramName; - result->paramType = readEntry.paramType; - result->paramValues = readEntry.paramValues; - result->paramDefaultValues = readEntry.paramDefaultValues; - result->paramMax = readEntry.paramMax; - } - result->min = readEntry.min; - result->max = readEntry.max; - - return result; -} - -// TODO: Change the name of the config variable. -KCFGXmlParser::KCFGXmlParser(const KConfigXTParameters &cfg, const QString& inputFileName) - : cfg(cfg), mInputFileName(inputFileName) -{ - mValidNameRegexp.setPattern(QRegularExpression::anchoredPattern(QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*"))); -} - -void KCFGXmlParser::start() -{ - QFile input(mInputFileName); - 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 " << mInputFileName << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl; - exit (1); - } - - QDomElement cfgElement = doc.documentElement(); - if (cfgElement.isNull()) { - cerr << "No document in kcfg file" << endl; - exit (1); - } - - for (QDomElement element = cfgElement.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) { - QString tag = element.tagName(); - - if (tag == QLatin1String("include")) { - readIncludeTag(element); - } else if (tag == QLatin1String("kcfgfile")) { - readKcfgfileTag(element); - } else if (tag == QLatin1String("group")) { - readGroupTag(element); - } else if (tag == QLatin1String("signal")) { - readSignalTag(element); - } - } -} - -ParseResult KCFGXmlParser::getParseResult() const -{ - return mParseResult; -} - -void KCFGXmlParser::readIncludeTag(const QDomElement &e) -{ - QString includeFile = e.text(); - if (!includeFile.isEmpty()) { - mParseResult.includes.append(includeFile); - } -} - -void KCFGXmlParser::readGroupTag(const QDomElement &e) -{ - QString group = e.attribute(QStringLiteral("name")); - if (group.isEmpty()) { - cerr << "Group without name" << endl; - exit (1); - } - - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() != QLatin1String("entry")) { - continue; - } - CfgEntry *entry = parseEntry(group, e2); - if (entry) { - mParseResult.entries.append(entry); - } else { - cerr << "Can not parse entry." << endl; - exit (1); - } - } -} - -void KCFGXmlParser::readKcfgfileTag(const QDomElement &e) -{ - mParseResult.cfgFileName = e.attribute(QStringLiteral("name")); - mParseResult.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"); - } - mParseResult.parameters.append(p); - } - } -} - -void KCFGXmlParser::readSignalTag(const QDomElement &e) -{ - QString signalName = e.attribute(QStringLiteral("name")); - if (signalName.isEmpty()) { - cerr << "Signal without name." << endl; - exit (1); - } - Signal theSignal; - theSignal.name = signalName; - - for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { - if (e2.tagName() == QLatin1String("argument")) { - Param argument; - argument.type = e2.attribute(QStringLiteral("type")); - if (argument.type.isEmpty()) { - cerr << "Signal argument without type." << endl; - exit (1); - } - argument.name= e2.text(); - theSignal.arguments.append(argument); - } else if (e2.tagName() == QLatin1String("label")) { - theSignal.label = e2.text(); - } - } - - mParseResult.signalList.append(theSignal); -} diff --git a/src/kconfig_compiler/KCFGXmlParser.h b/src/kconfig_compiler/KCFGXmlParser.h deleted file mode 100644 index 8c85d87..0000000 --- a/src/kconfig_compiler/KCFGXmlParser.h +++ /dev/null @@ -1,82 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KCFGXMLPARSER_H -#define KCFGXMLPARSER_H - -#include -#include -#include - -#include "KConfigCommonStructs.h" -#include "KConfigXTParameters.h" - -/* This parses the contents of a Xml file into a ParseResult Structure, - * It also fails hard: - * If start() succeeds, you can use the result, - * if start() fails, the program aborts with an error message so there's - * no possibility of generating incorrect code information. - */ -class KCFGXmlParser { -public: - KCFGXmlParser(const KConfigXTParameters &cfg, const QString& inputFileName); - - // Start the parser and reads the contents of the inputFileName into the ParseResult Structure - void start(); - - // Get the result of the parse - ParseResult getParseResult() const; - -private: - // creates a `somethingChanged` signal for every property - void createChangedSignal(CfgEntry &readEntry); - - void validateNameAndKey(CfgEntry &readEntry, const QDomElement &element); - - // TODO: Use std::optional and CfgEntry (without heap allocation) for this function - // *or* fail hard if the parse fails. - CfgEntry *parseEntry(const QString &group, const QDomElement &element); - - // Steps - void readIncludeTag(const QDomElement &element); - void readGroupTag(const QDomElement &element); - void readKcfgfileTag(const QDomElement &element); - void readSignalTag(const QDomElement &element); - - // Those are the Entries in the Xml, that represent a parameter within the tag. - void readParameterFromEntry(CfgEntry &entry, const QDomElement &element); - bool hasDefaultCode(CfgEntry &entry, const QDomElement &element); - void readChoicesFromEntry(CfgEntry &entry, const QDomElement &element); - void readGroupElements(CfgEntry &entry, const QDomElement &element); - void readParamDefaultValues(CfgEntry &entry, const QDomElement &element); - -private: - ParseResult mParseResult; - KConfigXTParameters cfg; - QString mInputFileName; - QStringList mAllNames; - QRegularExpression mValidNameRegexp; -}; - -#endif diff --git a/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp b/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp deleted file mode 100644 index 024af19..0000000 --- a/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "KConfigCodeGeneratorBase.h" -#include "KConfigXTParameters.h" -#include "KConfigCommonStructs.h" - -#include -#include -#include - -#include -#include - -using std::endl; - -namespace -{ -QTextStream cout(stdout); -QTextStream cerr(stderr); -} - -KConfigCodeGeneratorBase::KConfigCodeGeneratorBase( - const QString& inputFile, - const QString& baseDir, - const QString& fileName, - const KConfigXTParameters ¶meters, - ParseResult &parseResult) - : inputFile(inputFile), baseDir(baseDir), fileName(fileName), cfg(parameters), parseResult(parseResult) -{ - file.setFileName(fileName); - if (!file.open(QIODevice::WriteOnly)) { - cerr << "Can not open '" << fileName << "for writing." << endl; - exit(1); - } - stream.setDevice(&file); - stream.setCodec("utf-8"); - - if (cfg.staticAccessors) { - This = QStringLiteral("self()->"); - } else { - Const = QStringLiteral(" const"); - } -} - -KConfigCodeGeneratorBase::~KConfigCodeGeneratorBase() -{ - save(); -} - -void KConfigCodeGeneratorBase::save() -{ - file.close(); -} - -void KConfigCodeGeneratorBase::indent() -{ - if (indentLevel >= 4) { - indentLevel += 2; - } else { - indentLevel += 4; - } -} - -void KConfigCodeGeneratorBase::unindent() -{ - if (indentLevel > 4) { - indentLevel -= 2; - } else { - indentLevel -= 4; - } -} - -QString KConfigCodeGeneratorBase::whitespace() -{ - QString spaces; - for (int i = 0; i < indentLevel; i++) { - spaces.append(QLatin1Char(' ')); - } - return spaces; -} - -void KConfigCodeGeneratorBase::startScope() -{ - stream << whitespace() << QLatin1Char('{'); - stream << endl; - indent(); -} - -void KConfigCodeGeneratorBase::endScope(ScopeFinalizer finalizer) -{ - unindent(); - stream << whitespace() << QLatin1Char('}'); - if (finalizer == ScopeFinalizer::Semicolon) { - stream << ';'; - } - stream << endl; -} - -void KConfigCodeGeneratorBase::start() -{ - const QString fileName = QFileInfo(inputFile).fileName(); - stream << "// This file is generated by kconfig_compiler_kf5 from " << fileName << ".kcfg" << "." << endl; - stream << "// All changes you do to this file will be lost." << endl; -} - -void KConfigCodeGeneratorBase::addHeaders(const QStringList& headerList) -{ - for (auto include : qAsConst(headerList)) { - if (include.startsWith(QLatin1Char('"'))) { - stream << "#include " << include << endl; - } else { - stream << "#include <" << include << ">" << endl; - } - } -} - -// adds as many 'namespace foo {' lines to p_out as -// there are namespaces in p_ns -void KConfigCodeGeneratorBase::beginNamespaces() -{ - if (!cfg.nameSpace.isEmpty()) { - for (const QString &ns : cfg.nameSpace.split(QStringLiteral("::"))) { - stream << "namespace " << ns << " {" << endl; - } - stream << endl; - } -} - -// adds as many '}' lines to p_out as -// there are namespaces in p_ns -void KConfigCodeGeneratorBase::endNamespaces() -{ - if (!cfg.nameSpace.isEmpty()) { - stream << endl; - const int namespaceCount = cfg.nameSpace.count(QStringLiteral("::")) + 1; - for (int i = 0; i < namespaceCount; ++i) { - stream << "}" << endl; - } - } -} - -// returns the member accesor implementation -// which should go in the h file if inline -// or the cpp file if not inline -QString KConfigCodeGeneratorBase::memberAccessorBody(const CfgEntry *e, bool globalEnums) const -{ - 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; -} - -void KConfigCodeGeneratorBase::createIfSetLogic(const CfgEntry *e, const QString &varExpression) -{ - const QString n = e->name; - const QString t = e->type; - const bool hasBody = !e->signalList.empty() || cfg.generateProperties; - - stream << whitespace() << "if ("; - if (hasBody) { - stream << "v != " << varExpression << " && "; - } - stream << "!" << This << "isImmutable( QStringLiteral( \""; - if (!e->param.isEmpty()) { - QString paramName = e->paramName; - - stream << paramName.replace(QStringLiteral("$(") + e->param + QStringLiteral(")"), QLatin1String("%1")) << "\" ).arg( "; - if (e->paramType == QLatin1String("Enum")) { - stream << "QLatin1String( "; - - if (cfg.globalEnums) { - stream << enumName(e->param) << "ToString[i]"; - } else { - stream << enumName(e->param) << "::enumToString[i]"; - } - - stream << " )"; - } else { - stream << "i"; - } - stream << " )"; - } else { - stream << n << "\" )"; - } - stream << " ))"; -} - -void KConfigCodeGeneratorBase::memberMutatorBody(const CfgEntry *e) -{ - QString n = e->name; - QString t = e->type; - - // HACK: Don't open '{' manually, use startScope / endScope to automatically handle whitespace indentation. - if (!e->min.isEmpty()) { - if (e->min != QLatin1String("0") || !isUnsigned(t)) { // skip writing "if uint<0" (#187579) - stream << whitespace() << "if (v < " << e->min << ")" << endl; - stream << whitespace() << "{" << endl; - stream << whitespace(); addDebugMethod(stream, cfg, n); - stream << ": value \" << v << \" is less than the minimum value of " << e->min << "\";" << endl; - stream << whitespace() << " v = " << e->min << ";" << endl; - stream << whitespace() << "}" << endl; - } - } - - if (!e->max.isEmpty()) { - stream << endl; - stream << whitespace() << "if (v > " << e->max << ")" << endl; - stream << whitespace() << "{" << endl; - stream << whitespace(); addDebugMethod(stream, cfg, n); - stream << ": value \" << v << \" is greater than the maximum value of " << e->max << "\";" << endl; - stream << whitespace() << " v = " << e->max << ";" << endl; - stream << whitespace() << "}" << endl << endl; - } - - const QString varExpression = This + varPath(n, cfg) + (e->param.isEmpty() ? QString() : QStringLiteral("[i]")); - - // TODO: Remove this `hasBody` logic, always use an '{' for the if. - const bool hasBody = !e->signalList.empty() || cfg.generateProperties; - - // This call creates an `if (someTest ...) that's just to long to throw over the code. - createIfSetLogic(e, varExpression); - stream << (hasBody ? " {" : "") << endl; - stream << whitespace() << " " << varExpression << " = v;" << endl; - - const auto listSignal = e->signalList; - for (const Signal &signal : qAsConst(listSignal)) { - if (signal.modify) { - stream << whitespace() << " Q_EMIT " << This << signal.name << "();" << endl; - } else { - stream << whitespace() << " " << This << varPath(QStringLiteral("settingsChanged"), cfg) - << " |= " << signalEnumName(signal.name) << ";" << endl; - } - } - if (hasBody) { - stream << whitespace() << "}" << endl; - } -} diff --git a/src/kconfig_compiler/KConfigCodeGeneratorBase.h b/src/kconfig_compiler/KConfigCodeGeneratorBase.h deleted file mode 100644 index fdf3b7e..0000000 --- a/src/kconfig_compiler/KConfigCodeGeneratorBase.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - This file is part of KDE. - - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KCONFIGCODEGENERATORBASE_H -#define KCONFIGCODEGENERATORBASE_H - -#include -#include -#include -#include - -#include "KConfigXTParameters.h" - -class CfgEntry; -struct ParseResult; - -/* This class manages the base of writing a C - Based code */ -class KConfigCodeGeneratorBase { -public: - enum ScopeFinalizer {None, Semicolon}; - - KConfigCodeGeneratorBase( - const QString& inputFileName, // The kcfg file - const QString& baseDir, // where we should store the generated file - const QString& fileName, // the name of the generated file - const KConfigXTParameters ¶meters, // parameters passed to the generator - ParseResult &parseResult // The pre processed configuration entries - ); - virtual ~KConfigCodeGeneratorBase(); - - // iterates over the header list adding an #include directive. - void addHeaders(const QStringList& header); - - // Create all the namespace indentation levels based on the parsed result and parameters */ - void beginNamespaces(); - - // Closes all the namespaces adding lines with single '}' - void endNamespaces(); - - // Add the correct amount of whitespace in the code. - QString whitespace(); - - // start a block scope `{` and increase indentation level. - void endScope(ScopeFinalizer finalizer = None); - - // end a block scope `}` and decrease indentation level. - void startScope(); - - // start writing to the output file - virtual void start(); - - // save the result on the disk - void save(); - - // Code Implementations - // Implements the `Get` methods for the CfgEntry - // TODO: write to the stream directly without returning a QString. - QString memberAccessorBody(const CfgEntry *e, bool globalEnums) const; - - // Implements the `Set` methods for the CfgEntry - void memberMutatorBody(const CfgEntry *e); - - // This is the code that creates the logic for the Setter / Mutator. - // It *just* creates the if test, no body. The reason is that just - // the if test was more than 20 lines of code and hard to understand - // what was happening in a bigger function. - void createIfSetLogic(const CfgEntry *e, const QString &varExpression); - -protected: - /* advance the number of spaces for the indentation level */ - void indent(); - - /* reduce the number of spaces for the indentation level */ - void unindent(); - - QString inputFile; // the base file name, input file is based on this. - - QString baseDir; // Where we are going to save the file - QString fileName; // The file name - - const KConfigXTParameters &cfg; // The parameters passed via the kcfgc file - ParseResult &parseResult; // the result of the parsed kcfg file - QTextStream stream; // the stream that operates in the file to write data. - QFile file; // The file handler. - - // Special access to `this->` and `const` thru the code. - QString This; - QString Const; - -private: - int indentLevel = 0; -}; - -#endif diff --git a/src/kconfig_compiler/KConfigCommonStructs.h b/src/kconfig_compiler/KConfigCommonStructs.h deleted file mode 100644 index c78c7b7..0000000 --- a/src/kconfig_compiler/KConfigCommonStructs.h +++ /dev/null @@ -1,195 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KCONFIGCOMMONSTRUCTS_H -#define KCONFIGCOMMONSTRUCTS_H - -#include -#include -#include - -#include "KConfigXTParameters.h" - -struct Param -{ - QString name; - QString type; -}; - -struct Signal -{ - QString name; - QString label; - QList arguments; - bool modify = false; -}; - -class CfgEntry -{ -public: - struct Choice { - QString name; - QString context; - QString label; - QString toolTip; - QString whatsThis; - }; - class Choices - { - public: - Choices() {} - Choices(const QList &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 choices; - const QString &name() const - { - return mName; - } - const QString &externalQualifier() const - { - return mExternalQual; - } - bool external() const - { - return !mExternalQual.isEmpty(); - } - private: - QString mName; - QString mExternalQual; - }; - -public: - QString group; - QString type; - QString key; - QString name; - QString labelContext; - QString label; - QString toolTipContext; - QString toolTip; - QString whatsThisContext; - QString whatsThis; - QString code; - QString defaultValue; - QString param; - QString paramName; - QString paramType; - Choices choices; - QList signalList; - QStringList paramValues; - QStringList paramDefaultValues; - int paramMax; - bool hidden; - QString min; - QString max; -}; - -struct ParseResult { - QString cfgFileName; - bool cfgFileNameArg = false; - QList parameters; - QList signalList; - QStringList includes; - QList entries; - bool hasNonModifySignals = false; -}; - -// TODO: Move those methods -QString enumName(const QString &n); -QString enumName(const QString &n, const CfgEntry::Choices &c); -QString param(const QString &t); -QString cppType(const QString &t); -QString itemType(const QString &type); -QString changeSignalName(const QString &n); - -QString enumType(const CfgEntry *e, bool globalEnums); - -QString getDefaultFunction(const QString &n, const QString &className = QString()); -QString setFunction(const QString &n, const QString &className = QString()); -QString getFunction(const QString &n, const QString &className = QString()); - -QString itemAccessorBody(const CfgEntry *e, const KConfigXTParameters &cfg); -QString signalEnumName(const QString &signalName); - -bool isUnsigned(const QString &type); - -// returns the name of an member variable -// use itemPath to know the full path -// like using d-> in case of dpointer -QString varName(const QString &n, const KConfigXTParameters &cfg); - -QString varPath(const QString &n, const KConfigXTParameters &cfg); - -// returns the name of an item variable -// use itemPath to know the full path -// like using d-> in case of dpointer -QString itemVar(const CfgEntry *e, const KConfigXTParameters &cfg); - -QString itemPath(const CfgEntry *e, const KConfigXTParameters &cfg); - -QString filenameOnly(const QString &path); - -QString itemDeclaration(const CfgEntry *e, const KConfigXTParameters &cfg); - -QString translatedString( - const KConfigXTParameters &cfg, - const QString &string, - const QString &context = QString(), - const QString ¶m = QString(), - const QString ¶mValue = QString()); - -// TODO: Sanitize those functions. -QString newItem( - const CfgEntry* entry, - const QString &key, - const QString& defaultValue, - const KConfigXTParameters &cfg, - const QString ¶m = QString()); - -QString userTextsFunctions( - const CfgEntry *e, - const KConfigXTParameters &cfg, - QString itemVarStr = QString(), - const QString &i = QString()); - -QString paramString(const QString &s, const CfgEntry *e, int i); -QString paramString(const QString &group, const QList ¶meters); - -QString defaultValue(const QString &t); -QString memberGetDefaultBody(const CfgEntry *e); -QString literalString(const QString &s); -QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c); - -void addQuotes(QString &s); -void addDebugMethod(QTextStream &out, const KConfigXTParameters &cfg, const QString &n); - -#endif diff --git a/src/kconfig_compiler/KConfigHeaderGenerator.cpp b/src/kconfig_compiler/KConfigHeaderGenerator.cpp deleted file mode 100644 index 088f64e..0000000 --- a/src/kconfig_compiler/KConfigHeaderGenerator.cpp +++ /dev/null @@ -1,612 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "KConfigHeaderGenerator.h" -#include "KConfigCommonStructs.h" - -#include -#include - -namespace -{ -QTextStream cout(stdout); -QTextStream cerr(stderr); -} - -KConfigHeaderGenerator::KConfigHeaderGenerator( - const QString& inputFile, - const QString& baseDir, - const KConfigXTParameters &cfg, - ParseResult &parseResult) - : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.headerExtension, cfg, parseResult) -{ -} - -void KConfigHeaderGenerator::start() -{ - KConfigCodeGeneratorBase::start(); - startHeaderGuards(); - createHeaders(); - - beginNamespaces(); - - createForwardDeclarations(); - - doClassDefinition(); - - endNamespaces(); - endHeaderGuards(); -} - -void KConfigHeaderGenerator::doClassDefinition() -{ - stream << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl; - startScope(); - - // Add Q_OBJECT macro if the config need signals. - if (!parseResult.signalList.isEmpty() || cfg.generateProperties) { - stream << " Q_OBJECT" << endl; - } - stream << " public:" << endl; - implementEnums(); - createConstructor(); - createDestructor(); - - for (auto *entry : qAsConst(parseResult.entries)) { - const QString n = entry->name; - const QString t = entry->type; - - const QString returnType = (cfg.useEnumTypes && t == QLatin1String("Enum")) - ? enumType(entry, cfg.globalEnums) - : cppType(t); - - createSetters(entry); - createProperties(entry, returnType); - createGetters(entry, returnType); - createDefaultValueMember(entry); - createItemAcessors(entry, returnType); - } - - createSignals(); - stream << " protected:" << endl; - createSingleton(); - - // TODO: Move those to functions too. - if (parseResult.hasNonModifySignals) { - stream << whitespace() << "bool usrSave() override;" << endl; - } - - // Member variables - if (!cfg.memberVariables.isEmpty() && cfg.memberVariables != QLatin1String("private") && cfg.memberVariables != QLatin1String("dpointer")) { - stream << " " << cfg.memberVariables << ":" << endl; - } - - // Class Parameters - for (const auto ¶meter : qAsConst(parseResult.parameters)) { - stream << whitespace() << "" << cppType(parameter.type) << " mParam" << parameter.name << ";" << endl; - } - - createNonDPointerHelpers(); - createDPointer(); - - if (cfg.customAddons) { - stream << whitespace() << "// Include custom additions" << endl; - stream << whitespace() << "#include \"" << cfg.baseName << "_addons." << cfg.headerExtension << '"' << endl; - } - - endScope(ScopeFinalizer::Semicolon); -} - -void KConfigHeaderGenerator::createHeaders() -{ - addHeaders(cfg.headerIncludes); - if (cfg.headerIncludes.size()) { - stream << endl; - } - - if (!cfg.singleton && parseResult.parameters.isEmpty()) { - addHeaders({QStringLiteral("qglobal.h")}); - } - - if (cfg.inherits == QLatin1String("KCoreConfigSkeleton")) { - addHeaders({QStringLiteral("kcoreconfigskeleton.h")}); - } else { - addHeaders({QStringLiteral("kconfigskeleton.h")}); - } - - addHeaders({QStringLiteral("QCoreApplication"), QStringLiteral("QDebug")}); - stream << endl; - - addHeaders(parseResult.includes); - if (parseResult.includes.size()) { - stream << endl; - } -} - -void KConfigHeaderGenerator::startHeaderGuards() -{ - const bool hasNamespace = !cfg.nameSpace.isEmpty(); - const QString namespaceName = QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_"))).toUpper(); - const QString namespaceStr = hasNamespace ? namespaceName + QLatin1Char('_') : QStringLiteral(""); - const QString defineName = namespaceStr + cfg.className.toUpper() + QStringLiteral("_H"); - - stream << "#ifndef " << defineName << endl; - stream << "#define " << defineName << endl; - stream << endl; -} - -void KConfigHeaderGenerator::endHeaderGuards() -{ - stream << endl; - stream << "#endif"; - stream << endl; - // HACK: Original files ended with two last newlines, add them. - stream << endl; -} - -void KConfigHeaderGenerator::implementChoiceEnums(const CfgEntry *entry, const CfgEntry::Choices &choices) -{ - const QList chlist = choices.choices; - - if (chlist.isEmpty()) { - return; - } - - QStringList values; - for (const auto choice : qAsConst(chlist)) { - values.append(choices.prefix + choice.name); - } - - if (choices.name().isEmpty()) { - if (cfg.globalEnums) { - stream << whitespace() << "enum " << enumName(entry->name, entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; - } else { - // Create an automatically named enum - stream << whitespace() << "class " << enumName(entry->name, entry->choices) << endl; - stream << whitespace() << "{" << endl; - stream << whitespace() << " public:" << endl; - stream << whitespace() << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl; - stream << whitespace() << "};" << endl; - } - } else if (!choices.external()) { - // Create a named enum - stream << whitespace() << "enum " << enumName(entry->name, entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; - } -} - -void KConfigHeaderGenerator::implementValueEnums(const CfgEntry *entry, const QStringList &values) -{ - if (values.isEmpty()) { - return; - } - - if (cfg.globalEnums) { - // ### FIXME!! - // make the following string table an index-based string search! - // ### - stream << whitespace() << "enum " << enumName(entry->param) << " { " << values.join(QStringLiteral(", ")) << " };" << endl; - stream << whitespace() << "static const char* const " << enumName(entry->param) << "ToString[];" << endl; - } else { - stream << whitespace() << "class " << enumName(entry->param) << endl; - stream << whitespace() << "{" << endl; - stream << whitespace() << " public:" << endl; - stream << whitespace() << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl; - stream << whitespace() << " static const char* const enumToString[];" << endl; - stream << whitespace() << "};" << endl; - } -} - -void KConfigHeaderGenerator::implementEnums() -{ - if (!parseResult.entries.size()) { - return; - } - - for (const auto entry : qAsConst(parseResult.entries)) { - const CfgEntry::Choices &choices = entry->choices; - const QStringList values = entry->paramValues; - - implementChoiceEnums(entry, choices); - implementValueEnums(entry, values); - } - stream << endl; -} - -void KConfigHeaderGenerator::createSignals() -{ - // Signal definition. - const bool hasSignals = !parseResult.signalList.isEmpty(); - - unsigned val = 1 << parseResult.signalList.size(); - if (!val) { - cerr << "Too many signals to create unique bit masks" << endl; - exit(1); - } - - if (!hasSignals) { - return; - } - - stream << "\n enum {" << endl; - val = 1; - - // HACK: Use C-Style for add a comma in all but the last element, - // just to make the source generated code equal to the old one. - // When we are sure, revert this to a range-based-for and just add - // a last comma, as it's valid c++. - for (int i = 0, end = parseResult.signalList.size(); i < end; i++) { - auto signal = parseResult.signalList.at(i); - stream << whitespace() << " " << signalEnumName(signal.name) << " = 0x" << hex << val; - if (i != end-1) { - stream << "," << endl; - } - - val <<= 1; - } - stream << endl; - stream << whitespace() << "};" << dec << endl << endl; - - stream << " Q_SIGNALS:"; - for (const Signal &signal : qAsConst(parseResult.signalList)) { - stream << endl; - if (!signal.label.isEmpty()) { - stream << whitespace() << "/**" << endl; - stream << whitespace() << " " << signal.label << endl; - stream << whitespace() << "*/" << endl; - } - stream << whitespace() << "void " << signal.name << "("; - QList::ConstIterator it, itEnd = signal.arguments.constEnd(); - for (it = signal.arguments.constBegin(); it != itEnd;) { - Param argument = *it; - QString type = param(argument.type); - if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) { - for (auto *entry : qAsConst(parseResult.entries)) { - if (entry->name == argument.name) { - type = enumType(entry, cfg.globalEnums); - break; - } - } - } - stream << type << " " << argument.name; - if (++it != itEnd) { - stream << ", "; - } - } - stream << ");" << endl; - } - stream << endl; - - stream << " private:" << endl; - stream << whitespace() << "void itemChanged(quint64 flags);" << endl; - stream << endl; -} - -void KConfigHeaderGenerator::createDPointer() -{ - if (!cfg.dpointer) { - return; - } - - // use a private class for both member variables and items - stream << " private:" << endl; - for (const auto &entry : qAsConst(parseResult.entries)) { - if (cfg.allDefaultGetters || cfg.defaultGetters.contains(entry->name)) { - stream << whitespace() << ""; - if (cfg.staticAccessors) { - stream << "static "; - } - stream << cppType(entry->type) << " " << getDefaultFunction(entry->name) << "_helper("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")" << Const << ";" << endl; - } - } - stream << whitespace() << "" << cfg.className << "Private *d;" << endl; -} - -void KConfigHeaderGenerator::createConstructor() -{ - if (cfg.singleton) { - stream << whitespace() << "static " << cfg.className << " *self();" << endl; - if (parseResult.cfgFileNameArg) { - stream << whitespace() << "static void instance(const QString& cfgfilename);" << endl; - stream << whitespace() << "static void instance(KSharedConfig::Ptr config);" << endl; - } - return; - } - - stream << whitespace() << "" << cfg.className << "("; - if (parseResult.cfgFileNameArg) { - if (cfg.forceStringFilename) - stream << " const QString &cfgfilename" << (parseResult.parameters.isEmpty() ? " = QString()" : ", "); - else - stream << " KSharedConfig::Ptr config" << (parseResult.parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", "); - } - - bool first = true; - for (const auto parameter : qAsConst(parseResult.parameters)) { - if (first) { - first = false; - } else { - stream << ","; - } - - stream << " " << param(parameter.type) << " " << parameter.name; - } - - if (cfg.parentInConstructor) { - if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) { - stream << ","; - } - stream << " QObject *parent = nullptr"; - } - stream << " );" << endl; -} - -void KConfigHeaderGenerator::createDestructor() -{ - stream << whitespace() << "~" << cfg.className << "();" << endl << endl; -} - -void KConfigHeaderGenerator::createForwardDeclarations() -{ - // Private class declaration - if (cfg.dpointer) { - stream << "class " << cfg.className << "Private;" << endl << endl; - } -} - -void KConfigHeaderGenerator::createProperties(const CfgEntry *entry, const QString& returnType) -{ - if (!cfg.generateProperties) { - return; - } - stream << whitespace() << "Q_PROPERTY(" << returnType << ' ' << getFunction(entry->name); - stream << " READ " << getFunction(entry->name); - - if (cfg.allMutators || cfg.mutators.contains(entry->name)) { - const QString signal = changeSignalName(entry->name); - stream << " WRITE " << setFunction(entry->name); - stream << " 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; - parseResult.signalList.append(s); - } else { - stream << " CONSTANT"; - } - stream << ")" << endl; -} - -void KConfigHeaderGenerator::createSetters(const CfgEntry *entry) -{ - // Manipulator - if (!cfg.allMutators && !cfg.mutators.contains(entry->name)) { - return; - } - - stream << whitespace() << "/**" << endl; - stream << whitespace() << " Set " << entry->label << endl; - stream << whitespace() << "*/" << endl; - - if (cfg.staticAccessors) { - stream << whitespace() << "static" << endl; - } - - stream << whitespace() << "void " << setFunction(entry->name) << "( "; - if (!entry->param.isEmpty()) { - stream <paramType) << " i, "; - } - - stream << (cfg.useEnumTypes && entry->type == QLatin1String("Enum") - ? enumType(entry, cfg.globalEnums) - : param(entry->type)); - - stream << " v )"; - - // function body inline only if not using dpointer - // for BC mode - if (!cfg.dpointer) { - stream << endl; - startScope(); - memberMutatorBody(entry); - endScope(); - stream << endl; - } else { - stream << ";" << endl << endl; - } -} - -void KConfigHeaderGenerator::createGetters(const CfgEntry *entry, const QString& returnType) -{ - // Accessor - stream << whitespace() << "/**" << endl; - stream << whitespace() << " Get " << entry->label << endl; - stream << whitespace() << "*/" << endl; - if (cfg.staticAccessors) { - stream << whitespace() << "static" << endl; - } - stream << whitespace() << ""; - stream << returnType; - stream << " " << getFunction(entry->name) << "("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")" << Const; - - // function body inline only if not using dpointer - // for BC mode - if (!cfg.dpointer) { - stream << endl; - startScope(); - stream << whitespace() << memberAccessorBody(entry, cfg.globalEnums); - endScope(); - stream << endl; - } else { - stream << ";" << endl << endl; - } -} - -void KConfigHeaderGenerator::createItemAcessors(const CfgEntry *entry, const QString& returnType) -{ - // Item accessor - if (!cfg.itemAccessors) { - return; - } - stream << whitespace() << "/**" << endl; - stream << whitespace() << " Get Item object corresponding to " << entry->name << "()" - << endl; - stream << whitespace() << "*/" << endl; - stream << whitespace() << "Item" << itemType(entry->type) << " *" - << getFunction(entry->name) << "Item("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")"; - if (!cfg.dpointer) { - stream << endl; - startScope(); - stream << whitespace() << itemAccessorBody(entry, cfg); - endScope(); - } else { - stream << ";" << endl; - } - - stream <name)) && !entry->defaultValue.isEmpty())) { - return; - } - stream << whitespace() << "/**" << endl; - stream << whitespace() << " Get " << entry->label << " default value" << endl; - stream << whitespace() << "*/" << endl; - if (cfg.staticAccessors) { - stream << whitespace() << "static" << endl; - } - stream << whitespace() << ""; - if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) { - stream << enumType(entry, cfg.globalEnums); - } else { - stream << cppType(entry->type); - } - stream << " " << getDefaultFunction(entry->name) << "("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")" << Const << endl; - stream << whitespace() << "{" << endl; - stream << whitespace() << " return "; - if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) { - stream << "static_cast<" << enumType(entry, cfg.globalEnums) << ">("; - } - stream << getDefaultFunction(entry->name) << "_helper("; - if (!entry->param.isEmpty()) { - stream << " i "; - } - stream << ")"; - if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) { - stream << ")"; - } - stream << ";" << endl; - stream << whitespace() << "}" << endl; - stream << endl; -} - -void KConfigHeaderGenerator::createSingleton() -{ - // Private constructor for singleton - if (!cfg.singleton) { - return; - } - - stream << whitespace() << "" << cfg.className << "("; - if (parseResult.cfgFileNameArg) { - stream << "KSharedConfig::Ptr config"; - } - if (cfg.parentInConstructor) { - if (parseResult.cfgFileNameArg) { - stream << ", "; - } - stream << "QObject *parent = nullptr"; - } - stream << ");" << endl; - stream << whitespace() << "friend class " << cfg.className << "Helper;" << endl << endl; -} - -void KConfigHeaderGenerator::createNonDPointerHelpers() -{ - if (cfg.memberVariables == QLatin1String("dpointer")) { - return; - } - - QString group; - for (auto *entry : qAsConst(parseResult.entries)) { - if (entry->group != group) { - group = entry->group; - stream << endl; - stream << whitespace() << "// " << group << endl; - } - stream << whitespace() << "" << cppType(entry->type) << " " << varName(entry->name, cfg); - if (!entry->param.isEmpty()) { - stream << QStringLiteral("[%1]").arg(entry->paramMax + 1); - } - stream << ";" << endl; - - if (cfg.allDefaultGetters || cfg.defaultGetters.contains(entry->name)) { - stream << whitespace() << ""; - if (cfg.staticAccessors) { - stream << "static "; - } - stream << cppType(entry->type) << " " << getDefaultFunction(entry->name) << "_helper("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")" << Const << ";" << endl; - } - } - - stream << endl << " private:" << endl; - if (cfg.itemAccessors) { - for (auto *entry : qAsConst(parseResult.entries)) { - stream << whitespace() << "Item" << itemType(entry->type) << " *" << itemVar(entry, cfg); - if (!entry->param.isEmpty()) { - stream << QStringLiteral("[%1]").arg(entry->paramMax + 1); - } - stream << ";" << endl; - } - } - - if (parseResult.hasNonModifySignals) { - stream << whitespace() << "uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl; - } -} diff --git a/src/kconfig_compiler/KConfigHeaderGenerator.h b/src/kconfig_compiler/KConfigHeaderGenerator.h deleted file mode 100644 index 30f09ac..0000000 --- a/src/kconfig_compiler/KConfigHeaderGenerator.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - This file is part of KDE. - - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KCONFIGHEADERGENERATOR_H -#define KCONFIGHEADERGENERATOR_H - -#include "KConfigCodeGeneratorBase.h" -#include "KConfigCommonStructs.h" - -#include -#include - -class KConfigXTParameters; -class CfgEntry; -class QTextStream; -struct ParseResult; - -class KConfigHeaderGenerator : public KConfigCodeGeneratorBase { -public: - KConfigHeaderGenerator( - const QString& inputFile, - const QString& baseDir, - const KConfigXTParameters ¶meters, - ParseResult &parseResult); - - void start() override; - -private: - void startHeaderGuards(); - void endHeaderGuards(); - - void implementEnums(); - void implementChoiceEnums(const CfgEntry *entry, const CfgEntry::Choices &choices); - void implementValueEnums(const CfgEntry *entry, const QStringList &values); - - void doClassDefinition(); - void createHeaders(); - void createDPointer(); - void createNonDPointerHelpers(); - - void createConstructor(); - void createDestructor(); - void createForwardDeclarations(); - void createSingleton(); - void createSignals(); - - void createSetters(const CfgEntry *entry); - void createItemAcessors(const CfgEntry *entry, const QString& returnType); - void createGetters(const CfgEntry *entry, const QString& returnType); - void createProperties(const CfgEntry *entry, const QString& returnType); - void createDefaultValueMember(const CfgEntry *entry); -}; - -#endif diff --git a/src/kconfig_compiler/KConfigSourceGenerator.cpp b/src/kconfig_compiler/KConfigSourceGenerator.cpp deleted file mode 100644 index 1949b42..0000000 --- a/src/kconfig_compiler/KConfigSourceGenerator.cpp +++ /dev/null @@ -1,657 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "KConfigSourceGenerator.h" -#include "KConfigCommonStructs.h" - - -KConfigSourceGenerator::KConfigSourceGenerator( - const QString& inputFile, - const QString& baseDir, - const KConfigXTParameters &cfg, - ParseResult &parseResult) - : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.sourceExtension, cfg, parseResult) -{ -} - -void KConfigSourceGenerator::start() -{ - KConfigCodeGeneratorBase::start(); - stream << endl; - createHeaders(); - - if (!cfg.nameSpace.isEmpty()) { - stream << "using namespace " << cfg.nameSpace << ";"; - stream << endl << endl; - } - - createPrivateDPointerImplementation(); - createSingletonImplementation(); - createPreamble(); - doConstructor(); - doGetterSetterDPointerMode(); - createDefaultValueGetterSetter(); - createDestructor(); - createNonModifyingSignalsHelper(); - createSignalFlagsHandler(); - includeMoc(); -} - -void KConfigSourceGenerator::createHeaders() -{ - QString headerName = cfg.baseName + QLatin1Char('.') + cfg.headerExtension; - - // TODO: Make addQuotes return a string instead of replacing it inplace. - addQuotes(headerName); - - addHeaders({ headerName }); - stream << endl; - - addHeaders(cfg.sourceIncludes); - if (cfg.setUserTexts && cfg.translationSystem == KConfigXTParameters::KdeTranslation) { - addHeaders({QStringLiteral("klocalizedstring.h")}); - stream << endl; - } - - // Header required by singleton implementation - if (cfg.singleton) { - addHeaders({QStringLiteral("qglobal.h"), QStringLiteral("QFile")}); - - // HACK: Add single line to fix test. - if (cfg.singleton && parseResult.cfgFileNameArg) { - stream << endl; - } - } - - if (cfg.singleton && parseResult.cfgFileNameArg) { - addHeaders({QStringLiteral("QDebug")}); - } - - if (cfg.singleton) { - stream << endl; - } -} - -void KConfigSourceGenerator::createPrivateDPointerImplementation() -{ - // private class implementation - if (!cfg.dpointer) { - return; - } - - QString group; - beginNamespaces(); - stream << "class " << cfg.className << "Private" << endl; - stream << "{" << endl; - stream << " public:" << endl; - - // Create Members - for (auto *entry : qAsConst(parseResult.entries)) { - if (entry->group != group) { - group = entry->group; - stream << endl; - stream << " // " << group << endl; - } - stream << " " << cppType(entry->type) << " " << varName(entry->name, cfg); - if (!entry->param.isEmpty()) { - stream << QStringLiteral("[%1]").arg(entry->paramMax + 1); - } - stream << ";" << endl; - } - stream << endl << " // items" << endl; - - // Create Items. - for (auto *entry : qAsConst(parseResult.entries)) { - const QString declType = entry->signalList.isEmpty() - ? QString(cfg.inherits + QStringLiteral("::Item") + itemType(entry->type)) - : QStringLiteral("KConfigCompilerSignallingItem"); - - stream << " " << declType << " *" << itemVar( entry, cfg ); - if (!entry->param.isEmpty()) { - stream << QStringLiteral("[%1]").arg(entry->paramMax + 1); - } - stream << ";" << endl; - } - - if (parseResult.hasNonModifySignals) { - stream << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl; - } - - stream << "};" << endl << endl; - endNamespaces(); -} - -void KConfigSourceGenerator::createSingletonImplementation() -{ - // Singleton implementation - if (!cfg.singleton) { - return; - } - - beginNamespaces(); - stream << "class " << cfg.className << "Helper" << endl; - stream << '{' << endl; - stream << " public:" << endl; - stream << " " << cfg.className << "Helper() : q(nullptr) {}" << endl; - stream << " ~" << cfg.className << "Helper() { delete q; }" << endl; - stream << " " << cfg.className << "Helper(const " << cfg.className << "Helper&) = delete;" << endl; - stream << " " << cfg.className << "Helper& operator=(const " << cfg.className << "Helper&) = delete;" << endl; - stream << " " << cfg.className << " *q;" << endl; - stream << "};" << endl; - endNamespaces(); - - stream << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl; - - stream << cfg.className << " *" << cfg.className << "::self()" << endl; - stream << "{" << endl; - if (parseResult.cfgFileNameArg) { - stream << " if (!s_global" << cfg.className << "()->q)" << endl; - stream << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl; - } else { - stream << " if (!s_global" << cfg.className << "()->q) {" << endl; - stream << " new " << cfg.className << ';' << endl; - stream << " s_global" << cfg.className << "()->q->read();" << endl; - stream << " }" << endl << endl; - } - stream << " return s_global" << cfg.className << "()->q;" << endl; - stream << "}" << endl << endl; - - if (parseResult.cfgFileNameArg) { - auto instance = [this] (const QString &type, const QString &arg, bool isString) { - stream << "void " << cfg.className << "::instance(" << type << " " << arg << ")" << endl; - stream << "{" << endl; - stream << " if (s_global" << cfg.className << "()->q) {" << endl; - stream << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl; - stream << " return;" << endl; - stream << " }" << endl; - stream << " new " << cfg.className << "("; - if (isString) { - stream << "KSharedConfig::openConfig(" << arg << ")"; - } else { - stream << "std::move(" << arg << ")"; - } - stream << ");" << endl; - stream << " s_global" << cfg.className << "()->q->read();" << endl; - stream << "}" << endl << endl; - }; - instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true); - instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false); - } -} - -void KConfigSourceGenerator::createPreamble() -{ - QString cppPreamble; - for (const auto entry : qAsConst(parseResult.entries)) { - if (entry->paramValues.isEmpty()) { - continue; - } - - cppPreamble += QStringLiteral("const char* const ") + cfg.className + QStringLiteral("::") + enumName(entry->param); - cppPreamble += cfg.globalEnums - ? QStringLiteral("ToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n") - : QStringLiteral("::enumToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n"); - } - - if (!cppPreamble.isEmpty()) { - stream << cppPreamble << endl; - } -} - -void KConfigSourceGenerator::createConstructorParameterList() -{ - if (parseResult.cfgFileNameArg) { - if (!cfg.forceStringFilename) { - stream << " KSharedConfig::Ptr config"; - } else { - stream << " const QString& config"; - } - stream << (parseResult.parameters.isEmpty() ? "" : ","); - } - - for (QList::ConstIterator it = parseResult.parameters.constBegin(); - it != parseResult.parameters.constEnd(); ++it) { - if (it != parseResult.parameters.constBegin()) { - stream << ","; - } - stream << " " << param((*it).type) << " " << (*it).name; - } - - if (cfg.parentInConstructor) { - if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) { - stream << ","; - } - stream << " QObject *parent"; - } - -} - -void KConfigSourceGenerator::createParentConstructorCall() -{ - stream << cfg.inherits << "("; - if (!parseResult.cfgFileName.isEmpty()) { - stream << " QStringLiteral( \"" << parseResult.cfgFileName << "\" "; - } - if (parseResult.cfgFileNameArg) { - if (! cfg.forceStringFilename) { - stream << " std::move( config ) "; - } else { - stream << " config "; - } - } - if (!parseResult.cfgFileName.isEmpty()) { - stream << ") "; - } - stream << ")" << endl; -} - -void KConfigSourceGenerator::createInitializerList() -{ - for (const auto ¶meter : qAsConst(parseResult.parameters)) { - stream << " , mParam" << parameter.name << "(" << parameter.name << ")" << endl; - } - - if (parseResult.hasNonModifySignals && !cfg.dpointer) { - stream << " , " << varName(QStringLiteral("settingsChanged"), cfg) << "(0)" << endl; - } -} - -void KConfigSourceGenerator::createEnums(const CfgEntry *entry) -{ - if (entry->type != QLatin1String("Enum")) { - return; - } - stream << " QList<" << cfg.inherits << "::ItemEnum::Choice> values" << entry->name << ";" << endl; - - for (const auto &choice : qAsConst(entry->choices.choices)) { - stream << " {" << endl; - stream << " " << cfg.inherits << "::ItemEnum::Choice choice;" << endl; - stream << " choice.name = QStringLiteral(\"" << choice.name << "\");" << endl; - if (cfg.setUserTexts) { - if (!choice.label.isEmpty()) { - stream << " choice.label = " - << translatedString(cfg, choice.label, choice.context) - << ";" << endl; - } - if (!choice.toolTip.isEmpty()) { - stream << " choice.toolTip = " - << translatedString(cfg, choice.toolTip, choice.context) - << ";" << endl; - } - if (!choice.whatsThis.isEmpty()) { - stream << " choice.whatsThis = " - << translatedString(cfg, choice.whatsThis, choice.context) - << ";" << endl; - } - } - stream << " values" << entry->name << ".append( choice );" << endl; - stream << " }" << endl; - } -} - -void KConfigSourceGenerator::createNormalEntry(const CfgEntry *entry, const QString& key) -{ - stream << " " << itemPath(entry, cfg) << " = " - << newItem(entry, key, entry->defaultValue, cfg) << endl; - - if (!entry->min.isEmpty()) { - stream << " " << itemPath(entry, cfg) << "->setMinValue(" << entry->min << ");" << endl; - } - if (!entry->max.isEmpty()) { - stream << " " << itemPath(entry, cfg) << "->setMaxValue(" << entry->max << ");" << endl; - } - - if (cfg.setUserTexts) { - stream << userTextsFunctions(entry, cfg); - } - - if (cfg.allNotifiers || cfg.notifiers.contains(entry->name)) { - stream << " " << itemPath(entry, cfg) << "->setWriteFlags(KConfigBase::Notify);" << endl; - } - - stream << " addItem( " << itemPath(entry, cfg); - QString quotedName = entry->name; - addQuotes(quotedName); - if (quotedName != key) { - stream << ", QStringLiteral( \"" << entry->name << "\" )"; - } - stream << " );" << endl; -} - -void KConfigSourceGenerator::createIndexedEntry(const CfgEntry *entry, const QString& key) -{ - for (int i = 0; i <= entry->paramMax; i++) { - QString itemVarStr(itemPath(entry, cfg) + QStringLiteral("[%1]").arg(i)); - - QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i] - : !entry->defaultValue.isEmpty() ? paramString(entry->defaultValue, entry, i) - : defaultValue(entry->type); - - stream << " " << itemVarStr << " = " - << newItem(entry, paramString(key, entry, i), defaultStr, cfg, QStringLiteral("[%1]").arg(i)) << endl; - - if (cfg.setUserTexts) { - stream << userTextsFunctions(entry, cfg, itemVarStr, entry->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!. - const bool isEnum = entry->paramType == QLatin1String("Enum"); - const QString arg = isEnum ? entry->paramValues[i] : QString::number(i); - - QString paramName = entry->paramName; - - stream << " addItem( " << itemVarStr << ", QStringLiteral( \""; - stream << paramName.replace(QStringLiteral("$(") + entry->param + QLatin1Char(')'), QLatin1String("%1")).arg( arg ); - stream << "\" ) );" << endl; - } -} - -void KConfigSourceGenerator::handleCurrentGroupChange(const CfgEntry *entry) -{ - if (entry->group == mCurrentGroup) { - return; - } - - // HACK: This fixes one spacing line in the diff. Remove this in the future and adapt the testcases. - static bool first = true; - if (!entry->group.isEmpty()) { - if (!first) { - stream << endl; - } - first = false; - } - - mCurrentGroup = entry->group; - stream << " setCurrentGroup( " << paramString(mCurrentGroup, parseResult.parameters) << " );"; - stream << endl << endl; -} - -void KConfigSourceGenerator::doConstructor() -{ - // Constructor - stream << cfg.className << "::" << cfg.className << "("; - createConstructorParameterList(); - stream << " )" << endl; - stream << " : "; - createParentConstructorCall(); - createInitializerList(); - - stream << "{" << endl; - - if (cfg.parentInConstructor) { - stream << " setParent(parent);" << endl; - } - - if (cfg.dpointer) { - stream << " d = new " << cfg.className << "Private;" << endl; - if (parseResult.hasNonModifySignals) { - stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; - } - } - - // Needed in case the singleton class is used as baseclass for - // another singleton. - if (cfg.singleton) { - stream << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl; - stream << " s_global" << cfg.className << "()->q = this;" << endl; - } - - if (!parseResult.signalList.isEmpty()) { - // 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/ - stream << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction =" - << " static_cast(&" - << cfg.className << "::itemChanged);" << endl; - - stream << endl; - } - - for (auto *entry : qAsConst(parseResult.entries)) { - handleCurrentGroupChange(entry); - - const QString key = paramString(entry->key, parseResult.parameters); - if (!entry->code.isEmpty()) { - stream << entry->code << endl; - } - createEnums(entry); - - if (!cfg.dpointer) { - stream << itemDeclaration(entry, cfg); - } - - if (entry->param.isEmpty()) { - createNormalEntry(entry, key); - } else { - createIndexedEntry(entry, key); - } - } - - stream << "}" << endl << endl; -} - -void KConfigSourceGenerator::createGetterDPointerMode(const CfgEntry *entry) -{ - // Accessor - if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) { - stream << enumType(entry, cfg.globalEnums); - } else { - stream << cppType(entry->type); - } - - stream << " " << getFunction(entry->name, cfg.className) << "("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")" << Const << endl; - - // function body inline only if not using dpointer - // for BC mode - startScope(); - // HACK: Fix memberAccessorBody - stream << " " << memberAccessorBody(entry, cfg.globalEnums); - endScope(); - stream << endl; -} - -void KConfigSourceGenerator::createSetterDPointerMode(const CfgEntry *entry) -{ - // Manipulator - if (!(cfg.allMutators || cfg.mutators.contains(entry->name))) { - return; - } - - stream << "void " << setFunction(entry->name, cfg.className) << "( "; - if (!entry->param.isEmpty()) { - stream << cppType(entry->paramType) << " i, "; - } - - if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) { - stream << enumType(entry, cfg.globalEnums); - } else { - stream << param(entry->type); - } - stream << " v )" << endl; - - // function body inline only if not using dpointer - // for BC mode - startScope(); - memberMutatorBody(entry); - endScope(); - stream << endl; -} - -void KConfigSourceGenerator::createItemGetterDPointerMode(const CfgEntry *entry) -{ - // Item accessor - if (!cfg.itemAccessors) { - return; - } - stream << endl; - stream << cfg.inherits << "::Item" << itemType(entry->type) << " *" - << getFunction(entry->name, cfg.className) << "Item("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")" << endl; - startScope(); - stream << " " << itemAccessorBody(entry, cfg); - endScope(); -} - -void KConfigSourceGenerator::doGetterSetterDPointerMode() -{ - if (!cfg.dpointer) { - return; - } - - // setters and getters go in Cpp if in dpointer mode - for (auto *entry : qAsConst(parseResult.entries)) { - createSetterDPointerMode(entry); - createGetterDPointerMode(entry); - createItemGetterDPointerMode(entry); - stream << endl; - } -} - -void KConfigSourceGenerator::createDefaultValueGetterSetter() -{ - // default value getters always go in Cpp - for (auto *entry : qAsConst(parseResult.entries)) { - QString n = entry->name; - QString t = entry->type; - - // Default value Accessor, as "helper" function - if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !entry->defaultValue.isEmpty()) { - stream << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper("; - if (!entry->param.isEmpty()) { - stream << " " << cppType(entry->paramType) << " i "; - } - stream << ")" << Const << endl; - startScope(); - stream << memberGetDefaultBody(entry) << endl; - endScope(); - stream << endl; - } - } -} - -void KConfigSourceGenerator::createDestructor() -{ - stream << cfg.className << "::~" << cfg.className << "()" << endl; - startScope(); - if (cfg.dpointer) { - stream << " delete d;" << endl; - } - if (cfg.singleton) { - stream << " s_global" << cfg.className << "()->q = nullptr;" << endl; - } - endScope(); - stream << endl; -} - -void KConfigSourceGenerator::createNonModifyingSignalsHelper() -{ - if (!parseResult.hasNonModifySignals) { - return; - } - stream << "bool " << cfg.className << "::" << "usrSave()" << endl; - startScope(); - stream << " const bool res = " << cfg.inherits << "::usrSave();" << endl; - stream << " if (!res) return false;" << endl << endl; - for (const Signal &signal : qAsConst(parseResult.signalList)) { - if (signal.modify) { - continue; - } - - stream << " if ( " << varPath(QStringLiteral("settingsChanged"), cfg) << " & " << signalEnumName(signal.name) << " )" << endl; - stream << " Q_EMIT " << signal.name << "("; - QList::ConstIterator it, itEnd = signal.arguments.constEnd(); - for (it = signal.arguments.constBegin(); it != itEnd;) { - Param argument = *it; - bool cast = false; - if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) { - for (int i = 0, end = parseResult.entries.count(); i < end; ++i) { - if (parseResult.entries.at(i)->name == argument.name) { - stream << "static_cast<" << enumType(parseResult.entries.at(i), cfg.globalEnums) << ">("; - cast = true; - break; - } - } - } - stream << varPath(argument.name, cfg); - if (cast) { - stream << ")"; - } - if (++it != itEnd) { - stream << ", "; - } - } - - stream << ");" << endl; - } - - stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl; - stream << " return true;" << endl; - endScope(); -} - -void KConfigSourceGenerator::createSignalFlagsHandler() -{ - if (parseResult.signalList.isEmpty()) { - return; - } - - stream << endl; - stream << "void " << cfg.className << "::" << "itemChanged(quint64 flags) {" << endl; - if (parseResult.hasNonModifySignals) - stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " |= flags;" << endl; - - if (!parseResult.signalList.isEmpty()) - stream << endl; - - for (const Signal &signal : qAsConst(parseResult.signalList)) { - if (signal.modify) { - stream << " if ( flags & " << signalEnumName(signal.name) << " ) {" << endl; - stream << " Q_EMIT " << signal.name << "();" << endl; - stream << " }" << endl; - } - } - - stream << "}" << endl; -} - -void KConfigSourceGenerator::includeMoc() { - const QString mocFileName = cfg.baseName + QStringLiteral(".moc"); - - if (parseResult.signalList.count() || cfg.generateProperties) { - // Add includemoc if they are signals defined. - stream << endl; - stream << "#include \"" << mocFileName << "\"" << endl; - stream << endl; - } -} diff --git a/src/kconfig_compiler/KConfigSourceGenerator.h b/src/kconfig_compiler/KConfigSourceGenerator.h deleted file mode 100644 index 7740932..0000000 --- a/src/kconfig_compiler/KConfigSourceGenerator.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - This file is part of KDE. - - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KCONFIGSOURCEGENERATOR_H -#define KCONFIGSOURCEGENERATOR_H - -#include "KConfigCodeGeneratorBase.h" -#include "KConfigCommonStructs.h" - -#include -#include - -class KConfigXTParameters; -class CfgEntry; -class QTextStream; -struct ParseResult; - -class KConfigSourceGenerator : public KConfigCodeGeneratorBase { -public: - KConfigSourceGenerator( - const QString& inputFile, - const QString& baseDir, - const KConfigXTParameters ¶meters, - ParseResult &parseResult); - - void start() override; - -private: - // Those are fairly self contained functions. - void createHeaders(); - void createPrivateDPointerImplementation(); - void createSingletonImplementation(); - void createPreamble(); - void createDestructor(); - void createConstructorParameterList(); - void createParentConstructorCall(); - void createInitializerList(); - void createDefaultValueGetterSetter(); - void createNonModifyingSignalsHelper(); - void createSignalFlagsHandler(); - void includeMoc(); - - // Constructor related methods - // the `do` methods have related helper functions that are only related - // to it. So we can break the function into many smaller ones and create - // logic inside of the `do` function. - void doConstructor(); - void createEnums(const CfgEntry *entry); - void createNormalEntry(const CfgEntry *entry, const QString& key); - void createIndexedEntry(const CfgEntry *entry, const QString& key); - void handleCurrentGroupChange(const CfgEntry *entry); - - void doGetterSetterDPointerMode(); - void createGetterDPointerMode(const CfgEntry *entry); - void createSetterDPointerMode(const CfgEntry *entry); - void createItemGetterDPointerMode(const CfgEntry *entry); - -private: - QString mCurrentGroup; -}; - -#endif diff --git a/src/kconfig_compiler/KConfigXTParameters.cpp b/src/kconfig_compiler/KConfigXTParameters.cpp deleted file mode 100644 index 1d488e9..0000000 --- a/src/kconfig_compiler/KConfigXTParameters.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "KConfigXTParameters.h" - -// TODO: Remove this. -#undef QT_NO_CAST_FROM_ASCII - -#include -#include - -namespace -{ -QTextStream cout(stdout); -QTextStream cerr(stderr); -} - -KConfigXTParameters::KConfigXTParameters(const QString &codegenFilename) -{ - if (!codegenFilename.endsWith(QLatin1String(".kcfgc"))) { - cerr << "Codegen options file must have extension .kcfgc" << endl; - exit(1); - } - - baseName = QFileInfo(codegenFilename).fileName(); - baseName = baseName.left(baseName.length() - 6); - - // 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 += QLatin1Char(' '); - } - 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(); -} diff --git a/src/kconfig_compiler/KConfigXTParameters.h b/src/kconfig_compiler/KConfigXTParameters.h deleted file mode 100644 index db2cbcb..0000000 --- a/src/kconfig_compiler/KConfigXTParameters.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - This file is part of KDE. - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - Copyright (c) 2003 Cornelius Schumacher - Copyright (c) 2003 Waldo Bastian - Copyright (c) 2003 Zack Rusin - Copyright (c) 2006 MichaĆ«l Larouche - Copyright (c) 2008 Allen Winter - Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KCOFIGXTPARAMETERS_H -#define KCOFIGXTPARAMETERS_H - -#include -#include -#include - -/** - Configuration Compiler Configuration -*/ -class KConfigXTParameters -{ -public: - KConfigXTParameters(const QString &codegenFilename); - -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; - QString baseName; -}; - -#endif diff --git a/src/kconfig_compiler/kconfig_compiler.cpp b/src/kconfig_compiler/kconfig_compiler.cpp index 00699c3..848595f 100644 --- a/src/kconfig_compiler/kconfig_compiler.cpp +++ b/src/kconfig_compiler/kconfig_compiler.cpp @@ -1,769 +1,2737 @@ /* This file is part of KDE. Copyright (c) 2003 Cornelius Schumacher Copyright (c) 2003 Waldo Bastian Copyright (c) 2003 Zack Rusin Copyright (c) 2006 MichaĆ«l Larouche Copyright (c) 2008 Allen Winter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Compiling this file with this flag is just crazy #undef QT_NO_CAST_FROM_ASCII #include #include #include #include #include #include #include #include -#include -#include + +#include +#include #include #include #include #include "../../kconfig_version.h" -#include "KConfigXTParameters.h" -#include "KConfigCommonStructs.h" -#include "KConfigHeaderGenerator.h" -#include "KConfigSourceGenerator.h" -#include "KCFGXmlParser.h" namespace { QTextStream cout(stdout); QTextStream cerr(stderr); } -QString varName(const QString &n, const KConfigXTParameters &cfg) +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 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 &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 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 &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 &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 &value) + { + mSignalList = value; + } + QList signalList() const + { + return mSignalList; + } + + bool hidden() const + { + return mHidden; + } + + void dump() const + { + cerr << "" << 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 << "" << 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 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 result; if (!cfg.dpointer) { result = QChar::fromLatin1('m') + n; result[1] = result[1].toUpper(); } else { result = n; result[0] = result[0].toLower(); } return result; } -QString varPath(const QString &n, const KConfigXTParameters &cfg) +static QString varPath(const QString &n, const CfgConfig &cfg) { QString result; if (cfg.dpointer) { result = "d->" + varName(n, cfg); } else { result = varName(n, cfg); } return result; } -QString enumName(const QString &n) +static QString enumName(const QString &n) { QString result = QLatin1String("Enum") + n; result[4] = result[4].toUpper(); return result; } -QString enumName(const QString &n, const CfgEntry::Choices &c) +static QString enumName(const QString &n, const CfgEntry::Choices &c) { QString result = c.name(); if (result.isEmpty()) { result = QLatin1String("Enum") + n; result[4] = result[4].toUpper(); } return result; } -QString enumType(const CfgEntry *e, bool globalEnums) +static 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"); } result[4] = result[4].toUpper(); } return result; } -QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) +static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) { QString result = c.name(); if (result.isEmpty()) { result = QLatin1String("Enum") + n + QLatin1String("::"); result[4] = result[4].toUpper(); } else if (c.external()) { result = c.externalQualifier(); } else { result.clear(); } return result; } -QString setFunction(const QString &n, const QString &className) +static QString setFunction(const QString &n, const QString &className = QString()) { QString result = QLatin1String("set") + n; result[3] = result[3].toUpper(); if (!className.isEmpty()) { result = className + QLatin1String("::") + result; } return result; } -QString changeSignalName(const QString &n) +static QString changeSignalName(const QString &n) { return n+QStringLiteral("Changed"); } -QString getDefaultFunction(const QString &n, const QString &className) +static QString getDefaultFunction(const QString &n, const QString &className = QString()) { QString result = QLatin1String("default") + n + QLatin1String("Value"); result[7] = result[7].toUpper(); if (!className.isEmpty()) { result = className + QLatin1String("::") + result; } return result; } -QString getFunction(const QString &n, const QString &className) +static QString getFunction(const QString &n, const QString &className = QString()) { QString result = n; result[0] = result[0].toLower(); if (!className.isEmpty()) { result = className + QLatin1String("::") + result; } return result; } -void addQuotes(QString &s) +static void addQuotes(QString &s) { if (!s.startsWith(QLatin1Char('"'))) { s.prepend(QLatin1Char('"')); } if (!s.endsWith(QLatin1Char('"'))) { s.append(QLatin1Char('"')); } } static QString quoteString(const QString &s) { QString r = s; r.replace(QLatin1Char('\\'), QLatin1String("\\\\")); r.replace(QLatin1Char('\"'), QLatin1String("\\\"")); r.remove(QLatin1Char('\r')); r.replace(QLatin1Char('\n'), QLatin1String("\\n\"\n\"")); return QLatin1Char('\"') + r + QLatin1Char('\"'); } -QString literalString(const QString &s) +static QString literalString(const QString &s) { bool isAscii = true; for (int i = s.length(); i--;) if (s[i].unicode() > 127) { isAscii = false; } if (isAscii) { return QLatin1String("QStringLiteral( ") + quoteString(s) + QLatin1String(" )"); } else { return QLatin1String("QString::fromUtf8( ") + quoteString(s) + QLatin1String(" )"); } } +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; +} -QString signalEnumName(const QString &signalName) +static QString signalEnumName(const QString &signalName) { QString result; result = QLatin1String("signal") + signalName; result[6] = result[6].toUpper(); 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 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::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 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 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 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 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! 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); -bool isUnsigned(const QString &type) + return result; +} + +static bool isUnsigned(const QString &type) { if (type == QLatin1String("UInt")) { return true; } if (type == QLatin1String("ULongLong")) { return true; } return false; } /** Return parameter declaration for given type. */ QString param(const QString &t) { const QString type = t.toLower(); if (type == QLatin1String("string")) { return QStringLiteral("const QString &"); } else if (type == QLatin1String("stringlist")) { return QStringLiteral("const QStringList &"); } else if (type == QLatin1String("font")) { return QStringLiteral("const QFont &"); } else if (type == QLatin1String("rect")) { return QStringLiteral("const QRect &"); } else if (type == QLatin1String("size")) { return QStringLiteral("const QSize &"); } else if (type == QLatin1String("color")) { return QStringLiteral("const QColor &"); } else if (type == QLatin1String("point")) { return QStringLiteral("const QPoint &"); } else if (type == QLatin1String("int")) { return QStringLiteral("int"); } else if (type == QLatin1String("uint")) { return QStringLiteral("uint"); } else if (type == QLatin1String("bool")) { return QStringLiteral("bool"); } else if (type == QLatin1String("double")) { return QStringLiteral("double"); } else if (type == QLatin1String("datetime")) { return QStringLiteral("const QDateTime &"); } else if (type == QLatin1String("longlong")) { return QStringLiteral("qint64"); } else if (type == QLatin1String("ulonglong")) { return QStringLiteral("quint64"); } else if (type == QLatin1String("intlist")) { return QStringLiteral("const QList &"); } else if (type == QLatin1String("enum")) { return QStringLiteral("int"); } else if (type == QLatin1String("path")) { return QStringLiteral("const QString &"); } else if (type == QLatin1String("pathlist")) { return QStringLiteral("const QStringList &"); } else if (type == QLatin1String("password")) { return QStringLiteral("const QString &"); } else if (type == QLatin1String("url")) { return QStringLiteral("const QUrl &"); } else if (type == QLatin1String("urllist")) { return QStringLiteral("const QList &"); } else { cerr << "kconfig_compiler_kf5 does not support type \"" << type << "\"" << endl; return QStringLiteral("QString"); //For now, but an assert would be better } } /** Actual C++ storage type for given type. */ QString cppType(const QString &t) { const QString type = t.toLower(); if (type == QLatin1String("string")) { return QStringLiteral("QString"); } else if (type == QLatin1String("stringlist")) { return QStringLiteral("QStringList"); } else if (type == QLatin1String("font")) { return QStringLiteral("QFont"); } else if (type == QLatin1String("rect")) { return QStringLiteral("QRect"); } else if (type == QLatin1String("size")) { return QStringLiteral("QSize"); } else if (type == QLatin1String("color")) { return QStringLiteral("QColor"); } else if (type == QLatin1String("point")) { return QStringLiteral("QPoint"); } else if (type == QLatin1String("int")) { return QStringLiteral("int"); } else if (type == QLatin1String("uint")) { return QStringLiteral("uint"); } else if (type == QLatin1String("bool")) { return QStringLiteral("bool"); } else if (type == QLatin1String("double")) { return QStringLiteral("double"); } else if (type == QLatin1String("datetime")) { return QStringLiteral("QDateTime"); } else if (type == QLatin1String("longlong")) { return QStringLiteral("qint64"); } else if (type == QLatin1String("ulonglong")) { return QStringLiteral("quint64"); } else if (type == QLatin1String("intlist")) { return QStringLiteral("QList"); } else if (type == QLatin1String("enum")) { return QStringLiteral("int"); } else if (type == QLatin1String("path")) { return QStringLiteral("QString"); } else if (type == QLatin1String("pathlist")) { return QStringLiteral("QStringList"); } else if (type == QLatin1String("password")) { return QStringLiteral("QString"); } else if (type == QLatin1String("url")) { return QStringLiteral("QUrl"); } else if (type == QLatin1String("urllist")) { return QStringLiteral("QList"); } else { cerr << "kconfig_compiler_kf5 does not support type \"" << type << "\"" << endl; return QStringLiteral("QString"); //For now, but an assert would be better } } QString defaultValue(const QString &t) { const QString type = t.toLower(); if (type == QLatin1String("string")) { return QStringLiteral("\"\""); // Use empty string, not null string! } else if (type == QLatin1String("stringlist")) { return QStringLiteral("QStringList()"); } else if (type == QLatin1String("font")) { return QStringLiteral("QFont()"); } else if (type == QLatin1String("rect")) { return QStringLiteral("QRect()"); } else if (type == QLatin1String("size")) { return QStringLiteral("QSize()"); } else if (type == QLatin1String("color")) { return QStringLiteral("QColor(128, 128, 128)"); } else if (type == QLatin1String("point")) { return QStringLiteral("QPoint()"); } else if (type == QLatin1String("int")) { return QStringLiteral("0"); } else if (type == QLatin1String("uint")) { return QStringLiteral("0"); } else if (type == QLatin1String("bool")) { return QStringLiteral("false"); } else if (type == QLatin1String("double")) { return QStringLiteral("0.0"); } else if (type == QLatin1String("datetime")) { return QStringLiteral("QDateTime()"); } else if (type == QLatin1String("longlong")) { return QStringLiteral("0"); } else if (type == QLatin1String("ulonglong")) { return QStringLiteral("0"); } else if (type == QLatin1String("intlist")) { return QStringLiteral("QList()"); } else if (type == QLatin1String("enum")) { return QStringLiteral("0"); } else if (type == QLatin1String("path")) { return QStringLiteral("\"\""); // Use empty string, not null string! } else if (type == QLatin1String("pathlist")) { return QStringLiteral("QStringList()"); } else if (type == QLatin1String("password")) { return QStringLiteral("\"\""); // Use empty string, not null string! } else if (type == QLatin1String("url")) { return QStringLiteral("QUrl()"); } else if (type == QLatin1String("urllist")) { return QStringLiteral("QList()"); } else { cerr << "Error, kconfig_compiler_kf5 does not support the \"" << type << "\" type!" << endl; return QStringLiteral("QString"); //For now, but an assert would be better } } QString itemType(const QString &type) { QString t; t = type; t.replace(0, 1, t.left(1).toUpper()); return t; } -QString itemDeclaration(const CfgEntry *e, const KConfigXTParameters &cfg) +static QString itemDeclaration(const CfgEntry *e, const CfgConfig &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 -QString itemVar(const CfgEntry *e, const KConfigXTParameters &cfg) +static QString itemVar(const CfgEntry *e, const CfgConfig &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; } -QString itemPath(const CfgEntry *e, const KConfigXTParameters &cfg) +static QString itemPath(const CfgEntry *e, const CfgConfig &cfg) { QString result; if (cfg.dpointer) { result = "d->" + itemVar(e, cfg); } else { result = itemVar(e, cfg); } return result; } QString newItem(const CfgEntry* entry, const QString &key, const QString& defaultValue, - const KConfigXTParameters &cfg, const QString ¶m) { + const CfgConfig &cfg, const QString ¶m = QString()) { - QList sigs = entry->signalList; + QList 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; } t += QLatin1String(" )"); if (!sigs.isEmpty()) { t += QLatin1String(", this, notifyFunction, "); //append the signal flags for (int i = 0; i < sigs.size(); ++i) { if (i != 0) t += QLatin1String(" | "); t += signalEnumName(sigs[i].name); } t += QLatin1String(")"); } t += QLatin1String(";"); return t; } 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); } result.replace(needle, tmp); } return result; } QString paramString(const QString &group, const QList ¶meters) { QString paramString = group; QString arguments; int i = 1; for (QList::ConstIterator it = parameters.constBegin(); it != parameters.constEnd(); ++it) { if (paramString.contains("$(" + (*it).name + ')')) { const QString tmp = QStringLiteral("%%1").arg(i++); paramString.replace("$(" + (*it).name + ')', tmp); arguments += ".arg( mParam" + (*it).name + " )"; } } if (arguments.isEmpty()) { return "QStringLiteral( \"" + group + "\" )"; } return "QStringLiteral( \"" + paramString + "\" )" + arguments; } -QString translatedString(const KConfigXTParameters &cfg, const QString &string, const QString &context, const QString ¶m, const QString ¶mValue) +QString translatedString(const CfgConfig &cfg, const QString &string, const QString &context = QString(), const QString ¶m = QString(), const QString ¶mValue = QString()) { QString result; switch (cfg.translationSystem) { - case KConfigXTParameters::QtTranslation: + case CfgConfig::QtTranslation: if (!context.isEmpty()) { result += "/*: " + context + " */ QCoreApplication::translate(\""; } else { result += QLatin1String("QCoreApplication::translate(\""); } result += cfg.className + "\", "; break; - case KConfigXTParameters::KdeTranslation: + case CfgConfig::KdeTranslation: if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) { result += "i18ndc(" + quoteString(cfg.translationDomain) + ", " + quoteString(context) + ", "; } else if (!cfg.translationDomain.isEmpty()) { result += "i18nd(" + quoteString(cfg.translationDomain) + ", "; } else if (!context.isEmpty()) { result += "i18nc(" + quoteString(context) + ", "; } else { result += QLatin1String("i18n("); } break; } if (!param.isEmpty()) { QString resolvedString = string; resolvedString.replace("$(" + param + ')', paramValue); result += quoteString(resolvedString); } else { result += quoteString(string); } result += ')'; return result; } /* int i is the value of the parameter */ -QString userTextsFunctions(const CfgEntry *e, const KConfigXTParameters &cfg, QString itemVarStr, const QString &i) +QString userTextsFunctions(CfgEntry *e, const CfgConfig &cfg, QString itemVarStr = QString(), const QString &i = QString()) { 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 -//TODO: Fix add Debug Method, it should also take the debug string. -void addDebugMethod(QTextStream &out, const KConfigXTParameters &cfg, const QString &n) + +void addDebugMethod(QTextStream &out, const CfgConfig &cfg, const QString &n) { if (cfg.qCategoryLoggingName.isEmpty()) { out << " qDebug() << \"" << setFunction(n); } else { out << " qCDebug(" << cfg.qCategoryLoggingName << ") << \"" << setFunction(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(const CfgEntry *e) +QString memberGetDefaultBody(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->paramDefaultValues[i].isEmpty()) { - out << " case " << i << ": return " << e->paramDefaultValues[i] << ';' << endl; + for (int i = 0; i <= e->paramMax(); ++i) { + if (!e->paramDefaultValue(i).isEmpty()) { + out << " case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl; } } - QString defaultValue = e->defaultValue; - out << " default:" << endl; - out << " return " << defaultValue.replace("$(" + e->param + ')', QLatin1String("i")) << ';' << endl; + out << " return " << e->defaultValue().replace("$(" + e->param() + ')', QLatin1String("i")) << ';' << endl; out << " }" << endl; } else { - out << " return " << e->defaultValue << ';'; + out << " return " << e->defaultValue() << ';'; } return result; } // returns the item accesor implementation // which should go in the h file if inline // or the cpp file if not inline -QString itemAccessorBody(const CfgEntry *e, const KConfigXTParameters &cfg) +QString itemAccessorBody(CfgEntry *e, const CfgConfig &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; return result; } //indents text adding X spaces per line QString indent(QString text, int spaces) { QString result; QTextStream out(&result, QIODevice::WriteOnly); QTextStream in(&text, QIODevice::ReadOnly); QString currLine; while (!in.atEnd()) { currLine = in.readLine(); if (!currLine.isEmpty()) for (int i = 0; i < spaces; i++) { out << " "; } out << currLine << endl; } return result; } -bool hasErrors(KCFGXmlParser &parser, const ParseResult& parseResult, const KConfigXTParameters &cfg) +// 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) { - if (cfg.className.isEmpty()) { - cerr << "Class name missing" << endl; - return true; - } - - 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 (!p_ns.isEmpty()) { + const QStringList nameSpaces = p_ns.split(QStringLiteral("::")); + for (const QString &ns : nameSpaces) { + p_out << "namespace " << ns << " {" << endl; + } + p_out << endl; } +} - if (parseResult.entries.isEmpty()) { - cerr << "No entries." << 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; } - - return false; } int main(int argc, char **argv) { QCoreApplication app(argc, argv); app.setApplicationName(QStringLiteral("kconfig_compiler")); app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING)); - QString inputFilename, codegenFilename; - - QCommandLineOption targetDirectoryOption(QStringList { QStringLiteral("d"), QStringLiteral("directory") }, - QCoreApplication::translate("main", "Directory to generate files in [.]"), - QCoreApplication::translate("main", "directory"), QStringLiteral(".")); + validNameRegexp = new QRegularExpression(QRegularExpression::anchoredPattern( + QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*"))); - QCommandLineOption licenseOption ( - QStringList { QStringLiteral("l"), QStringLiteral("license") }, - QCoreApplication::translate("main", "Display software license.")); + QString inputFilename, codegenFilename; 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(); parser.addHelpOption(); 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; cout << "under the terms of the GNU Library Public License." << endl; cout << "For more information about these matters, see the file named COPYING." << endl; return 0; } 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 if (!baseDir.endsWith('/') && !baseDir.endsWith('\\')) #else if (!baseDir.endsWith('/')) #endif baseDir.append("/"); - KConfigXTParameters cfg(codegenFilename); + 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); - 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(); + CfgConfig cfg = CfgConfig(codegenFilename); - ParseResult parseResult = xmlParser.getParseResult(); + QFile input(inputFilename); - if (hasErrors(xmlParser, parseResult, cfg)) { + 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; } - // TODO: Move this to somewhere saner. - for (const auto &signal : qAsConst(parseResult.signalList)) { - parseResult.hasNonModifySignals |= !signal.modify; + QDomElement cfgElement = doc.documentElement(); + + if (cfgElement.isNull()) { + cerr << "No document in kcfg file" << endl; + return 1; } - // remove '.kcfg' from the name. - const QString baseName = inputFilename.mid(0, inputFilename.size()-5); - KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult); - headerGenerator.start(); - headerGenerator.save(); + QString cfgFileName; + bool cfgFileNameArg = false; + QList parameters; + QList signalList; + QStringList includes; + + QList 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; + } + + 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 " << endl; + } + + if (cfg.inherits == QLatin1String("KCoreConfigSkeleton")) { + h << "#include " << endl; + } else { + h << "#include " << endl; + } + + h << "#include " << endl; + h << "#include " << 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::ConstIterator itEntry; + for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) { + const CfgEntry::Choices &choices = (*itEntry)->choices(); + const QList chlist = choices.choices; + if (!chlist.isEmpty()) { + QStringList values; + QList::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::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::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::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::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 " << endl << endl; + } + + // Header required by singleton implementation + if (cfg.singleton) { + cpp << "#include " << endl << "#include " << endl << endl; + } + if (cfg.singleton && cfgFileNameArg) { + cpp << "#include " << 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::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::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(&" + << 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 choices = (*itEntry)->choices().choices; + QList::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::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; + } - KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult); - sourceGenerator.start(); - sourceGenerator.save(); + // clear entries list + qDeleteAll(entries); - qDeleteAll(parseResult.entries); + implementation.close(); }