From d8dff3dc6554b1fe00e3f743dc41f4f747a5088b Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 12 Mar 2021 17:20:36 +0100 Subject: [PATCH] [libcalamares] Replace loadPresets() with an applicative style Build up the list of known presets by what the Config-object expects, not by what the Config file provides. This allows early detection of mis-matched configurations. Presets can only apply to Q_PROPERTY properties, and the preset must match the property name. --- src/libcalamares/modulesystem/Config.cpp | 67 +++++++++++++++--------- src/libcalamares/modulesystem/Config.h | 24 ++++++++- src/libcalamares/modulesystem/Preset.cpp | 1 + src/libcalamares/modulesystem/Preset.h | 12 ++++- src/modules/users/Config.cpp | 13 ++--- 5 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/libcalamares/modulesystem/Config.cpp b/src/libcalamares/modulesystem/Config.cpp index 701fbec74..af1536129 100644 --- a/src/libcalamares/modulesystem/Config.cpp +++ b/src/libcalamares/modulesystem/Config.cpp @@ -10,6 +10,7 @@ #include "Config.h" #include "Preset.h" +#include "utils/Logger.h" #include "utils/Variant.h" namespace Calamares @@ -33,47 +34,63 @@ Config::Config( QObject* parent ) Config::~Config() {} -void -Config::loadPresets( const QVariantMap& configurationMap ) +bool +Config::isEditable( const QString& fieldName ) const { - const QString key( "presets" ); - if ( !configurationMap.contains( key ) ) + if ( m_unlocked ) { - d->m_presets.reset(); - return; + return true; } - bool bogus = true; - d->m_presets = std::make_unique< Presets >( CalamaresUtils::getSubMap( configurationMap, key, bogus ) ); + if ( d && d->m_presets ) + { + return d->m_presets->isEditable( fieldName ); + } + else + { + cWarning() << "Checking isEditable, but no presets are configured."; + } + return true; } -void -Config::loadPresets( const QVariantMap& configurationMap, const QStringList& recognizedKeys ) +Config::ApplyPresets::ApplyPresets( Calamares::ModuleSystem::Config& c, const QVariantMap& configurationMap ) + : m_c( c ) + , m_bogus( true ) + , m_map( CalamaresUtils::getSubMap( configurationMap, "presets", m_bogus ) ) { - const QString key( "presets" ); - if ( !configurationMap.contains( key ) ) + c.m_unlocked = true; + if ( !c.d->m_presets ) { - d->m_presets.reset(); - return; + c.d->m_presets = std::make_unique< Presets >(); } - bool bogus = true; - d->m_presets - = std::make_unique< Presets >( CalamaresUtils::getSubMap( configurationMap, key, bogus ), recognizedKeys ); } -bool -Config::isEditable( const QString& fieldName ) const + +Config::ApplyPresets& +Config::ApplyPresets::apply( const char* fieldName ) { - if ( m_unlocked ) + const auto prop = m_c.property( fieldName ); + if ( !prop.isValid() ) { - return true; + cWarning() << "Applying invalid property" << fieldName; } - if ( d && d->m_presets ) + else { - return d->m_presets->isEditable( fieldName ); + const QString key( fieldName ); + if ( !key.isEmpty() && m_map.contains( key ) ) + { + QVariantMap m = CalamaresUtils::getSubMap( m_map, key, m_bogus ); + QVariant value = m[ "value" ]; + bool editable = CalamaresUtils::getBool( m, "editable", true ); + + if ( value.isValid() ) + { + m_c.setProperty( fieldName, value ); + } + m_c.d->m_presets->append( PresetField { key, value, editable } ); + } } - return true; + return *this; } - } // namespace ModuleSystem } // namespace Calamares diff --git a/src/libcalamares/modulesystem/Config.h b/src/libcalamares/modulesystem/Config.h index d0f5fa51f..c38b0c11c 100644 --- a/src/libcalamares/modulesystem/Config.h +++ b/src/libcalamares/modulesystem/Config.h @@ -58,8 +58,28 @@ public Q_SLOTS: bool isEditable( const QString& fieldName ) const; protected: - void loadPresets( const QVariantMap& configurationMap ); - void loadPresets( const QVariantMap& configurationMap, const QStringList& recognizedKeys ); + friend class ApplyPresets; + /** @brief "Builder" class for presets + * + * Derived classes should instantiate this (with themselves, + * and the whole configuration map that is passed to + * setConfigurationMap()) and then call .apply() to apply + * the presets specified in the configuration to the **named** + * QObject properties. + */ + class ApplyPresets + { + public: + ApplyPresets( Config& c, const QVariantMap& configurationMap ); + ~ApplyPresets() { m_c.m_unlocked = false; } + + ApplyPresets& apply( const char* fieldName ); + + private: + Config& m_c; + bool m_bogus = true; + const QVariantMap m_map; + }; private: class Private; diff --git a/src/libcalamares/modulesystem/Preset.cpp b/src/libcalamares/modulesystem/Preset.cpp index 9685a6b68..3a54c9e68 100644 --- a/src/libcalamares/modulesystem/Preset.cpp +++ b/src/libcalamares/modulesystem/Preset.cpp @@ -62,6 +62,7 @@ Presets::isEditable( const QString& fieldName ) const return p.editable; } } + cWarning() << "Checking isEditable for unknown field" << fieldName; return true; } diff --git a/src/libcalamares/modulesystem/Preset.h b/src/libcalamares/modulesystem/Preset.h index 59c308b92..f7b5023e5 100644 --- a/src/libcalamares/modulesystem/Preset.h +++ b/src/libcalamares/modulesystem/Preset.h @@ -36,8 +36,10 @@ namespace ModuleSystem struct PresetField { QString fieldName; - QString value; + QVariant value; bool editable = true; + + bool isValid() const { return !fieldName.isEmpty(); } }; /** @brief All the presets for one UI entity @@ -62,6 +64,14 @@ public: */ Presets( const QVariantMap& configurationMap, const QStringList& recognizedKeys ); + /** @brief Creates an empty presets map + * + * This constructor is primarily intended for use by the ApplyPresets + * helper class, which will reserve suitable space and load + * presets on-demand. + */ + Presets() = default; + /** @brief Is the given @p fieldName editable? * * Fields are editable by default, so if there is no explicit setting, diff --git a/src/modules/users/Config.cpp b/src/modules/users/Config.cpp index 0fcf745fa..047b8d516 100644 --- a/src/modules/users/Config.cpp +++ b/src/modules/users/Config.cpp @@ -183,7 +183,7 @@ Config::setSudoersGroup( const QString& group ) void Config::setLoginName( const QString& login ) { - if ( login != m_loginName ) + if ( login != m_loginName && isEditable( QStringLiteral( "loginName" ) ) ) { m_customLoginName = !login.isEmpty(); m_loginName = login; @@ -393,6 +393,11 @@ makeHostnameSuggestion( const QStringList& parts ) void Config::setFullName( const QString& name ) { + if ( !isEditable( QStringLiteral( "fullName" ) ) ) + { + return; + } + if ( name.isEmpty() && !m_fullName.isEmpty() ) { if ( !m_customHostName ) @@ -837,11 +842,7 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) updateGSAutoLogin( doAutoLogin(), loginName() ); checkReady(); - loadPresets( configurationMap, - { - "fullname", - "loginname", - } ); + ApplyPresets( *this, configurationMap ).apply( "fullName" ).apply( "loginName" ); } void