From 0f075500067eb36011aca203aee2b658a102f933 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 11 Nov 2020 13:08:42 +0100 Subject: [PATCH 01/27] [plasmalnf] Introduce (empty) Config object --- src/modules/plasmalnf/CMakeLists.txt | 1 + src/modules/plasmalnf/Config.cpp | 20 ++++++++++++++++ src/modules/plasmalnf/Config.h | 26 +++++++++++++++++++++ src/modules/plasmalnf/PlasmaLnfViewStep.cpp | 3 +++ src/modules/plasmalnf/PlasmaLnfViewStep.h | 2 ++ 5 files changed, 52 insertions(+) create mode 100644 src/modules/plasmalnf/Config.cpp create mode 100644 src/modules/plasmalnf/Config.h diff --git a/src/modules/plasmalnf/CMakeLists.txt b/src/modules/plasmalnf/CMakeLists.txt index 15c836b5b..f13f4f9c7 100644 --- a/src/modules/plasmalnf/CMakeLists.txt +++ b/src/modules/plasmalnf/CMakeLists.txt @@ -32,6 +32,7 @@ if ( KF5Plasma_FOUND AND KF5Package_FOUND ) COMPILE_DEFINITIONS ${option_defs} SOURCES + Config.cpp PlasmaLnfViewStep.cpp PlasmaLnfPage.cpp PlasmaLnfJob.cpp diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp new file mode 100644 index 000000000..6a80509f4 --- /dev/null +++ b/src/modules/plasmalnf/Config.cpp @@ -0,0 +1,20 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#include "Config.h" + +Config::Config( QObject* parent ) + : QObject( parent ) +{ +} + +void +Config::setConfigurationMap( const QVariantMap& ) +{ +} diff --git a/src/modules/plasmalnf/Config.h b/src/modules/plasmalnf/Config.h new file mode 100644 index 000000000..389e2aff4 --- /dev/null +++ b/src/modules/plasmalnf/Config.h @@ -0,0 +1,26 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#ifndef PLASMALNF_CONFIG_H +#define PLASMALNF_CONFIG_H + +#include + +class Config : public QObject +{ + Q_OBJECT + +public: + Config( QObject* parent = nullptr ); + virtual ~Config() override = default; + + void setConfigurationMap( const QVariantMap& ); +}; + +#endif diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index 9bda0164b..971805502 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -8,6 +8,7 @@ */ #include "PlasmaLnfViewStep.h" +#include "Config.h" #include "PlasmaLnfJob.h" #include "PlasmaLnfPage.h" #include "ThemeInfo.h" @@ -39,6 +40,7 @@ currentPlasmaTheme() PlasmaLnfViewStep::PlasmaLnfViewStep( QObject* parent ) : Calamares::ViewStep( parent ) + , m_config( new Config( this ) ) , m_widget( new PlasmaLnfPage ) { connect( m_widget, &PlasmaLnfPage::plasmaThemeSelected, this, &PlasmaLnfViewStep::themeSelected ); @@ -127,6 +129,7 @@ PlasmaLnfViewStep::jobs() const void PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { + m_config->setConfigurationMap( configurationMap ); m_lnfPath = CalamaresUtils::getString( configurationMap, "lnftool" ); m_widget->setLnfPath( m_lnfPath ); diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.h b/src/modules/plasmalnf/PlasmaLnfViewStep.h index 74de803c9..f30761ffc 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.h +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.h @@ -14,6 +14,7 @@ #include "utils/PluginFactory.h" #include "viewpages/ViewStep.h" +class Config; class PlasmaLnfPage; class PLUGINDLLEXPORT PlasmaLnfViewStep : public Calamares::ViewStep @@ -44,6 +45,7 @@ public slots: void themeSelected( const QString& id ); private: + Config* m_config; PlasmaLnfPage* m_widget; QString m_lnfPath; // Path to the lnf tool QString m_themeId; // Id of selected theme From 00293d11118112b69c3f45cee615ec9600e4e261 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 11 Nov 2020 13:21:16 +0100 Subject: [PATCH 02/27] [plasmalnf] Move the lookandfeeltool path setting to Config --- src/modules/plasmalnf/Config.cpp | 11 ++++++++++- src/modules/plasmalnf/Config.h | 5 +++++ src/modules/plasmalnf/PlasmaLnfViewStep.cpp | 21 ++++++++------------- src/modules/plasmalnf/PlasmaLnfViewStep.h | 1 - 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index 6a80509f4..cefbd1e64 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -9,12 +9,21 @@ #include "Config.h" +#include "utils/Logger.h" +#include "utils/Variant.h" + Config::Config( QObject* parent ) : QObject( parent ) { } void -Config::setConfigurationMap( const QVariantMap& ) +Config::setConfigurationMap( const QVariantMap& configurationMap ) { + m_lnfPath = CalamaresUtils::getString( configurationMap, "lnftool" ); + + if ( m_lnfPath.isEmpty() ) + { + cWarning() << "no lnftool given for plasmalnf module."; + } } diff --git a/src/modules/plasmalnf/Config.h b/src/modules/plasmalnf/Config.h index 389e2aff4..759d9677f 100644 --- a/src/modules/plasmalnf/Config.h +++ b/src/modules/plasmalnf/Config.h @@ -21,6 +21,11 @@ public: virtual ~Config() override = default; void setConfigurationMap( const QVariantMap& ); + + QString lnfToolPath() const { return m_lnfPath; } + +private: + QString m_lnfPath; // Path to the lnf tool }; #endif diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index 971805502..1e894011b 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -113,9 +113,9 @@ PlasmaLnfViewStep::jobs() const cDebug() << "Creating Plasma LNF jobs .."; if ( !m_themeId.isEmpty() ) { - if ( !m_lnfPath.isEmpty() ) + if ( !m_config->lnfToolPath().isEmpty() ) { - l.append( Calamares::job_ptr( new PlasmaLnfJob( m_lnfPath, m_themeId ) ) ); + l.append( Calamares::job_ptr( new PlasmaLnfJob( m_config->lnfToolPath(), m_themeId ) ) ); } else { @@ -130,13 +130,8 @@ void PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { m_config->setConfigurationMap( configurationMap ); - m_lnfPath = CalamaresUtils::getString( configurationMap, "lnftool" ); - m_widget->setLnfPath( m_lnfPath ); - if ( m_lnfPath.isEmpty() ) - { - cWarning() << "no lnftool given for plasmalnf module."; - } + m_widget->setLnfPath( m_config->lnfToolPath() ); m_liveUser = CalamaresUtils::getString( configurationMap, "liveuser" ); @@ -186,7 +181,7 @@ void PlasmaLnfViewStep::themeSelected( const QString& id ) { m_themeId = id; - if ( m_lnfPath.isEmpty() ) + if ( m_config->lnfToolPath().isEmpty() ) { cWarning() << "no lnftool given for plasmalnf module."; return; @@ -194,18 +189,18 @@ PlasmaLnfViewStep::themeSelected( const QString& id ) QProcess lnftool; if ( !m_liveUser.isEmpty() ) - lnftool.start( "sudo", { "-E", "-H", "-u", m_liveUser, m_lnfPath, "--resetLayout", "--apply", id } ); + lnftool.start( "sudo", { "-E", "-H", "-u", m_liveUser, m_config->lnfToolPath(), "--resetLayout", "--apply", id } ); else - lnftool.start( m_lnfPath, { "--resetLayout", "--apply", id } ); + lnftool.start( m_config->lnfToolPath(), { "--resetLayout", "--apply", id } ); if ( !lnftool.waitForStarted( 1000 ) ) { - cWarning() << "could not start look-and-feel" << m_lnfPath; + cWarning() << "could not start look-and-feel" << m_config->lnfToolPath(); return; } if ( !lnftool.waitForFinished() ) { - cWarning() << m_lnfPath << "timed out."; + cWarning() << m_config->lnfToolPath() << "timed out."; return; } diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.h b/src/modules/plasmalnf/PlasmaLnfViewStep.h index f30761ffc..1f97f91b2 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.h +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.h @@ -47,7 +47,6 @@ public slots: private: Config* m_config; PlasmaLnfPage* m_widget; - QString m_lnfPath; // Path to the lnf tool QString m_themeId; // Id of selected theme QString m_liveUser; // Name of the live user (for OEM mode) }; From b4aca7e1889497f94264008c8ffbd7cd57424c9b Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 11 Nov 2020 14:03:23 +0100 Subject: [PATCH 03/27] [libcalamares] Tidy up documentation for System::runCommand - Make explicit which one runs in the host, which one is selectable. - Document *location* parameter in the selectable version. - Tidy up alignment of apidox. --- src/libcalamares/utils/CalamaresUtilsSystem.h | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.h b/src/libcalamares/utils/CalamaresUtilsSystem.h index afdd4ec34..e11ecae05 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.h +++ b/src/libcalamares/utils/CalamaresUtilsSystem.h @@ -139,32 +139,33 @@ public: RunInTarget }; - /** - * Runs the specified command in the chroot of the target system. - * @param args the command with arguments, as a string list. - * @param workingPath the current working directory for the QProcess - * call (optional). - * @param stdInput the input string to send to the running process as - * standard input (optional). - * @param timeoutSec the timeout after which the process will be - * killed (optional, default is 0 i.e. no timeout). - * - * @returns the program's exit code and its output (if any). Special - * exit codes (which will never have any output) are: - * Crashed = QProcess crash - * FailedToStart = QProcess cannot start - * NoWorkingDirectory = bad arguments - * TimedOut = QProcess timeout - */ + /** @brief Runs a command in the host or the target (select explicitly) + * + * @param location whether to run in the host or the target + * @param args the command with arguments, as a string list. + * @param workingPath the current working directory for the QProcess + * call (optional). + * @param stdInput the input string to send to the running process as + * standard input (optional). + * @param timeoutSec the timeout after which the process will be + * killed (optional, default is 0 i.e. no timeout). + * + * @returns the program's exit code and its output (if any). Special + * exit codes (which will never have any output) are: + * Crashed = QProcess crash + * FailedToStart = QProcess cannot start + * NoWorkingDirectory = bad arguments + * TimedOut = QProcess timeout + */ static DLLEXPORT ProcessResult runCommand( RunLocation location, const QStringList& args, const QString& workingPath = QString(), const QString& stdInput = QString(), std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) ); - /** @brief Convenience wrapper for runCommand() + /** @brief Convenience wrapper for runCommand() in the host * - * Runs the given command-line @p args in the host in the current direcory + * Runs the given command-line @p args in the **host** in the current direcory * with no input, and the given @p timeoutSec for completion. */ static inline ProcessResult runCommand( const QStringList& args, std::chrono::seconds timeoutSec ) @@ -173,10 +174,11 @@ public: } /** @brief Convenience wrapper for runCommand(). - * Runs the command in the location specified through the boolean - * doChroot(), which is what you usually want for running commands - * during installation. - */ + * + * Runs the command in the location specified through the boolean + * doChroot(), which is what you usually want for running commands + * during installation. + */ inline ProcessResult targetEnvCommand( const QStringList& args, const QString& workingPath = QString(), const QString& stdInput = QString(), From 0af12546ef794dd8fdf67b52e0e45d57f0a5a074 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 11 Nov 2020 14:41:45 +0100 Subject: [PATCH 04/27] [plasmalnf] Migrate more settings to Config --- src/modules/plasmalnf/Config.cpp | 42 +++++++++++++++++++ src/modules/plasmalnf/Config.h | 24 +++++++++++ src/modules/plasmalnf/PlasmaLnfViewStep.cpp | 45 ++------------------- src/modules/plasmalnf/PlasmaLnfViewStep.h | 5 --- 4 files changed, 69 insertions(+), 47 deletions(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index cefbd1e64..c813959e3 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -9,6 +9,7 @@ #include "Config.h" +#include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" #include "utils/Variant.h" @@ -26,4 +27,45 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) { cWarning() << "no lnftool given for plasmalnf module."; } + + m_liveUser = CalamaresUtils::getString( configurationMap, "liveuser" ); +} + +void +Config::setTheme( const QString& id ) +{ + if ( m_themeId == id ) + { + return; + } + + m_themeId = id; + if ( lnfToolPath().isEmpty() ) + { + cWarning() << "no lnftool given for plasmalnf module."; + } + else + { + QStringList command; + if ( !m_liveUser.isEmpty() ) + { + command << "sudo" + << "-E" + << "-H" + << "-u" << m_liveUser; + } + command << lnfToolPath() << "--resetLayout" + << "--apply" << id; + auto r = CalamaresUtils::System::instance()->runCommand( command, std::chrono::seconds( 10 ) ); + + if ( r.getExitCode() ) + { + cWarning() << r.explainProcess( command, std::chrono::seconds( 10 ) ); + } + else + { + cDebug() << "Plasma look-and-feel applied" << id; + } + } + emit themeChanged( id ); } diff --git a/src/modules/plasmalnf/Config.h b/src/modules/plasmalnf/Config.h index 759d9677f..16980abc0 100644 --- a/src/modules/plasmalnf/Config.h +++ b/src/modules/plasmalnf/Config.h @@ -16,16 +16,40 @@ class Config : public QObject { Q_OBJECT + Q_PROPERTY( QString theme READ theme WRITE setTheme NOTIFY themeChanged ) + public: Config( QObject* parent = nullptr ); virtual ~Config() override = default; void setConfigurationMap( const QVariantMap& ); + /** @brief Full path to the lookandfeeltool (if it exists) + * + * This can be configured, or defaults to `lookandfeeltool` to find + * it in $PATH. + */ QString lnfToolPath() const { return m_lnfPath; } + /** @brief For OEM mode, the name of the (current) live user + * + */ + QString liveUser() const { return m_liveUser; } + + /** @brief The id (in reverse-DNS notation) of the current theme. + */ + QString theme() const { return m_themeId; } + +public slots: + void setTheme( const QString& id ); + +signals: + void themeChanged( const QString& id ); private: QString m_lnfPath; // Path to the lnf tool + QString m_liveUser; // Name of the live user (for OEM mode) + + QString m_themeId; // Id of selected theme }; #endif diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index 1e894011b..7f8e19681 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -43,7 +43,7 @@ PlasmaLnfViewStep::PlasmaLnfViewStep( QObject* parent ) , m_config( new Config( this ) ) , m_widget( new PlasmaLnfPage ) { - connect( m_widget, &PlasmaLnfPage::plasmaThemeSelected, this, &PlasmaLnfViewStep::themeSelected ); + connect( m_widget, &PlasmaLnfPage::plasmaThemeSelected, m_config, &Config::setTheme ); emit nextStatusChanged( false ); } @@ -111,11 +111,11 @@ PlasmaLnfViewStep::jobs() const Calamares::JobList l; cDebug() << "Creating Plasma LNF jobs .."; - if ( !m_themeId.isEmpty() ) + if ( !m_config->theme().isEmpty() ) { if ( !m_config->lnfToolPath().isEmpty() ) { - l.append( Calamares::job_ptr( new PlasmaLnfJob( m_config->lnfToolPath(), m_themeId ) ) ); + l.append( Calamares::job_ptr( new PlasmaLnfJob( m_config->lnfToolPath(), m_config->theme() ) ) ); } else { @@ -133,8 +133,6 @@ PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) m_widget->setLnfPath( m_config->lnfToolPath() ); - m_liveUser = CalamaresUtils::getString( configurationMap, "liveuser" ); - QString preselect = CalamaresUtils::getString( configurationMap, "preselect" ); if ( preselect == QStringLiteral( "*" ) ) { @@ -176,40 +174,3 @@ PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) m_widget->setEnabledThemesAll(); // All of them } } - -void -PlasmaLnfViewStep::themeSelected( const QString& id ) -{ - m_themeId = id; - if ( m_config->lnfToolPath().isEmpty() ) - { - cWarning() << "no lnftool given for plasmalnf module."; - return; - } - - QProcess lnftool; - if ( !m_liveUser.isEmpty() ) - lnftool.start( "sudo", { "-E", "-H", "-u", m_liveUser, m_config->lnfToolPath(), "--resetLayout", "--apply", id } ); - else - lnftool.start( m_config->lnfToolPath(), { "--resetLayout", "--apply", id } ); - - if ( !lnftool.waitForStarted( 1000 ) ) - { - cWarning() << "could not start look-and-feel" << m_config->lnfToolPath(); - return; - } - if ( !lnftool.waitForFinished() ) - { - cWarning() << m_config->lnfToolPath() << "timed out."; - return; - } - - if ( ( lnftool.exitCode() == 0 ) && ( lnftool.exitStatus() == QProcess::NormalExit ) ) - { - cDebug() << "Plasma look-and-feel applied" << id; - } - else - { - cWarning() << "could not apply look-and-feel" << id; - } -} diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.h b/src/modules/plasmalnf/PlasmaLnfViewStep.h index 1f97f91b2..48f03cdad 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.h +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.h @@ -41,14 +41,9 @@ public: void setConfigurationMap( const QVariantMap& configurationMap ) override; -public slots: - void themeSelected( const QString& id ); - private: Config* m_config; PlasmaLnfPage* m_widget; - QString m_themeId; // Id of selected theme - QString m_liveUser; // Name of the live user (for OEM mode) }; CALAMARES_PLUGIN_FACTORY_DECLARATION( PlasmaLnfViewStepFactory ) From cba27334712280cb1c5700a3e47390c62ee13819 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 11 Nov 2020 14:45:31 +0100 Subject: [PATCH 05/27] [plasmalnf] Move job creation to config --- src/modules/plasmalnf/Config.cpp | 23 +++++++++++++++++++++ src/modules/plasmalnf/Config.h | 3 +++ src/modules/plasmalnf/PlasmaLnfViewStep.cpp | 17 +-------------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index c813959e3..c7aea240f 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -9,6 +9,8 @@ #include "Config.h" +#include "PlasmaLnfJob.h" + #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" #include "utils/Variant.h" @@ -31,6 +33,27 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) m_liveUser = CalamaresUtils::getString( configurationMap, "liveuser" ); } +Calamares::JobList +Config::createJobs() const +{ + Calamares::JobList l; + + cDebug() << "Creating Plasma LNF jobs .."; + if ( !theme().isEmpty() ) + { + if ( !lnfToolPath().isEmpty() ) + { + l.append( Calamares::job_ptr( new PlasmaLnfJob( lnfToolPath(), theme() ) ) ); + } + else + { + cWarning() << "no lnftool given for plasmalnf module."; + } + } + return l; +} + + void Config::setTheme( const QString& id ) { diff --git a/src/modules/plasmalnf/Config.h b/src/modules/plasmalnf/Config.h index 16980abc0..ef32df2d9 100644 --- a/src/modules/plasmalnf/Config.h +++ b/src/modules/plasmalnf/Config.h @@ -10,6 +10,8 @@ #ifndef PLASMALNF_CONFIG_H #define PLASMALNF_CONFIG_H +#include "Job.h" + #include class Config : public QObject @@ -23,6 +25,7 @@ public: virtual ~Config() override = default; void setConfigurationMap( const QVariantMap& ); + Calamares::JobList createJobs() const; /** @brief Full path to the lookandfeeltool (if it exists) * diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index 7f8e19681..52435d5a6 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -9,7 +9,6 @@ #include "PlasmaLnfViewStep.h" #include "Config.h" -#include "PlasmaLnfJob.h" #include "PlasmaLnfPage.h" #include "ThemeInfo.h" @@ -108,21 +107,7 @@ PlasmaLnfViewStep::onLeave() Calamares::JobList PlasmaLnfViewStep::jobs() const { - Calamares::JobList l; - - cDebug() << "Creating Plasma LNF jobs .."; - if ( !m_config->theme().isEmpty() ) - { - if ( !m_config->lnfToolPath().isEmpty() ) - { - l.append( Calamares::job_ptr( new PlasmaLnfJob( m_config->lnfToolPath(), m_config->theme() ) ) ); - } - else - { - cWarning() << "no lnftool given for plasmalnf module."; - } - } - return l; + return m_config->createJobs(); } From a19109ed0b800d2efd2eb02a2ed430fc09408224 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 12 Nov 2020 15:36:29 +0100 Subject: [PATCH 06/27] [plasmalnf] Prepare a new model - start a model for available themes, to replace the list held by the widget which just duplicates information. - move preselected theme to Config. --- src/modules/plasmalnf/Config.cpp | 102 ++++++++++++++++++++ src/modules/plasmalnf/Config.h | 20 +++- src/modules/plasmalnf/PlasmaLnfViewStep.cpp | 29 +----- 3 files changed, 122 insertions(+), 29 deletions(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index c7aea240f..1fd6033df 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -15,8 +15,99 @@ #include "utils/Logger.h" #include "utils/Variant.h" +#ifdef WITH_KCONFIG +#include +#include +#endif + +#include +#include + +#include +#include + +class ThemesModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum + { + LabelRole = Qt::DisplayRole, + KeyRole = Qt::UserRole + }; + + explicit ThemesModel( QObject* parent ); + + int rowCount( const QModelIndex& = QModelIndex() ) const override; + QVariant data( const QModelIndex& index, int role ) const override; + + QHash< int, QByteArray > roleNames() const override; + +private: + QList< KPluginMetaData > m_themes; +}; + +ThemesModel::ThemesModel( QObject* parent ) + : QAbstractListModel( parent ) + , m_themes( KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" ) ) +{ +} + +int +ThemesModel::rowCount( const QModelIndex& ) const +{ + return m_themes.count(); +} + +QVariant +ThemesModel::data( const QModelIndex& index, int role ) const +{ + if ( !index.isValid() ) + { + return QVariant(); + } + if ( index.row() < 0 || index.row() >= m_themes.count() ) + { + return QVariant(); + } + + const auto& item = m_themes.at( index.row() ); + switch ( role ) + { + case LabelRole: + return item.name(); + case KeyRole: + return item.pluginId(); + default: + return QVariant(); + } + __builtin_unreachable(); +} + +QHash< int, QByteArray > +ThemesModel::roleNames() const +{ + return { { LabelRole, "label" }, { KeyRole, "key" } }; +} + + +static QString +currentPlasmaTheme() +{ +#ifdef WITH_KCONFIG + KConfigGroup cg( KSharedConfig::openConfig( QStringLiteral( "kdeglobals" ) ), "KDE" ); + return cg.readEntry( "LookAndFeelPackage", QString() ); +#else + cWarning() << "No KConfig support, cannot determine Plasma theme."; + return QString(); +#endif +} + + Config::Config( QObject* parent ) : QObject( parent ) + , m_themeModel( new ThemesModel( this ) ) { } @@ -31,6 +122,13 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) } m_liveUser = CalamaresUtils::getString( configurationMap, "liveuser" ); + + QString preselect = CalamaresUtils::getString( configurationMap, "preselect" ); + if ( preselect == QStringLiteral( "*" ) ) + { + preselect = currentPlasmaTheme(); + } + m_preselectThemeId = preselect; } Calamares::JobList @@ -92,3 +190,7 @@ Config::setTheme( const QString& id ) } emit themeChanged( id ); } + +#include "utils/moc-warnings.h" + +#include "Config.moc" diff --git a/src/modules/plasmalnf/Config.h b/src/modules/plasmalnf/Config.h index ef32df2d9..cad705530 100644 --- a/src/modules/plasmalnf/Config.h +++ b/src/modules/plasmalnf/Config.h @@ -14,15 +14,19 @@ #include +class QAbstractItemModel; + class Config : public QObject { Q_OBJECT + Q_PROPERTY( QString preselectedTheme READ preselectedTheme CONSTANT ) Q_PROPERTY( QString theme READ theme WRITE setTheme NOTIFY themeChanged ) + Q_PROPERTY( QAbstractItemModel* themeModel READ themeModel CONSTANT ) public: Config( QObject* parent = nullptr ); - virtual ~Config() override = default; + virtual ~Config() override = default; // QObject cleans up the model pointer void setConfigurationMap( const QVariantMap& ); Calamares::JobList createJobs() const; @@ -42,6 +46,17 @@ public: */ QString theme() const { return m_themeId; } + /** @brief The theme we start with + * + * This can be configured, or is taken from the live environment + * if the environment is (also) KDE Plasma. + */ + QString preselectedTheme() const { return m_preselectThemeId; } + + /** @brief The (list) model of available themes. + */ + QAbstractItemModel* themeModel() const { return m_themeModel; } + public slots: void setTheme( const QString& id ); @@ -52,7 +67,10 @@ private: QString m_lnfPath; // Path to the lnf tool QString m_liveUser; // Name of the live user (for OEM mode) + QString m_preselectThemeId; QString m_themeId; // Id of selected theme + + QAbstractItemModel* m_themeModel = nullptr; }; #endif diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index 52435d5a6..d282cea09 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -15,28 +15,10 @@ #include "utils/Logger.h" #include "utils/Variant.h" -#include #include -#ifdef WITH_KCONFIG -#include -#include -#endif - CALAMARES_PLUGIN_FACTORY_DEFINITION( PlasmaLnfViewStepFactory, registerPlugin< PlasmaLnfViewStep >(); ) -static QString -currentPlasmaTheme() -{ -#ifdef WITH_KCONFIG - KConfigGroup cg( KSharedConfig::openConfig( QStringLiteral( "kdeglobals" ) ), "KDE" ); - return cg.readEntry( "LookAndFeelPackage", QString() ); -#else - cWarning() << "No KConfig support, cannot determine Plasma theme."; - return QString(); -#endif -} - PlasmaLnfViewStep::PlasmaLnfViewStep( QObject* parent ) : Calamares::ViewStep( parent ) , m_config( new Config( this ) ) @@ -117,16 +99,7 @@ PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) m_config->setConfigurationMap( configurationMap ); m_widget->setLnfPath( m_config->lnfToolPath() ); - - QString preselect = CalamaresUtils::getString( configurationMap, "preselect" ); - if ( preselect == QStringLiteral( "*" ) ) - { - preselect = currentPlasmaTheme(); - } - if ( !preselect.isEmpty() ) - { - m_widget->setPreselect( preselect ); - } + m_widget->setPreselect( m_config->preselectedTheme() ); bool showAll = CalamaresUtils::getBool( configurationMap, "showAll", false ); From 27f1e82a8ffa1b6f412f07c49c6f19a3f4b79719 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 12 Nov 2020 15:59:03 +0100 Subject: [PATCH 07/27] [plasmalnf] Remove unused path-setting from the widget - Only Config needs to know the path, since it is responsible for doing the actual lnf changes. --- src/modules/plasmalnf/PlasmaLnfPage.cpp | 6 ------ src/modules/plasmalnf/PlasmaLnfPage.h | 2 -- src/modules/plasmalnf/PlasmaLnfViewStep.cpp | 1 - 3 files changed, 9 deletions(-) diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index a44620074..d512b1dc0 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -72,12 +72,6 @@ PlasmaLnfPage::PlasmaLnfPage( QWidget* parent ) } ) } -void -PlasmaLnfPage::setLnfPath( const QString& path ) -{ - m_lnfPath = path; -} - void PlasmaLnfPage::setEnabledThemes( const ThemeInfoList& themes, bool showAll ) { diff --git a/src/modules/plasmalnf/PlasmaLnfPage.h b/src/modules/plasmalnf/PlasmaLnfPage.h index 287da8b29..acdf7c587 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.h +++ b/src/modules/plasmalnf/PlasmaLnfPage.h @@ -36,7 +36,6 @@ class PlasmaLnfPage : public QWidget public: explicit PlasmaLnfPage( QWidget* parent = nullptr ); - void setLnfPath( const QString& path ); /** @brief enable only the listed themes. * * Shows the listed @p themes with full information (e.g. screenshot). @@ -61,7 +60,6 @@ private: void fillUi(); Ui::PlasmaLnfPage* ui; - QString m_lnfPath; QString m_preselect; bool m_showAll; // If true, don't winnow according to enabledThemes ThemeInfoList m_enabledThemes; diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index d282cea09..445e5dddb 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -98,7 +98,6 @@ PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { m_config->setConfigurationMap( configurationMap ); - m_widget->setLnfPath( m_config->lnfToolPath() ); m_widget->setPreselect( m_config->preselectedTheme() ); bool showAll = CalamaresUtils::getBool( configurationMap, "showAll", false ); From 57907ca992be505f70933e1fb3ad71c94d2be648 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 16 Nov 2020 16:37:30 +0100 Subject: [PATCH 08/27] [plasmalnf] Move model to ThemeInfo files --- src/modules/plasmalnf/CMakeLists.txt | 1 + src/modules/plasmalnf/Config.cpp | 77 +------------------------ src/modules/plasmalnf/Config.h | 6 +- src/modules/plasmalnf/PlasmaLnfPage.cpp | 8 --- src/modules/plasmalnf/ThemeInfo.cpp | 69 ++++++++++++++++++++++ src/modules/plasmalnf/ThemeInfo.h | 27 ++++++++- 6 files changed, 100 insertions(+), 88 deletions(-) create mode 100644 src/modules/plasmalnf/ThemeInfo.cpp diff --git a/src/modules/plasmalnf/CMakeLists.txt b/src/modules/plasmalnf/CMakeLists.txt index f13f4f9c7..027b3e12a 100644 --- a/src/modules/plasmalnf/CMakeLists.txt +++ b/src/modules/plasmalnf/CMakeLists.txt @@ -36,6 +36,7 @@ if ( KF5Plasma_FOUND AND KF5Package_FOUND ) PlasmaLnfViewStep.cpp PlasmaLnfPage.cpp PlasmaLnfJob.cpp + ThemeInfo.cpp ThemeWidget.cpp RESOURCES page_plasmalnf.qrc diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index 1fd6033df..215aef1d6 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -10,6 +10,7 @@ #include "Config.h" #include "PlasmaLnfJob.h" +#include "ThemeInfo.h" #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" @@ -20,78 +21,6 @@ #include #endif -#include -#include - -#include -#include - -class ThemesModel : public QAbstractListModel -{ - Q_OBJECT - -public: - enum - { - LabelRole = Qt::DisplayRole, - KeyRole = Qt::UserRole - }; - - explicit ThemesModel( QObject* parent ); - - int rowCount( const QModelIndex& = QModelIndex() ) const override; - QVariant data( const QModelIndex& index, int role ) const override; - - QHash< int, QByteArray > roleNames() const override; - -private: - QList< KPluginMetaData > m_themes; -}; - -ThemesModel::ThemesModel( QObject* parent ) - : QAbstractListModel( parent ) - , m_themes( KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" ) ) -{ -} - -int -ThemesModel::rowCount( const QModelIndex& ) const -{ - return m_themes.count(); -} - -QVariant -ThemesModel::data( const QModelIndex& index, int role ) const -{ - if ( !index.isValid() ) - { - return QVariant(); - } - if ( index.row() < 0 || index.row() >= m_themes.count() ) - { - return QVariant(); - } - - const auto& item = m_themes.at( index.row() ); - switch ( role ) - { - case LabelRole: - return item.name(); - case KeyRole: - return item.pluginId(); - default: - return QVariant(); - } - __builtin_unreachable(); -} - -QHash< int, QByteArray > -ThemesModel::roleNames() const -{ - return { { LabelRole, "label" }, { KeyRole, "key" } }; -} - - static QString currentPlasmaTheme() { @@ -190,7 +119,3 @@ Config::setTheme( const QString& id ) } emit themeChanged( id ); } - -#include "utils/moc-warnings.h" - -#include "Config.moc" diff --git a/src/modules/plasmalnf/Config.h b/src/modules/plasmalnf/Config.h index cad705530..725563c34 100644 --- a/src/modules/plasmalnf/Config.h +++ b/src/modules/plasmalnf/Config.h @@ -12,9 +12,9 @@ #include "Job.h" -#include +#include "ThemeInfo.h" -class QAbstractItemModel; +#include class Config : public QObject { @@ -70,7 +70,7 @@ private: QString m_preselectThemeId; QString m_themeId; // Id of selected theme - QAbstractItemModel* m_themeModel = nullptr; + ThemesModel* m_themeModel = nullptr; }; #endif diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index d512b1dc0..22e240266 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -21,14 +21,6 @@ #include #include -ThemeInfo::ThemeInfo( const KPluginMetaData& data ) - : id( data.pluginId() ) - , name( data.name() ) - , description( data.description() ) - , widget( nullptr ) -{ -} - static ThemeInfoList plasma_themes() { diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp new file mode 100644 index 000000000..41bffd1f0 --- /dev/null +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -0,0 +1,69 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ +#include "ThemeInfo.h" + +#include +#include + +ThemesModel::ThemesModel( QObject* parent ) + : QAbstractListModel( parent ) +{ + auto packages = KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" ); + m_themes.reserve( packages.length() ); + + for ( const auto& p : packages ) + { + m_themes.append( ThemeInfo { p } ); + } +} + +int +ThemesModel::rowCount( const QModelIndex& ) const +{ + return m_themes.count(); +} + +QVariant +ThemesModel::data( const QModelIndex& index, int role ) const +{ + if ( !index.isValid() ) + { + return QVariant(); + } + if ( index.row() < 0 || index.row() >= m_themes.count() ) + { + return QVariant(); + } + + const auto& item = m_themes.at( index.row() ); + switch ( role ) + { + case LabelRole: + return item.name; + case KeyRole: + return item.id; + default: + return QVariant(); + } + __builtin_unreachable(); +} + +QHash< int, QByteArray > +ThemesModel::roleNames() const +{ + return { { LabelRole, "label" }, { KeyRole, "key" } }; +} + +ThemeInfo::ThemeInfo( const KPluginMetaData& data ) + : id( data.pluginId() ) + , name( data.name() ) + , description( data.description() ) + , widget( nullptr ) +{ +} diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index 6848fb8c3..a44c41858 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -10,6 +10,7 @@ #ifndef PLASMALNF_THEMEINFO_H #define PLASMALNF_THEMEINFO_H +#include #include #include @@ -49,7 +50,6 @@ struct ThemeInfo { } - // Defined in PlasmaLnfPage.cpp explicit ThemeInfo( const KPluginMetaData& ); bool isValid() const { return !id.isEmpty(); } @@ -88,4 +88,29 @@ public: bool contains( const QString& id ) const { return findById( id ) != nullptr; } }; +class ThemesModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum + { + LabelRole = Qt::DisplayRole, + KeyRole = Qt::UserRole + }; + + explicit ThemesModel( QObject* parent ); + + int rowCount( const QModelIndex& = QModelIndex() ) const override; + QVariant data( const QModelIndex& index, int role ) const override; + + QHash< int, QByteArray > roleNames() const override; + + const ThemeInfo* findById( const QString& id ) const { return m_themes.findById( id ); } + +private: + ThemeInfoList m_themes; +}; + + #endif From 254933a4888aff9c28cfc02f9dac357f51b5b889 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 16 Nov 2020 21:28:37 +0100 Subject: [PATCH 09/27] [plasmalnf] Prep-work for loading the themes into the model --- src/modules/plasmalnf/ThemeInfo.cpp | 39 +++++++++++++++++++++++++++++ src/modules/plasmalnf/ThemeInfo.h | 13 ++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 41bffd1f0..2cf389a7c 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -60,6 +60,45 @@ ThemesModel::roleNames() const return { { LabelRole, "label" }, { KeyRole, "key" } }; } +void +ThemesModel::setThemeImage( const QString& id, const QString& imagePath ) +{ + auto* theme = m_themes.findById( id ); + if ( theme ) + { + theme->imagePath = imagePath; + } +} + +void +ThemesModel::setThemeImage( const QMap< QString, QString >& images ) +{ + for ( const auto& k : images ) + { + setThemeImage( k, images[ k ] ); + } +} + +void +ThemesModel::showTheme( const QString& id, bool show ) +{ + auto* theme = m_themes.findById( id ); + if ( theme ) + { + theme->show = show; + } +} + +void +ThemesModel::showTheme( const QMap< QString, QString >& onlyThese ) +{ + for ( auto& t : m_themes ) + { + t.show = onlyThese.contains( t.id ); + } +} + + ThemeInfo::ThemeInfo( const KPluginMetaData& data ) : id( data.pluginId() ) , name( data.name() ) diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index a44c41858..3ac83c771 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -31,6 +31,7 @@ struct ThemeInfo QString description; QString imagePath; ThemeWidget* widget; + bool show = true; ThemeInfo() : widget( nullptr ) @@ -108,6 +109,18 @@ public: const ThemeInfo* findById( const QString& id ) const { return m_themes.findById( id ); } + /// @brief Set the screenshot to go with the given @p id + void setThemeImage( const QString& id, const QString& imagePath ); + + /// @brief Call setThemeImage( key, value ) for all keys in @p images + void setThemeImage( const QMap< QString, QString >& images ); + + /// @brief Set whether to show the given theme @p id (or not) + void showTheme( const QString& id, bool show = true ); + + /// @brief Shows the keys in the @p onlyThese map, and hides the rest + void showTheme( const QMap< QString, QString >& onlyThese ); + private: ThemeInfoList m_themes; }; From d4887426e291f4eca28df026a19dfb7a566dd105 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 16 Nov 2020 21:57:06 +0100 Subject: [PATCH 10/27] [plasmalnf] Set screenshots on themes, filtering - while here reorder the config so the effect of *showAll* is clearer --- src/modules/plasmalnf/Config.cpp | 31 ++++++++++++++++++++++++++++ src/modules/plasmalnf/ThemeInfo.cpp | 2 +- src/modules/plasmalnf/ThemeInfo.h | 2 +- src/modules/plasmalnf/plasmalnf.conf | 17 ++++++++------- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index 215aef1d6..9e5183383 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -58,6 +58,37 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) preselect = currentPlasmaTheme(); } m_preselectThemeId = preselect; + + if ( configurationMap.contains( "themes" ) && configurationMap.value( "themes" ).type() == QVariant::List ) + { + QMap< QString, QString > listedThemes; + auto themeList = configurationMap.value( "themes" ).toList(); + // Create the ThemInfo objects for the listed themes; information + // about the themes from Plasma (e.g. human-readable name and description) + // are filled in by update_names() in PlasmaLnfPage. + for ( const auto& i : themeList ) + if ( i.type() == QVariant::Map ) + { + auto iv = i.toMap(); + listedThemes.insert( iv.value( "theme" ).toString(), iv.value( "image" ).toString() ); + } + else if ( i.type() == QVariant::String ) + { + listedThemes.insert( i.toString(), QString() ); + } + + if ( listedThemes.count() == 1 ) + { + cWarning() << "only one theme enabled in plasmalnf"; + } + m_themeModel->setThemeImage( listedThemes ); + + bool showAll = CalamaresUtils::getBool( configurationMap, "showAll", false ); + if ( !listedThemes.isEmpty() && !showAll ) + { + m_themeModel->showOnlyThemes( listedThemes ); + } + } } Calamares::JobList diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 2cf389a7c..51b19c8fa 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -90,7 +90,7 @@ ThemesModel::showTheme( const QString& id, bool show ) } void -ThemesModel::showTheme( const QMap< QString, QString >& onlyThese ) +ThemesModel::showOnlyThemes( const QMap< QString, QString >& onlyThese ) { for ( auto& t : m_themes ) { diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index 3ac83c771..978aee70e 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -119,7 +119,7 @@ public: void showTheme( const QString& id, bool show = true ); /// @brief Shows the keys in the @p onlyThese map, and hides the rest - void showTheme( const QMap< QString, QString >& onlyThese ); + void showOnlyThemes( const QMap< QString, QString >& onlyThese ); private: ThemeInfoList m_themes; diff --git a/src/modules/plasmalnf/plasmalnf.conf b/src/modules/plasmalnf/plasmalnf.conf index fd59389a8..105f247ef 100644 --- a/src/modules/plasmalnf/plasmalnf.conf +++ b/src/modules/plasmalnf/plasmalnf.conf @@ -24,10 +24,18 @@ lnftool: "/usr/bin/lookandfeeltool" # # liveuser: "live" +# If *showAll* is true, then all installed themes are shown in the +# UI for selection, even if they are not listed in *themes* (below). +# This allows selection of all themes even while not all of them are +# listed in *themes* -- which is useful to show screenshots for those +# you do have a screenshot for. If *themes* is empty or missing, +# the value of *showAll* is treated as `true`. +showAll: false + # You can limit the list of Plasma look-and-feel themes by listing ids # here. If this key is not present, all of the installed themes are listed. # If the key is present, only installed themes that are **also** included -# in the list are shown (could be none!). See the *showAll* key, below, +# in the list are shown (could be none!). See the *showAll* key, above, # to change that. # # Themes may be listed by id, (e.g. fluffy-bunny, below) or as a theme @@ -58,13 +66,6 @@ themes: image: "breeze-dark.png" - org.kde.fluffy-bunny.desktop -# If *showAll* is true, then all installed themes are shown in the -# UI for selection, even if they are not listed in *themes*. This -# allows selection of all themes even while not all of them are -# listed in *themes* -- which is useful to show screenshots for those -# you do have a screenshot for. -showAll: false - # You can pre-select one of the themes; it is not applied # immediately, but its radio-button is switched on to indicate # that that is the theme (that is most likely) currently in use. From aaa56b69033e1111464cef1b89f373751c4916d6 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 16 Nov 2020 23:36:32 +0100 Subject: [PATCH 11/27] [plasmalnf] Rip out most of the widget - put a filter model in place, so only the themes with "show" set are displayed - rip out the messing about with widgets, soon to introduce a model- based UI --- src/modules/plasmalnf/Config.cpp | 9 +- src/modules/plasmalnf/Config.h | 3 +- src/modules/plasmalnf/PlasmaLnfPage.cpp | 149 +------------------- src/modules/plasmalnf/PlasmaLnfPage.h | 30 +--- src/modules/plasmalnf/PlasmaLnfViewStep.cpp | 36 +---- src/modules/plasmalnf/ThemeInfo.cpp | 2 + src/modules/plasmalnf/ThemeInfo.h | 3 +- 7 files changed, 23 insertions(+), 209 deletions(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index 9e5183383..f5fa59b89 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -21,6 +21,8 @@ #include #endif +#include + static QString currentPlasmaTheme() { @@ -33,11 +35,16 @@ currentPlasmaTheme() #endif } - Config::Config( QObject* parent ) : QObject( parent ) , m_themeModel( new ThemesModel( this ) ) { + auto* filter = new QSortFilterProxyModel( m_themeModel ); + filter->setFilterRole( ThemesModel::ShownRole ); + filter->setFilterFixedString( QStringLiteral( "true" ) ); + filter->setSourceModel( m_themeModel ); + + m_filteredModel = filter; } void diff --git a/src/modules/plasmalnf/Config.h b/src/modules/plasmalnf/Config.h index 725563c34..aafdf6418 100644 --- a/src/modules/plasmalnf/Config.h +++ b/src/modules/plasmalnf/Config.h @@ -55,7 +55,7 @@ public: /** @brief The (list) model of available themes. */ - QAbstractItemModel* themeModel() const { return m_themeModel; } + QAbstractItemModel* themeModel() const { return m_filteredModel; } public slots: void setTheme( const QString& id ); @@ -70,6 +70,7 @@ private: QString m_preselectThemeId; QString m_themeId; // Id of selected theme + QAbstractItemModel* m_filteredModel = nullptr; ThemesModel* m_themeModel = nullptr; }; diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index 22e240266..095bd3ec9 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -10,6 +10,7 @@ #include "PlasmaLnfPage.h" +#include "Config.h" #include "ui_page_plasmalnf.h" #include "Settings.h" @@ -21,30 +22,10 @@ #include #include -static ThemeInfoList -plasma_themes() -{ - ThemeInfoList packages; - - QList< KPluginMetaData > pkgs = KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" ); - - for ( const KPluginMetaData& data : pkgs ) - { - if ( data.isValid() && !data.isHidden() && !data.name().isEmpty() ) - { - packages << ThemeInfo { data }; - } - } - - return packages; -} - - -PlasmaLnfPage::PlasmaLnfPage( QWidget* parent ) +PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) : QWidget( parent ) , ui( new Ui::PlasmaLnfPage ) - , m_showAll( false ) - , m_buttonGroup( nullptr ) + , m_config( config ) { ui->setupUi( this ); CALAMARES_RETRANSLATE( { @@ -59,128 +40,6 @@ PlasmaLnfPage::PlasmaLnfPage( QWidget* parent ) "You can also skip this step and configure the look-and-feel " "once the system is installed. Clicking on a look-and-feel " "selection will give you a live preview of that look-and-feel." ) ); - updateThemeNames(); - fillUi(); } ) -} - -void -PlasmaLnfPage::setEnabledThemes( const ThemeInfoList& themes, bool showAll ) -{ - m_enabledThemes = themes; - - if ( showAll ) - { - auto plasmaThemes = plasma_themes(); - for ( auto& installed_theme : plasmaThemes ) - if ( !m_enabledThemes.findById( installed_theme.id ) ) - { - m_enabledThemes.append( installed_theme ); - } - } - - updateThemeNames(); - winnowThemes(); - fillUi(); -} - -void -PlasmaLnfPage::setEnabledThemesAll() -{ - // Don't need to set showAll=true, because we're already passing in - // the complete list of installed themes. - setEnabledThemes( plasma_themes(), false ); -} - -void -PlasmaLnfPage::setPreselect( const QString& id ) -{ - m_preselect = id; - if ( !m_enabledThemes.isEmpty() ) - { - fillUi(); - } -} - -void -PlasmaLnfPage::updateThemeNames() -{ - auto plasmaThemes = plasma_themes(); - for ( auto& enabled_theme : m_enabledThemes ) - { - ThemeInfo* t = plasmaThemes.findById( enabled_theme.id ); - if ( t != nullptr ) - { - enabled_theme.name = t->name; - enabled_theme.description = t->description; - } - } -} - -void -PlasmaLnfPage::winnowThemes() -{ - auto plasmaThemes = plasma_themes(); - bool winnowed = true; - int winnow_index = 0; - while ( winnowed ) - { - winnowed = false; - winnow_index = 0; - - for ( auto& enabled_theme : m_enabledThemes ) - { - ThemeInfo* t = plasmaThemes.findById( enabled_theme.id ); - if ( t == nullptr ) - { - cDebug() << "Removing" << enabled_theme.id; - winnowed = true; - break; - } - ++winnow_index; - } - - if ( winnowed ) - { - m_enabledThemes.removeAt( winnow_index ); - } - } -} - -void -PlasmaLnfPage::fillUi() -{ - if ( m_enabledThemes.isEmpty() ) - { - return; - } - - if ( !m_buttonGroup ) - { - m_buttonGroup = new QButtonGroup( this ); - m_buttonGroup->setExclusive( true ); - } - - int c = 1; // After the general explanation - for ( auto& theme : m_enabledThemes ) - { - if ( !theme.widget ) - { - ThemeWidget* w = new ThemeWidget( theme ); - m_buttonGroup->addButton( w->button() ); - ui->verticalLayout->insertWidget( c, w ); - connect( w, &ThemeWidget::themeSelected, this, &PlasmaLnfPage::plasmaThemeSelected ); - theme.widget = w; - } - else - { - theme.widget->updateThemeName( theme ); - } - if ( theme.id == m_preselect ) - { - const QSignalBlocker b( theme.widget->button() ); - theme.widget->button()->setChecked( true ); - } - ++c; - } + connect( this, &PlasmaLnfPage::plasmaThemeSelected, config, &Config::setTheme ); } diff --git a/src/modules/plasmalnf/PlasmaLnfPage.h b/src/modules/plasmalnf/PlasmaLnfPage.h index acdf7c587..9afda305c 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.h +++ b/src/modules/plasmalnf/PlasmaLnfPage.h @@ -24,6 +24,8 @@ namespace Ui class PlasmaLnfPage; } +class Config; + /** @brief Page for selecting a Plasma Look-and-Feel theme. * * You must call setEnabledThemes -- either overload -- once @@ -34,38 +36,14 @@ class PlasmaLnfPage : public QWidget { Q_OBJECT public: - explicit PlasmaLnfPage( QWidget* parent = nullptr ); - - /** @brief enable only the listed themes. - * - * Shows the listed @p themes with full information (e.g. screenshot). - * If @p showAll is true, then also show all installed themes - * not explicitly listed (without a screenshot). - */ - void setEnabledThemes( const ThemeInfoList& themes, bool showAll ); - /** @brief enable all installed plasma themes. */ - void setEnabledThemesAll(); - /** @brief set which theme is to be preselected. */ - void setPreselect( const QString& id ); + explicit PlasmaLnfPage( Config* config, QWidget* parent = nullptr ); signals: void plasmaThemeSelected( const QString& id ); private: - /** @brief Intersect the list of enabled themes with the installed ones. */ - void winnowThemes(); - /** @brief Get the translated names for all enabled themes. */ - void updateThemeNames(); - /** @brief show enabled themes in the UI. */ - void fillUi(); - Ui::PlasmaLnfPage* ui; - QString m_preselect; - bool m_showAll; // If true, don't winnow according to enabledThemes - ThemeInfoList m_enabledThemes; - - QButtonGroup* m_buttonGroup; - QList< ThemeWidget* > m_widgets; + Config* m_config; }; #endif //PLASMALNFPAGE_H diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index 445e5dddb..fd38bfab3 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -22,9 +22,8 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( PlasmaLnfViewStepFactory, registerPlugin< P PlasmaLnfViewStep::PlasmaLnfViewStep( QObject* parent ) : Calamares::ViewStep( parent ) , m_config( new Config( this ) ) - , m_widget( new PlasmaLnfPage ) + , m_widget( new PlasmaLnfPage( m_config ) ) { - connect( m_widget, &PlasmaLnfPage::plasmaThemeSelected, m_config, &Config::setTheme ); emit nextStatusChanged( false ); } @@ -97,37 +96,4 @@ void PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { m_config->setConfigurationMap( configurationMap ); - - m_widget->setPreselect( m_config->preselectedTheme() ); - - bool showAll = CalamaresUtils::getBool( configurationMap, "showAll", false ); - - if ( configurationMap.contains( "themes" ) && configurationMap.value( "themes" ).type() == QVariant::List ) - { - ThemeInfoList listedThemes; - auto themeList = configurationMap.value( "themes" ).toList(); - // Create the ThemInfo objects for the listed themes; information - // about the themes from Plasma (e.g. human-readable name and description) - // are filled in by update_names() in PlasmaLnfPage. - for ( const auto& i : themeList ) - if ( i.type() == QVariant::Map ) - { - auto iv = i.toMap(); - listedThemes.append( ThemeInfo( iv.value( "theme" ).toString(), iv.value( "image" ).toString() ) ); - } - else if ( i.type() == QVariant::String ) - { - listedThemes.append( ThemeInfo( i.toString() ) ); - } - - if ( listedThemes.length() == 1 ) - { - cWarning() << "only one theme enabled in plasmalnf"; - } - m_widget->setEnabledThemes( listedThemes, showAll ); - } - else - { - m_widget->setEnabledThemesAll(); // All of them - } } diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 51b19c8fa..c9ab3e36a 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -48,6 +48,8 @@ ThemesModel::data( const QModelIndex& index, int role ) const return item.name; case KeyRole: return item.id; + case ShownRole: + return item.show; default: return QVariant(); } diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index 978aee70e..cba9b87d6 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -97,7 +97,8 @@ public: enum { LabelRole = Qt::DisplayRole, - KeyRole = Qt::UserRole + KeyRole = Qt::UserRole, + ShownRole }; explicit ThemesModel( QObject* parent ); From 1f57a0dddaab3bc1db09bfb5d93715755b8dbda3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 00:02:59 +0100 Subject: [PATCH 12/27] [plasmalnf] Very basic combo-box based UI --- src/modules/plasmalnf/Config.cpp | 2 ++ src/modules/plasmalnf/PlasmaLnfPage.cpp | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index f5fa59b89..123adecdb 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -43,6 +43,8 @@ Config::Config( QObject* parent ) filter->setFilterRole( ThemesModel::ShownRole ); filter->setFilterFixedString( QStringLiteral( "true" ) ); filter->setSourceModel( m_themeModel ); + filter->setSortRole( ThemesModel::LabelRole ); + filter->sort( 0 ); m_filteredModel = filter; } diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index 095bd3ec9..cf1330912 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -17,7 +17,8 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" -#include +#include + #include #include @@ -42,4 +43,18 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) "selection will give you a live preview of that look-and-feel." ) ); } ) connect( this, &PlasmaLnfPage::plasmaThemeSelected, config, &Config::setTheme ); + + QComboBox* box = new QComboBox(); + box->setModel( m_config->themeModel() ); + ui->verticalLayout->addWidget( box ); + + connect( box, QOverload< int >::of( &QComboBox::currentIndexChanged ), [this]( int index ) { + auto* model = m_config->themeModel(); + auto id = model->data( model->index( index, 0 ), ThemesModel::KeyRole ).toString(); + cDebug() << "ComboBox selected" << index << id; + if ( !id.isEmpty() ) + { + emit plasmaThemeSelected( id ); + } + } ); } From f9e99da4686829ec28822f75ed112c4aaaaa259f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 00:12:47 +0100 Subject: [PATCH 13/27] [plasmalnf] Improve lnf model - remove useless widget pointer from themeinfo - notify when data changes in the model --- src/modules/plasmalnf/ThemeInfo.cpp | 15 +++++++++++++-- src/modules/plasmalnf/ThemeInfo.h | 12 +++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index c9ab3e36a..f3f2a192a 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -59,7 +59,7 @@ ThemesModel::data( const QModelIndex& index, int role ) const QHash< int, QByteArray > ThemesModel::roleNames() const { - return { { LabelRole, "label" }, { KeyRole, "key" } }; + return { { LabelRole, "label" }, { KeyRole, "key" }, { ShownRole, "show" }, { ImageRole, "image" } }; } void @@ -75,10 +75,16 @@ ThemesModel::setThemeImage( const QString& id, const QString& imagePath ) void ThemesModel::setThemeImage( const QMap< QString, QString >& images ) { + if ( m_themes.isEmpty() ) + { + return; + } + for ( const auto& k : images ) { setThemeImage( k, images[ k ] ); } + emit dataChanged( index( 0, 0 ), index( m_themes.count() - 1 ), { ImageRole } ); } void @@ -94,10 +100,16 @@ ThemesModel::showTheme( const QString& id, bool show ) void ThemesModel::showOnlyThemes( const QMap< QString, QString >& onlyThese ) { + if ( m_themes.isEmpty() ) + { + return; + } + for ( auto& t : m_themes ) { t.show = onlyThese.contains( t.id ); } + emit dataChanged( index( 0, 0 ), index( m_themes.count() - 1 ), { ShownRole } ); } @@ -105,6 +117,5 @@ ThemeInfo::ThemeInfo( const KPluginMetaData& data ) : id( data.pluginId() ) , name( data.name() ) , description( data.description() ) - , widget( nullptr ) { } diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index cba9b87d6..a75c3c2bc 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -15,7 +15,6 @@ #include class KPluginMetaData; -class ThemeWidget; /** @brief describes a single plasma LnF theme. * @@ -30,24 +29,18 @@ struct ThemeInfo QString name; QString description; QString imagePath; - ThemeWidget* widget; bool show = true; - ThemeInfo() - : widget( nullptr ) - { - } + ThemeInfo() {} explicit ThemeInfo( const QString& _id ) : id( _id ) - , widget( nullptr ) { } explicit ThemeInfo( const QString& _id, const QString& image ) : id( _id ) , imagePath( image ) - , widget( nullptr ) { } @@ -98,7 +91,8 @@ public: { LabelRole = Qt::DisplayRole, KeyRole = Qt::UserRole, - ShownRole + ShownRole, + ImageRole }; explicit ThemesModel( QObject* parent ); From f93cec031b93d418394fc0fcf18c744f983b3883 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 00:25:48 +0100 Subject: [PATCH 14/27] [plasmalnf] Introduce an index-lookup function - for signalling model changes, also need to know indexes / row --- src/modules/plasmalnf/ThemeInfo.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index a75c3c2bc..34c26dc6f 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -52,6 +52,20 @@ struct ThemeInfo class ThemeInfoList : public QList< ThemeInfo > { public: + std::pair< int, ThemeInfo* > indexById( const QString& id ) + { + int index = 0; + for ( ThemeInfo& i : *this ) + { + if ( i.id == id ) + { + return { index, &i }; + } + } + return { -1, nullptr }; + } + + /** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */ ThemeInfo* findById( const QString& id ) { From 39094595630360f56e367e30b77dd6e2ade7b46a Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 11:17:47 +0100 Subject: [PATCH 15/27] [plasmalnf] Signal more changes to the model - also individual changes need to be signalled - use QSignalBlocker to avoid spamming changes when calling aggregate change methods - refactor findById() so that also a row number can be obtained, which is needed for the change signals. --- src/modules/plasmalnf/ThemeInfo.cpp | 16 +++++++++++---- src/modules/plasmalnf/ThemeInfo.h | 31 ++++++++++++----------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index f3f2a192a..2999a7cac 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -65,10 +65,11 @@ ThemesModel::roleNames() const void ThemesModel::setThemeImage( const QString& id, const QString& imagePath ) { - auto* theme = m_themes.findById( id ); + auto [ i, theme ] = m_themes.indexById( id ); if ( theme ) { theme->imagePath = imagePath; + emit dataChanged( index( i, 0 ), index( i, 0 ), { ImageRole } ); } } @@ -80,9 +81,13 @@ ThemesModel::setThemeImage( const QMap< QString, QString >& images ) return; } - for ( const auto& k : images ) + // Don't emit signals from each call, aggregate to one call (below this block) { - setThemeImage( k, images[ k ] ); + QSignalBlocker b( this ); + for ( const auto& k : images ) + { + setThemeImage( k, images[ k ] ); + } } emit dataChanged( index( 0, 0 ), index( m_themes.count() - 1 ), { ImageRole } ); } @@ -90,10 +95,11 @@ ThemesModel::setThemeImage( const QMap< QString, QString >& images ) void ThemesModel::showTheme( const QString& id, bool show ) { - auto* theme = m_themes.findById( id ); + auto [ i, theme ] = m_themes.indexById( id ); if ( theme ) { theme->show = show; + emit dataChanged( index( i, 0 ), index( i, 0 ), { ShownRole } ); } } @@ -105,6 +111,8 @@ ThemesModel::showOnlyThemes( const QMap< QString, QString >& onlyThese ) return; } + // No signal blocker block needed here because we're not calling showTheme() + // QSignalBlocker b( this ); for ( auto& t : m_themes ) { t.show = onlyThese.contains( t.id ); diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index 34c26dc6f..059858617 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -52,10 +52,10 @@ struct ThemeInfo class ThemeInfoList : public QList< ThemeInfo > { public: - std::pair< int, ThemeInfo* > indexById( const QString& id ) + std::pair< int, const ThemeInfo* > indexById( const QString& id ) const { int index = 0; - for ( ThemeInfo& i : *this ) + for ( const ThemeInfo& i : *this ) { if ( i.id == id ) { @@ -65,31 +65,26 @@ public: return { -1, nullptr }; } + std::pair< int, ThemeInfo* > indexById( const QString& id ) + { + // Call the const version and then munge the types + auto [ i, p ] = const_cast< const ThemeInfoList* >( this )->indexById( id ); + return { i, const_cast< ThemeInfo* >( p ) }; + } + /** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */ ThemeInfo* findById( const QString& id ) { - for ( ThemeInfo& i : *this ) - { - if ( i.id == id ) - { - return &i; - } - } - return nullptr; + auto [ i, p ] = indexById( id ); + return p; } /** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */ const ThemeInfo* findById( const QString& id ) const { - for ( const ThemeInfo& i : *this ) - { - if ( i.id == id ) - { - return &i; - } - } - return nullptr; + auto [ i, p ] = indexById( id ); + return p; } /** @brief Checks if a given @p id is in the list of themes. */ From 0a88273e0d5899ad215f459b2ab60528919f8118 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 11:38:33 +0100 Subject: [PATCH 16/27] [plasmalnf] Replace combobox with a view --- src/modules/plasmalnf/PlasmaLnfPage.cpp | 34 +++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index cf1330912..20c2a5569 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -17,8 +17,7 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" -#include - +#include #include #include @@ -44,17 +43,24 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) } ) connect( this, &PlasmaLnfPage::plasmaThemeSelected, config, &Config::setTheme ); - QComboBox* box = new QComboBox(); - box->setModel( m_config->themeModel() ); - ui->verticalLayout->addWidget( box ); + QListView* view = new QListView( this ); + view->setUniformItemSizes( true ); + view->setModel( m_config->themeModel() ); + ui->verticalLayout->addWidget( view ); - connect( box, QOverload< int >::of( &QComboBox::currentIndexChanged ), [this]( int index ) { - auto* model = m_config->themeModel(); - auto id = model->data( model->index( index, 0 ), ThemesModel::KeyRole ).toString(); - cDebug() << "ComboBox selected" << index << id; - if ( !id.isEmpty() ) - { - emit plasmaThemeSelected( id ); - } - } ); + connect( view->selectionModel(), + &QItemSelectionModel::selectionChanged, + [this]( const QItemSelection& selected, const QItemSelection& ) { + auto i = selected.indexes(); + if ( !i.isEmpty() ) + { + auto* model = m_config->themeModel(); + auto id = model->data( i.first(), ThemesModel::KeyRole ).toString(); + cDebug() << "View selected" << selected << id; + if ( !id.isEmpty() ) + { + emit plasmaThemeSelected( id ); + } + } + } ); } From 04a6fbc4c412ce997142055291013d1d3f5fab3c Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 11:42:27 +0100 Subject: [PATCH 17/27] [plasmalnf] Fix debug-logging - ProcessResult isn't loggable, so operator bool() is called, so it logged 'false' on failure which isn't helpful. --- src/modules/plasmalnf/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index 123adecdb..e418e885b 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -150,7 +150,7 @@ Config::setTheme( const QString& id ) if ( r.getExitCode() ) { - cWarning() << r.explainProcess( command, std::chrono::seconds( 10 ) ); + cWarning() << "Failed (" << r.getExitCode() << ')'; } else { From 258a14bea2727d735d5ae5d1f6f98c47ade012c3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 11:56:09 +0100 Subject: [PATCH 18/27] [plasmalnf] Expose only the themes model - make ThemeInfo and ThemeInfoList internal, expose only ThemesModel to the rest of the PlasmaLnF module - don't build the widget anymore (needs to be replaced by a delegate) --- src/modules/plasmalnf/CMakeLists.txt | 1 - src/modules/plasmalnf/ThemeInfo.cpp | 100 +++++++++++++++++++++++---- src/modules/plasmalnf/ThemeInfo.h | 81 +--------------------- 3 files changed, 90 insertions(+), 92 deletions(-) diff --git a/src/modules/plasmalnf/CMakeLists.txt b/src/modules/plasmalnf/CMakeLists.txt index 027b3e12a..0860167ef 100644 --- a/src/modules/plasmalnf/CMakeLists.txt +++ b/src/modules/plasmalnf/CMakeLists.txt @@ -37,7 +37,6 @@ if ( KF5Plasma_FOUND AND KF5Package_FOUND ) PlasmaLnfPage.cpp PlasmaLnfJob.cpp ThemeInfo.cpp - ThemeWidget.cpp RESOURCES page_plasmalnf.qrc UI diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 2999a7cac..86f7ad344 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -11,22 +11,98 @@ #include #include +/** @brief describes a single plasma LnF theme. + * + * A theme description has an id, which is really the name of the desktop + * file (e.g. org.kde.breeze.desktop), a name which is human-readable and + * translated, and an optional image Page, which points to a local screenshot + * of that theme. + */ +struct ThemeInfo +{ + QString id; + QString name; + QString description; + QString imagePath; + bool show = true; + + ThemeInfo() {} + + explicit ThemeInfo( const QString& _id ) + : id( _id ) + { + } + + explicit ThemeInfo( const QString& _id, const QString& image ) + : id( _id ) + , imagePath( image ) + { + } + + explicit ThemeInfo( const KPluginMetaData& ); + + bool isValid() const { return !id.isEmpty(); } +}; + +class ThemeInfoList : public QList< ThemeInfo > +{ +public: + std::pair< int, const ThemeInfo* > indexById( const QString& id ) const + { + int index = 0; + for ( const ThemeInfo& i : *this ) + { + if ( i.id == id ) + { + return { index, &i }; + } + } + return { -1, nullptr }; + } + + std::pair< int, ThemeInfo* > indexById( const QString& id ) + { + // Call the const version and then munge the types + auto [ i, p ] = const_cast< const ThemeInfoList* >( this )->indexById( id ); + return { i, const_cast< ThemeInfo* >( p ) }; + } + + + /** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */ + ThemeInfo* findById( const QString& id ) + { + auto [ i, p ] = indexById( id ); + return p; + } + + /** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */ + const ThemeInfo* findById( const QString& id ) const + { + auto [ i, p ] = indexById( id ); + return p; + } + + /** @brief Checks if a given @p id is in the list of themes. */ + bool contains( const QString& id ) const { return findById( id ) != nullptr; } +}; + ThemesModel::ThemesModel( QObject* parent ) : QAbstractListModel( parent ) + , m_themes( new ThemeInfoList ) { auto packages = KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" ); - m_themes.reserve( packages.length() ); + m_themes->reserve( packages.length() ); for ( const auto& p : packages ) { - m_themes.append( ThemeInfo { p } ); + m_themes->append( ThemeInfo { p } ); } } int ThemesModel::rowCount( const QModelIndex& ) const { - return m_themes.count(); + return m_themes->count(); } QVariant @@ -36,12 +112,12 @@ ThemesModel::data( const QModelIndex& index, int role ) const { return QVariant(); } - if ( index.row() < 0 || index.row() >= m_themes.count() ) + if ( index.row() < 0 || index.row() >= m_themes->count() ) { return QVariant(); } - const auto& item = m_themes.at( index.row() ); + const auto& item = m_themes->at( index.row() ); switch ( role ) { case LabelRole: @@ -65,7 +141,7 @@ ThemesModel::roleNames() const void ThemesModel::setThemeImage( const QString& id, const QString& imagePath ) { - auto [ i, theme ] = m_themes.indexById( id ); + auto [ i, theme ] = m_themes->indexById( id ); if ( theme ) { theme->imagePath = imagePath; @@ -76,7 +152,7 @@ ThemesModel::setThemeImage( const QString& id, const QString& imagePath ) void ThemesModel::setThemeImage( const QMap< QString, QString >& images ) { - if ( m_themes.isEmpty() ) + if ( m_themes->isEmpty() ) { return; } @@ -89,13 +165,13 @@ ThemesModel::setThemeImage( const QMap< QString, QString >& images ) setThemeImage( k, images[ k ] ); } } - emit dataChanged( index( 0, 0 ), index( m_themes.count() - 1 ), { ImageRole } ); + emit dataChanged( index( 0, 0 ), index( m_themes->count() - 1 ), { ImageRole } ); } void ThemesModel::showTheme( const QString& id, bool show ) { - auto [ i, theme ] = m_themes.indexById( id ); + auto [ i, theme ] = m_themes->indexById( id ); if ( theme ) { theme->show = show; @@ -106,18 +182,18 @@ ThemesModel::showTheme( const QString& id, bool show ) void ThemesModel::showOnlyThemes( const QMap< QString, QString >& onlyThese ) { - if ( m_themes.isEmpty() ) + if ( m_themes->isEmpty() ) { return; } // No signal blocker block needed here because we're not calling showTheme() // QSignalBlocker b( this ); - for ( auto& t : m_themes ) + for ( auto& t : *m_themes ) { t.show = onlyThese.contains( t.id ); } - emit dataChanged( index( 0, 0 ), index( m_themes.count() - 1 ), { ShownRole } ); + emit dataChanged( index( 0, 0 ), index( m_themes->count() - 1 ), { ShownRole } ); } diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index 059858617..474bb3ff8 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -14,82 +14,7 @@ #include #include -class KPluginMetaData; - -/** @brief describes a single plasma LnF theme. - * - * A theme description has an id, which is really the name of the desktop - * file (e.g. org.kde.breeze.desktop), a name which is human-readable and - * translated, and an optional image Page, which points to a local screenshot - * of that theme. - */ -struct ThemeInfo -{ - QString id; - QString name; - QString description; - QString imagePath; - bool show = true; - - ThemeInfo() {} - - explicit ThemeInfo( const QString& _id ) - : id( _id ) - { - } - - explicit ThemeInfo( const QString& _id, const QString& image ) - : id( _id ) - , imagePath( image ) - { - } - - explicit ThemeInfo( const KPluginMetaData& ); - - bool isValid() const { return !id.isEmpty(); } -}; - -class ThemeInfoList : public QList< ThemeInfo > -{ -public: - std::pair< int, const ThemeInfo* > indexById( const QString& id ) const - { - int index = 0; - for ( const ThemeInfo& i : *this ) - { - if ( i.id == id ) - { - return { index, &i }; - } - } - return { -1, nullptr }; - } - - std::pair< int, ThemeInfo* > indexById( const QString& id ) - { - // Call the const version and then munge the types - auto [ i, p ] = const_cast< const ThemeInfoList* >( this )->indexById( id ); - return { i, const_cast< ThemeInfo* >( p ) }; - } - - - /** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */ - ThemeInfo* findById( const QString& id ) - { - auto [ i, p ] = indexById( id ); - return p; - } - - /** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */ - const ThemeInfo* findById( const QString& id ) const - { - auto [ i, p ] = indexById( id ); - return p; - } - - /** @brief Checks if a given @p id is in the list of themes. */ - bool contains( const QString& id ) const { return findById( id ) != nullptr; } -}; +class ThemeInfoList; class ThemesModel : public QAbstractListModel { @@ -111,8 +36,6 @@ public: QHash< int, QByteArray > roleNames() const override; - const ThemeInfo* findById( const QString& id ) const { return m_themes.findById( id ); } - /// @brief Set the screenshot to go with the given @p id void setThemeImage( const QString& id, const QString& imagePath ); @@ -126,7 +49,7 @@ public: void showOnlyThemes( const QMap< QString, QString >& onlyThese ); private: - ThemeInfoList m_themes; + ThemeInfoList* m_themes; }; From 58ea40c14d6933fe9fd591b746c7ba64d2c9f8d8 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 12:41:50 +0100 Subject: [PATCH 19/27] [plasmalnf] Add a description - add a role for description - change view to a table view --- src/modules/plasmalnf/PlasmaLnfPage.cpp | 12 ++++++------ src/modules/plasmalnf/ThemeInfo.cpp | 2 ++ src/modules/plasmalnf/ThemeInfo.h | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index 20c2a5569..3dc367fe5 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -17,10 +17,9 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" -#include - -#include -#include +#include +#include +#include PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) : QWidget( parent ) @@ -43,8 +42,9 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) } ) connect( this, &PlasmaLnfPage::plasmaThemeSelected, config, &Config::setTheme ); - QListView* view = new QListView( this ); - view->setUniformItemSizes( true ); + QTableView* view = new QTableView( this ); + view->verticalHeader()->hide(); + view->horizontalHeader()->hide(); view->setModel( m_config->themeModel() ); ui->verticalLayout->addWidget( view ); diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 86f7ad344..da5ca7f44 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -126,6 +126,8 @@ ThemesModel::data( const QModelIndex& index, int role ) const return item.id; case ShownRole: return item.show; + case DescriptionRole: + return item.description; default: return QVariant(); } diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index 474bb3ff8..0c4f2fd34 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -26,6 +26,7 @@ public: LabelRole = Qt::DisplayRole, KeyRole = Qt::UserRole, ShownRole, + DescriptionRole, ImageRole }; From faa1cb6b652ae96653496782cd1a8b4c82aedb6c Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 14:32:50 +0100 Subject: [PATCH 20/27] [plasmalnf] Demand-load image for a theme --- src/modules/plasmalnf/CMakeLists.txt | 15 ++++- src/modules/plasmalnf/PlasmaLnfPage.cpp | 44 +++++++++++++- src/modules/plasmalnf/ThemeInfo.cpp | 78 +++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 5 deletions(-) diff --git a/src/modules/plasmalnf/CMakeLists.txt b/src/modules/plasmalnf/CMakeLists.txt index 0860167ef..9e89ec555 100644 --- a/src/modules/plasmalnf/CMakeLists.txt +++ b/src/modules/plasmalnf/CMakeLists.txt @@ -10,22 +10,30 @@ find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE) set( lnf_ver 5.41 ) find_package( KF5Config ${lnf_ver} ) -find_package( KF5Plasma ${lnf_ver} ) -find_package( KF5Package ${lnf_ver} ) set_package_properties( KF5Config PROPERTIES PURPOSE "For finding default Plasma Look-and-Feel" ) + +find_package( KF5Plasma ${lnf_ver} ) set_package_properties( KF5Plasma PROPERTIES PURPOSE "For Plasma Look-and-Feel selection" ) + +find_package( KF5Package ${lnf_ver} ) set_package_properties( KF5Package PROPERTIES PURPOSE "For Plasma Look-and-Feel selection" ) -if ( KF5Plasma_FOUND AND KF5Package_FOUND ) +find_package( KF5ItemModels ${lnf_ver} ) +set_package_properties( + KF5ItemModels PROPERTIES + PURPOSE "For Plasma Look-and-Feel display" +) + +if ( KF5Plasma_FOUND AND KF5Package_FOUND AND KF5ItemModels_FOUND ) calamares_add_plugin( plasmalnf TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO @@ -43,6 +51,7 @@ if ( KF5Plasma_FOUND AND KF5Package_FOUND ) page_plasmalnf.ui LINK_PRIVATE_LIBRARIES calamaresui + KF5::ItemModels KF5::Package KF5::Plasma SHARED_LIB diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index 3dc367fe5..f832de261 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -17,10 +17,47 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" +#include + #include #include #include +class ThemeColumns : public KExtraColumnsProxyModel +{ +public: + ThemeColumns( QObject* parent ); + + QVariant extraColumnData( const QModelIndex& parent, int row, int extraColumn, int role ) const override; +}; + +ThemeColumns::ThemeColumns( QObject* parent ) + : KExtraColumnsProxyModel( parent ) +{ + appendColumn(); + appendColumn(); +} + +QVariant +ThemeColumns::extraColumnData( const QModelIndex& parent, int row, int extraColumn, int role ) const +{ + if ( role != Qt::DisplayRole ) + { + return QVariant(); + } + switch ( extraColumn ) + { + case 0: + return sourceModel()->data( sourceModel()->index( row, 0 ), ThemesModel::DescriptionRole ); + case 1: + return sourceModel()->data( sourceModel()->index( row, 0 ), ThemesModel::ImageRole ); + default: + return QVariant(); + } + __builtin_unreachable(); +} + + PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) : QWidget( parent ) , ui( new Ui::PlasmaLnfPage ) @@ -43,9 +80,11 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) connect( this, &PlasmaLnfPage::plasmaThemeSelected, config, &Config::setTheme ); QTableView* view = new QTableView( this ); + ThemeColumns* model = new ThemeColumns( this ); + model->setSourceModel( m_config->themeModel() ); + view->setModel( model ); view->verticalHeader()->hide(); view->horizontalHeader()->hide(); - view->setModel( m_config->themeModel() ); ui->verticalLayout->addWidget( view ); connect( view->selectionModel(), @@ -54,8 +93,9 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) auto i = selected.indexes(); if ( !i.isEmpty() ) { + auto row = i.first().row(); auto* model = m_config->themeModel(); - auto id = model->data( i.first(), ThemesModel::KeyRole ).toString(); + auto id = model->data( model->index( row, 0 ), ThemesModel::KeyRole ).toString(); cDebug() << "View selected" << selected << id; if ( !id.isEmpty() ) { diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index da5ca7f44..69f6818d4 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -8,9 +8,17 @@ */ #include "ThemeInfo.h" +#include "Branding.h" +#include "utils/CalamaresUtilsGui.h" +#include "utils/Logger.h" + #include #include +#include +#include +#include + /** @brief describes a single plasma LnF theme. * * A theme description has an id, which is really the name of the desktop @@ -24,6 +32,7 @@ struct ThemeInfo QString name; QString description; QString imagePath; + mutable QPixmap pixmap; bool show = true; ThemeInfo() {} @@ -42,6 +51,9 @@ struct ThemeInfo explicit ThemeInfo( const KPluginMetaData& ); bool isValid() const { return !id.isEmpty(); } + + /// @brief Fill in the pixmap member based on imagePath + QPixmap loadImage() const; }; class ThemeInfoList : public QList< ThemeInfo > @@ -128,6 +140,8 @@ ThemesModel::data( const QModelIndex& index, int role ) const return item.show; case DescriptionRole: return item.description; + case ImageRole: + return item.loadImage(); default: return QVariant(); } @@ -198,6 +212,39 @@ ThemesModel::showOnlyThemes( const QMap< QString, QString >& onlyThese ) emit dataChanged( index( 0, 0 ), index( m_themes->count() - 1 ), { ShownRole } ); } +/** + * Massage the given @p path to the most-likely + * path that actually contains a screenshot. For + * empty image paths, returns the QRC path for an + * empty screenshot. Returns blank if the path + * doesn't exist anywhere in the search paths. + */ +static QString +munge_imagepath( const QString& path ) +{ + if ( path.isEmpty() ) + { + return ":/view-preview.png"; + } + + if ( path.startsWith( '/' ) ) + { + return path; + } + + if ( QFileInfo::exists( path ) ) + { + return path; + } + + QFileInfo fi( QDir( Calamares::Branding::instance()->componentDirectory() ), path ); + if ( fi.exists() ) + { + return fi.absoluteFilePath(); + } + + return QString(); +} ThemeInfo::ThemeInfo( const KPluginMetaData& data ) : id( data.pluginId() ) @@ -205,3 +252,34 @@ ThemeInfo::ThemeInfo( const KPluginMetaData& data ) , description( data.description() ) { } + +QPixmap +ThemeInfo::loadImage() const +{ + if ( pixmap.isNull() ) + { + + const QSize image_size { qMax( 12 * CalamaresUtils::defaultFontHeight(), 120 ), + qMax( 8 * CalamaresUtils::defaultFontHeight(), 80 ) }; + + const QString path = munge_imagepath( imagePath ); + cDebug() << "Loading initial image for" << id << imagePath << "->" << path; + QPixmap image( path ); + if ( image.isNull() ) + { + // Not found or not specified, so convert the name into some (horrible, likely) + // color instead. + image = QPixmap( image_size ); + auto hash_color = qHash( imagePath.isEmpty() ? id : imagePath ); + cDebug() << Logger::SubEntry << "Theme image" << imagePath << "not found, hash" << hash_color; + image.fill( QColor( QRgb( hash_color ) ) ); + } + else + { + cDebug() << Logger::SubEntry << "Theme image" << image.size(); + } + + pixmap = image.scaled( image_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + } + return pixmap; +} From 06cbabd189b59953a2af3f6216f861ca4534c906 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 17 Nov 2020 14:40:21 +0100 Subject: [PATCH 21/27] [plasmalnf] Simplify (warnings--, debug--) --- src/modules/plasmalnf/PlasmaLnfPage.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index f832de261..c4ecf94b7 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -39,7 +39,7 @@ ThemeColumns::ThemeColumns( QObject* parent ) } QVariant -ThemeColumns::extraColumnData( const QModelIndex& parent, int row, int extraColumn, int role ) const +ThemeColumns::extraColumnData( const QModelIndex&, int row, int extraColumn, int role ) const { if ( role != Qt::DisplayRole ) { @@ -80,9 +80,9 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) connect( this, &PlasmaLnfPage::plasmaThemeSelected, config, &Config::setTheme ); QTableView* view = new QTableView( this ); - ThemeColumns* model = new ThemeColumns( this ); - model->setSourceModel( m_config->themeModel() ); - view->setModel( model ); + ThemeColumns* columnsModel = new ThemeColumns( this ); + columnsModel->setSourceModel( m_config->themeModel() ); + view->setModel( columnsModel ); view->verticalHeader()->hide(); view->horizontalHeader()->hide(); ui->verticalLayout->addWidget( view ); @@ -96,7 +96,6 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) auto row = i.first().row(); auto* model = m_config->themeModel(); auto id = model->data( model->index( row, 0 ), ThemesModel::KeyRole ).toString(); - cDebug() << "View selected" << selected << id; if ( !id.isEmpty() ) { emit plasmaThemeSelected( id ); From dac590a0948034b9b003ba5f8f13187f781473ad Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sat, 28 Nov 2020 16:53:35 +0100 Subject: [PATCH 22/27] [plasmalnf] Rip out the intermediate model again, in prep for a delegate --- src/modules/plasmalnf/CMakeLists.txt | 9 +----- src/modules/plasmalnf/PlasmaLnfPage.cpp | 43 ++----------------------- src/modules/plasmalnf/PlasmaLnfPage.h | 3 -- 3 files changed, 3 insertions(+), 52 deletions(-) diff --git a/src/modules/plasmalnf/CMakeLists.txt b/src/modules/plasmalnf/CMakeLists.txt index 9e89ec555..3a85d9598 100644 --- a/src/modules/plasmalnf/CMakeLists.txt +++ b/src/modules/plasmalnf/CMakeLists.txt @@ -27,13 +27,7 @@ set_package_properties( PURPOSE "For Plasma Look-and-Feel selection" ) -find_package( KF5ItemModels ${lnf_ver} ) -set_package_properties( - KF5ItemModels PROPERTIES - PURPOSE "For Plasma Look-and-Feel display" -) - -if ( KF5Plasma_FOUND AND KF5Package_FOUND AND KF5ItemModels_FOUND ) +if ( KF5Plasma_FOUND AND KF5Package_FOUND ) calamares_add_plugin( plasmalnf TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO @@ -51,7 +45,6 @@ if ( KF5Plasma_FOUND AND KF5Package_FOUND AND KF5ItemModels_FOUND ) page_plasmalnf.ui LINK_PRIVATE_LIBRARIES calamaresui - KF5::ItemModels KF5::Package KF5::Plasma SHARED_LIB diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index c4ecf94b7..ac73ee42a 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -17,46 +17,10 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" -#include - #include #include #include -class ThemeColumns : public KExtraColumnsProxyModel -{ -public: - ThemeColumns( QObject* parent ); - - QVariant extraColumnData( const QModelIndex& parent, int row, int extraColumn, int role ) const override; -}; - -ThemeColumns::ThemeColumns( QObject* parent ) - : KExtraColumnsProxyModel( parent ) -{ - appendColumn(); - appendColumn(); -} - -QVariant -ThemeColumns::extraColumnData( const QModelIndex&, int row, int extraColumn, int role ) const -{ - if ( role != Qt::DisplayRole ) - { - return QVariant(); - } - switch ( extraColumn ) - { - case 0: - return sourceModel()->data( sourceModel()->index( row, 0 ), ThemesModel::DescriptionRole ); - case 1: - return sourceModel()->data( sourceModel()->index( row, 0 ), ThemesModel::ImageRole ); - default: - return QVariant(); - } - __builtin_unreachable(); -} - PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) : QWidget( parent ) @@ -77,12 +41,9 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) "once the system is installed. Clicking on a look-and-feel " "selection will give you a live preview of that look-and-feel." ) ); } ) - connect( this, &PlasmaLnfPage::plasmaThemeSelected, config, &Config::setTheme ); QTableView* view = new QTableView( this ); - ThemeColumns* columnsModel = new ThemeColumns( this ); - columnsModel->setSourceModel( m_config->themeModel() ); - view->setModel( columnsModel ); + view->setModel( m_config->themeModel() ); view->verticalHeader()->hide(); view->horizontalHeader()->hide(); ui->verticalLayout->addWidget( view ); @@ -98,7 +59,7 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) auto id = model->data( model->index( row, 0 ), ThemesModel::KeyRole ).toString(); if ( !id.isEmpty() ) { - emit plasmaThemeSelected( id ); + m_config->setTheme( id ); } } } ); diff --git a/src/modules/plasmalnf/PlasmaLnfPage.h b/src/modules/plasmalnf/PlasmaLnfPage.h index 9afda305c..f04ecde06 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.h +++ b/src/modules/plasmalnf/PlasmaLnfPage.h @@ -38,9 +38,6 @@ class PlasmaLnfPage : public QWidget public: explicit PlasmaLnfPage( Config* config, QWidget* parent = nullptr ); -signals: - void plasmaThemeSelected( const QString& id ); - private: Ui::PlasmaLnfPage* ui; Config* m_config; From cc6611bac4aef55184a6d4ea4f6dc2a60218ce43 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 30 Nov 2020 10:46:46 +0100 Subject: [PATCH 23/27] [plasmalnf] Make 'the size of screenshots' available outside ThemeInfo --- src/modules/plasmalnf/ThemeInfo.cpp | 11 +++++++++-- src/modules/plasmalnf/ThemeInfo.h | 8 ++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 69f6818d4..8c922ceef 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -212,6 +212,14 @@ ThemesModel::showOnlyThemes( const QMap< QString, QString >& onlyThese ) emit dataChanged( index( 0, 0 ), index( m_themes->count() - 1 ), { ShownRole } ); } +QSize +ThemesModel::imageSize() +{ + return { qMax( 12 * CalamaresUtils::defaultFontHeight(), 120 ), + qMax( 8 * CalamaresUtils::defaultFontHeight(), 80 ) }; +} + + /** * Massage the given @p path to the most-likely * path that actually contains a screenshot. For @@ -259,8 +267,7 @@ ThemeInfo::loadImage() const if ( pixmap.isNull() ) { - const QSize image_size { qMax( 12 * CalamaresUtils::defaultFontHeight(), 120 ), - qMax( 8 * CalamaresUtils::defaultFontHeight(), 80 ) }; + const QSize image_size( ThemesModel::imageSize() ); const QString path = munge_imagepath( imagePath ); cDebug() << "Loading initial image for" << id << imagePath << "->" << path; diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index 0c4f2fd34..eab2bba6c 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -49,6 +49,14 @@ public: /// @brief Shows the keys in the @p onlyThese map, and hides the rest void showOnlyThemes( const QMap< QString, QString >& onlyThese ); + /** @brief The size of theme Images + * + * The size is dependent on the font size used by Calamares, + * and is constant within one run of Calamares, but may change + * if the font settings do between runs. + */ + static QSize imageSize(); + private: ThemeInfoList* m_themes; }; From cf538fb8373da406ff3b2b83afe8fabc466c4cec Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 30 Nov 2020 11:19:00 +0100 Subject: [PATCH 24/27] [plasmalnf] Implement a delegate for drawing the list of themes --- src/modules/plasmalnf/PlasmaLnfPage.cpp | 52 +++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index ac73ee42a..b652e820c 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -18,8 +18,52 @@ #include "utils/Retranslator.h" #include +#include #include -#include + +class ThemeDelegate : public QStyledItemDelegate +{ +public: + using QStyledItemDelegate::QStyledItemDelegate; + + void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override; + // The size of the item is constant + QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const override; +}; + +QSize +ThemeDelegate::sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const +{ + QSize image( ThemesModel::imageSize() ); + return { 3 * image.width(), image.height() }; +} + +void +ThemeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + auto label = index.data( ThemesModel::LabelRole ).toString(); + auto description = index.data( ThemesModel::DescriptionRole ).toString(); + auto image_v = index.data( ThemesModel::ImageRole ); + QPixmap image = image_v.canConvert< QPixmap >() ? qvariant_cast< QPixmap >( image_v ) : QPixmap(); + + // The delegate paints three "columns", each of which takes 1/3 + // of the space: label, description and screenshot. + QRect labelRect( option.rect ); + labelRect.setWidth( labelRect.width() / 3 ); + + QStyleOptionButton rbOption; + rbOption.state |= QStyle::State_Enabled | QStyle::State_On; + rbOption.rect = labelRect; + rbOption.text = label; + option.widget->style()->drawControl( QStyle::CE_RadioButton, &rbOption, painter, option.widget ); + + labelRect.moveLeft( labelRect.width() ); + option.widget->style()->drawItemText( + painter, labelRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, option.palette, false, description ); + + labelRect.moveLeft( 2 * labelRect.width() ); + option.widget->style()->drawItemPixmap( painter, labelRect, Qt::AlignHCenter | Qt::AlignVCenter, image ); +} PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) @@ -42,10 +86,10 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) "selection will give you a live preview of that look-and-feel." ) ); } ) - QTableView* view = new QTableView( this ); + auto* view = new QListView( this ); view->setModel( m_config->themeModel() ); - view->verticalHeader()->hide(); - view->horizontalHeader()->hide(); + view->setItemDelegate( new ThemeDelegate( view ) ); + view->setUniformItemSizes( true ); ui->verticalLayout->addWidget( view ); connect( view->selectionModel(), From da4f8fffcf4340f6a8f3270413011cc7ab5d1a27 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 30 Nov 2020 11:31:44 +0100 Subject: [PATCH 25/27] [plasmalnf] Give the theme list plenty of space --- src/modules/plasmalnf/PlasmaLnfPage.cpp | 1 + src/modules/plasmalnf/page_plasmalnf.ui | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index b652e820c..fc3be4471 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -90,6 +90,7 @@ PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent ) view->setModel( m_config->themeModel() ); view->setItemDelegate( new ThemeDelegate( view ) ); view->setUniformItemSizes( true ); + view->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); ui->verticalLayout->addWidget( view ); connect( view->selectionModel(), diff --git a/src/modules/plasmalnf/page_plasmalnf.ui b/src/modules/plasmalnf/page_plasmalnf.ui index 88d5a39a2..b079013d6 100644 --- a/src/modules/plasmalnf/page_plasmalnf.ui +++ b/src/modules/plasmalnf/page_plasmalnf.ui @@ -28,19 +28,6 @@ SPDX-License-Identifier: GPL-3.0-or-later - - - - Qt::Vertical - - - - 20 - 40 - - - - From bcff0454a30afe52d4e71e63f4f12f84adf22770 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 30 Nov 2020 12:11:11 +0100 Subject: [PATCH 26/27] [plasmalnf] Give the themes a selected-state - This kind of runs around the selection model on the view, but we're drawing radio buttons ourselves **anyway** and the list of themes knows which is selected / current independent of the view. --- src/modules/plasmalnf/Config.cpp | 3 +++ src/modules/plasmalnf/PlasmaLnfPage.cpp | 3 ++- src/modules/plasmalnf/ThemeInfo.cpp | 29 ++++++++++++++++++++++++- src/modules/plasmalnf/ThemeInfo.h | 12 +++++++++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/modules/plasmalnf/Config.cpp b/src/modules/plasmalnf/Config.cpp index e418e885b..e022109b4 100644 --- a/src/modules/plasmalnf/Config.cpp +++ b/src/modules/plasmalnf/Config.cpp @@ -98,6 +98,8 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) m_themeModel->showOnlyThemes( listedThemes ); } } + + m_themeModel->select( m_preselectThemeId ); } Calamares::JobList @@ -157,5 +159,6 @@ Config::setTheme( const QString& id ) cDebug() << "Plasma look-and-feel applied" << id; } } + m_themeModel->select( id ); emit themeChanged( id ); } diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index fc3be4471..0e7f05e43 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -43,6 +43,7 @@ ThemeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, con { auto label = index.data( ThemesModel::LabelRole ).toString(); auto description = index.data( ThemesModel::DescriptionRole ).toString(); + auto selected = index.data( ThemesModel::SelectedRole ).toBool() ? QStyle::State_On : QStyle::State_Off; auto image_v = index.data( ThemesModel::ImageRole ); QPixmap image = image_v.canConvert< QPixmap >() ? qvariant_cast< QPixmap >( image_v ) : QPixmap(); @@ -52,7 +53,7 @@ ThemeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, con labelRect.setWidth( labelRect.width() / 3 ); QStyleOptionButton rbOption; - rbOption.state |= QStyle::State_Enabled | QStyle::State_On; + rbOption.state |= QStyle::State_Enabled | selected; rbOption.rect = labelRect; rbOption.text = label; option.widget->style()->drawControl( QStyle::CE_RadioButton, &rbOption, painter, option.widget ); diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 8c922ceef..77f0a30ab 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -34,6 +34,7 @@ struct ThemeInfo QString imagePath; mutable QPixmap pixmap; bool show = true; + bool selected = false; ThemeInfo() {} @@ -138,6 +139,8 @@ ThemesModel::data( const QModelIndex& index, int role ) const return item.id; case ShownRole: return item.show; + case SelectedRole: + return item.selected; case DescriptionRole: return item.description; case ImageRole: @@ -151,7 +154,11 @@ ThemesModel::data( const QModelIndex& index, int role ) const QHash< int, QByteArray > ThemesModel::roleNames() const { - return { { LabelRole, "label" }, { KeyRole, "key" }, { ShownRole, "show" }, { ImageRole, "image" } }; + return { { LabelRole, "label" }, + { KeyRole, "key" }, + { SelectedRole, "selected" }, + { ShownRole, "show" }, + { ImageRole, "image" } }; } void @@ -219,6 +226,26 @@ ThemesModel::imageSize() qMax( 8 * CalamaresUtils::defaultFontHeight(), 80 ) }; } +void +ThemesModel::select( const QString& themeId ) +{ + int i = 0; + for ( auto& t : *m_themes ) + { + if ( t.selected && t.id != themeId ) + { + t.selected = false; + emit dataChanged( index( i, 0 ), index( i, 0 ), { SelectedRole } ); + } + if ( !t.selected && t.id == themeId ) + { + t.selected = true; + emit dataChanged( index( i, 0 ), index( i, 0 ), { SelectedRole } ); + } + ++i; + } +} + /** * Massage the given @p path to the most-likely diff --git a/src/modules/plasmalnf/ThemeInfo.h b/src/modules/plasmalnf/ThemeInfo.h index eab2bba6c..c859bcd2d 100644 --- a/src/modules/plasmalnf/ThemeInfo.h +++ b/src/modules/plasmalnf/ThemeInfo.h @@ -25,7 +25,8 @@ public: { LabelRole = Qt::DisplayRole, KeyRole = Qt::UserRole, - ShownRole, + ShownRole, // Should theme be displayed + SelectedRole, // Is theme selected DescriptionRole, ImageRole }; @@ -49,6 +50,15 @@ public: /// @brief Shows the keys in the @p onlyThese map, and hides the rest void showOnlyThemes( const QMap< QString, QString >& onlyThese ); + /** @brief Mark the @p themeId as current / selected + * + * One theme can be selected at a time; this will emit data + * changed signals for any (one) theme already selected, and + * the newly-selected theme. If @p themeId does not name any + * theme, none are selected. + */ + void select( const QString& themeId ); + /** @brief The size of theme Images * * The size is dependent on the font size used by Calamares, From fb9fa347a0f8c9ee62b3ed1496c801c20dffbb1a Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 30 Nov 2020 12:29:47 +0100 Subject: [PATCH 27/27] [plasmalnf] Fix iteration `for k : images` iterates over the values in the map, while we need both the key (the theme-id) and the value (the image to hand to that theme). --- src/modules/plasmalnf/ThemeInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/plasmalnf/ThemeInfo.cpp b/src/modules/plasmalnf/ThemeInfo.cpp index 77f0a30ab..82da064be 100644 --- a/src/modules/plasmalnf/ThemeInfo.cpp +++ b/src/modules/plasmalnf/ThemeInfo.cpp @@ -183,9 +183,9 @@ ThemesModel::setThemeImage( const QMap< QString, QString >& images ) // Don't emit signals from each call, aggregate to one call (below this block) { QSignalBlocker b( this ); - for ( const auto& k : images ) + for ( auto k = images.constKeyValueBegin(); k != images.constKeyValueEnd(); ++k ) { - setThemeImage( k, images[ k ] ); + setThemeImage( k->first, k->second ); } } emit dataChanged( index( 0, 0 ), index( m_themes->count() - 1 ), { ImageRole } );