diff --git a/Dockerfile b/Dockerfile index cd0e4f365..a4d424f45 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,2 +1,2 @@ -FROM kdeneon/all +FROM kdeneon/all:dev-stable RUN sudo apt-get update && sudo apt-get -y install build-essential cmake extra-cmake-modules gettext kio-dev libatasmart-dev libboost-python-dev libkf5config-dev libkf5coreaddons-dev libkf5i18n-dev libkf5iconthemes-dev libkf5parts-dev libkf5service-dev libkf5solid-dev libkpmcore-dev libparted-dev libpolkit-qt5-1-dev libqt5svg5-dev libqt5webkit5-dev libyaml-cpp-dev os-prober pkg-config python3-dev qtbase5-dev qtdeclarative5-dev qttools5-dev qttools5-dev-tools diff --git a/src/modules/locale/LocaleConfiguration.cpp b/src/modules/locale/LocaleConfiguration.cpp index b8f5f6a9e..c612c50c4 100644 --- a/src/modules/locale/LocaleConfiguration.cpp +++ b/src/modules/locale/LocaleConfiguration.cpp @@ -43,9 +43,11 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale, const QStringList& availableLocales, const QString& countryCode ) { - LocaleConfiguration lc = LocaleConfiguration(); + LocaleConfiguration lc; + + // Note that the documentation how this works is in packages.conf QString language = languageLocale.split( '_' ).first(); - lc.myLanguageLocaleBcp47 = QLocale(language).bcp47Name(); + lc.myLanguageLocaleBcp47 = QLocale(language).bcp47Name().toLower(); QStringList linesForLanguage; for ( const QString &line : availableLocales ) @@ -288,7 +290,7 @@ LocaleConfiguration::isEmpty() const QMap< QString, QString > -LocaleConfiguration::toMap() +LocaleConfiguration::toMap() const { QMap< QString, QString > map; @@ -324,3 +326,9 @@ LocaleConfiguration::toMap() return map; } + +QString +LocaleConfiguration::toBcp47() const +{ + return myLanguageLocaleBcp47; +} diff --git a/src/modules/locale/LocaleConfiguration.h b/src/modules/locale/LocaleConfiguration.h index 073d19a5b..04d1db456 100644 --- a/src/modules/locale/LocaleConfiguration.h +++ b/src/modules/locale/LocaleConfiguration.h @@ -35,16 +35,21 @@ public: bool isEmpty() const; + QMap< QString, QString > toMap() const; + // Note that the documentation how this works is in packages.conf + QString toBcp47() const; + // These become all uppercase in locale.conf, but we keep them lowercase here to // avoid confusion with locale.h. QString lang, lc_numeric, lc_time, lc_monetary, lc_paper, lc_name, lc_address, lc_telephone, lc_measurement, lc_identification; - QString myLanguageLocaleBcp47; - QMap< QString, QString > toMap(); // If the user has explicitly selected language (from the dialog) // or numbers format, set these to avoid implicit changes to them. bool explicit_lang, explicit_lc; + +private: + QString myLanguageLocaleBcp47; }; #endif // LOCALECONFIGURATION_H diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp index 2172586ff..8b05ccfba 100644 --- a/src/modules/locale/LocalePage.cpp +++ b/src/modules/locale/LocalePage.cpp @@ -489,8 +489,10 @@ LocalePage::updateGlobalStorage() ->insert( "locationRegion", location.region ); Calamares::JobQueue::instance()->globalStorage() ->insert( "locationZone", location.zone ); - Calamares::JobQueue::instance()->globalStorage() - ->insert( "locale", m_selectedLocaleConfiguration.myLanguageLocaleBcp47); + + const QString bcp47 = m_selectedLocaleConfiguration.toBcp47(); + Calamares::JobQueue::instance()->globalStorage()->insert( "locale", bcp47 ); + cDebug() << "Updated locale globals, BCP47=" << bcp47; // If we're in chroot mode (normal install mode), then we immediately set the // timezone on the live system. diff --git a/src/modules/locale/locale.conf b/src/modules/locale/locale.conf index 54a7b584c..459dceb38 100644 --- a/src/modules/locale/locale.conf +++ b/src/modules/locale/locale.conf @@ -20,20 +20,24 @@ zone: "New_York" # GeoIP settings. Leave commented out to disable GeoIP. # # An HTTP request is made to *geoipUrl* -- depending on the geoipStyle, -# the URL may be modified before use. The request must return -# valid JSON data in the FreeGeoIP format; there should -# be an attribute *time_zone*, with a string value set to the -# timezone, in / format. +# the URL may be modified before use. The request should return +# valid data in a suitable format, depending on geoipStyle; +# generally this includes a string value with the timezone +# in / format. # # Note that this example URL works, but the service is shutting # down in June 2018. # -# Suitable data looks like +# Suitable JSON data looks like # ``` # {"time_zone":"America/New_York"} # ``` +# Suitable XML data looks like +# ``` +# Europe/Brussels +# ``` # -#geoipUrl: "freegeoip.net/json" +#geoipUrl: "freegeoip.net" # GeoIP style. Leave commented out for the "legacy" interpretation. # This setting only makes sense if geoipUrl is set, enabliing geoIP. diff --git a/src/modules/packages/main.py b/src/modules/packages/main.py index 60ede34fa..f252bc15f 100644 --- a/src/modules/packages/main.py +++ b/src/modules/packages/main.py @@ -318,7 +318,10 @@ def subst_locale(plist): """ locale = libcalamares.globalstorage.value("locale") if not locale: - return plist + # It is possible to skip the locale-setting entirely. + # Then pretend it is "en", so that {LOCALE}-decorated + # package names are removed from the list. + locale = "en" ret = [] for packagedata in plist: @@ -364,20 +367,20 @@ def run_operations(pkgman, entry): global group_packages, completed_packages, mode_packages for key in entry.keys(): - entry[key] = subst_locale(entry[key]) - group_packages = len(entry[key]) + package_list = subst_locale(entry[key]) + group_packages = len(package_list) if key == "install": _change_mode(INSTALL) - if all([isinstance(x, str) for x in entry[key]]): - pkgman.install(entry[key]) + if all([isinstance(x, str) for x in package_list]): + pkgman.install(package_list) else: - for package in entry[key]: + for package in package_list: pkgman.install_package(package) elif key == "try_install": _change_mode(INSTALL) # we make a separate package manager call for each package so a # single failing package won't stop all of them - for package in entry[key]: + for package in package_list: try: pkgman.install_package(package) except subprocess.CalledProcessError: @@ -386,10 +389,10 @@ def run_operations(pkgman, entry): libcalamares.utils.debug(warn_text) elif key == "remove": _change_mode(REMOVE) - pkgman.remove(entry[key]) + pkgman.remove(package_list) elif key == "try_remove": _change_mode(REMOVE) - for package in entry[key]: + for package in package_list: try: pkgman.remove([package]) except subprocess.CalledProcessError: @@ -398,9 +401,9 @@ def run_operations(pkgman, entry): libcalamares.utils.debug(warn_text) elif key == "localInstall": _change_mode(INSTALL) - pkgman.install(entry[key], from_local=True) + pkgman.install(package_list, from_local=True) - completed_packages += len(entry[key]) + completed_packages += len(package_list) libcalamares.job.setprogress(completed_packages * 1.0 / total_packages) libcalamares.utils.debug(pretty_name()) @@ -444,7 +447,7 @@ def run(): completed_packages = 0 for op in operations: for packagelist in op.values(): - total_packages += len(packagelist) + total_packages += len(subst_locale(packagelist)) if not total_packages: # Avoids potential divide-by-zero in progress reporting diff --git a/src/modules/packages/packages.conf b/src/modules/packages/packages.conf index 2d6ca116f..7e5717b7c 100644 --- a/src/modules/packages/packages.conf +++ b/src/modules/packages/packages.conf @@ -76,7 +76,7 @@ update_db: true # pre-script: touch /tmp/installing-vi # post-script: rm -f /tmp/installing-vi # -# The pre- and post-scripts are optional, but not both optional: using +# The pre- and post-scripts are optional, but you cannot leave both out: using # "package: vi" with neither script option will trick Calamares into # trying to install a package named "package: vi", which is unlikely to work. # @@ -84,11 +84,16 @@ update_db: true # packages for software based on the selected system locale. By including # the string LOCALE in the package name, the following happens: # -# - if the system locale is English (generally US English; en_GB is a valid -# localization), then the package is not installed at all, -# - otherwise $LOCALE or ${LOCALE} is replaced by the Bcp47 name of the selected -# system locale, e.g. nl_BE. Note that just plain LOCALE will not be replaced, -# so foo-LOCALE will be unchanged, while foo-$LOCALE will be changed. +# - if the system locale is English (any variety), then the package is not +# installed at all, +# - otherwise $LOCALE or ${LOCALE} is replaced by the **lower-cased** BCP47 +# name of the **language** part of the selected system locale (not the +# country/region/dialect part), e.g. selecting *nl_BE* will use *nl* +# here. +# +# Take care that just plain LOCALE will not be replaced, so foo-LOCALE will +# be left unchanged, while foo-$LOCALE will be changed. However, foo-LOCALE +# **will** be removed from the list of packages, if English is selected. # # The following installs localizations for vi, if they are relevant; if # there is no localization, installation continues normally. @@ -127,6 +132,7 @@ update_db: true operations: - install: - vi + - vi-${LOCALE} - wget - binutils - remove: diff --git a/src/modules/plasmalnf/CMakeLists.txt b/src/modules/plasmalnf/CMakeLists.txt index 15897f98c..e39b1af9f 100644 --- a/src/modules/plasmalnf/CMakeLists.txt +++ b/src/modules/plasmalnf/CMakeLists.txt @@ -4,8 +4,13 @@ find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE) # needs a runtime support component (which we don't test for). 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" +) set_package_properties( KF5Plasma PROPERTIES PURPOSE "For Plasma Look-and-Feel selection" @@ -16,11 +21,19 @@ set_package_properties( ) if ( KF5Plasma_FOUND AND KF5Package_FOUND ) - find_package( KF5 ${lnf_ver} REQUIRED CoreAddons Plasma Package ) + if ( KF5Config_FOUND ) + set( option_kf5 Config ) + set( option_defs WITH_KCONFIG ) + # set( option_libs KF5::Config ) # Not needed anyway + endif() + + find_package( KF5 ${lnf_ver} REQUIRED CoreAddons Plasma Package ${option_kf5} ) calamares_add_plugin( plasmalnf TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO + COMPILE_DEFINITIONS + ${option_defs} SOURCES PlasmaLnfViewStep.cpp PlasmaLnfPage.cpp @@ -32,6 +45,7 @@ if ( KF5Plasma_FOUND AND KF5Package_FOUND ) page_plasmalnf.ui LINK_PRIVATE_LIBRARIES calamaresui + ${option_libs} KF5::Package KF5::Plasma SHARED_LIB diff --git a/src/modules/plasmalnf/PlasmaLnfPage.cpp b/src/modules/plasmalnf/PlasmaLnfPage.cpp index 2b171cc40..c65e79ba2 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.cpp +++ b/src/modules/plasmalnf/PlasmaLnfPage.cpp @@ -23,6 +23,8 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" +#include + #include #include @@ -55,13 +57,18 @@ static ThemeInfoList plasma_themes() PlasmaLnfPage::PlasmaLnfPage( QWidget* parent ) : QWidget( parent ) , ui( new Ui::PlasmaLnfPage ) + , m_showAll( false ) , m_buttonGroup( nullptr ) { ui->setupUi( this ); CALAMARES_RETRANSLATE( { ui->retranslateUi( this ); - ui->generalExplanation->setText( tr( "Please choose a look-and-feel for the KDE Plasma Desktop. You can also skip this step and configure the look-and-feel once the system is installed." ) ); + ui->generalExplanation->setText( tr( + "Please choose a look-and-feel for the KDE Plasma Desktop. " + "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(); } @@ -75,10 +82,18 @@ PlasmaLnfPage::setLnfPath( const QString& path ) } void -PlasmaLnfPage::setEnabledThemes(const ThemeInfoList& themes) +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(); @@ -87,9 +102,18 @@ PlasmaLnfPage::setEnabledThemes(const ThemeInfoList& themes) void PlasmaLnfPage::setEnabledThemesAll() { - setEnabledThemes( plasma_themes() ); + // 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() { @@ -162,6 +186,11 @@ void PlasmaLnfPage::fillUi() { theme.widget->updateThemeName( theme ); } + if ( theme.id == m_preselect ) + { + const QSignalBlocker b( theme.widget->button() ); + theme.widget->button()->setChecked( true ); + } ++c; } } diff --git a/src/modules/plasmalnf/PlasmaLnfPage.h b/src/modules/plasmalnf/PlasmaLnfPage.h index e489e99a7..49a6ff69a 100644 --- a/src/modules/plasmalnf/PlasmaLnfPage.h +++ b/src/modules/plasmalnf/PlasmaLnfPage.h @@ -46,10 +46,17 @@ public: explicit PlasmaLnfPage( QWidget* parent = nullptr ); void setLnfPath( const QString& path ); - /** @brief enable only the listed themes. */ - void setEnabledThemes( const ThemeInfoList& themes ); + /** @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 ); signals: void plasmaThemeSelected( const QString& id ); @@ -64,6 +71,8 @@ private: Ui::PlasmaLnfPage* ui; QString m_lnfPath; + QString m_preselect; + bool m_showAll; // If true, don't winnow according to enabledThemes ThemeInfoList m_enabledThemes; QButtonGroup *m_buttonGroup; diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index db8529d56..498a40fe0 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -26,8 +26,25 @@ #include #include +#ifdef WITH_KCONFIG +#include +#include +#endif + CALAMARES_PLUGIN_FACTORY_DEFINITION( PlasmaLnfViewStepFactory, registerPlugin(); ) +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_widget( new PlasmaLnfPage ) @@ -137,10 +154,22 @@ PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) liveUser = configurationMap.value( "liveuser" ).toString(); m_liveUser = liveUser; + QString preselect; + if ( configurationMap.contains( "preselect" ) && configurationMap.value( "preselect" ).type() == QVariant::String ) + preselect = configurationMap.value( "preselect" ).toString(); + if ( preselect == QStringLiteral( "*" ) ) + preselect = currentPlasmaTheme(); + if ( !preselect.isEmpty() ) + m_widget->setPreselect( preselect ); + + bool showAll( false ); + if ( configurationMap.contains( "showAll" ) && configurationMap.value( "showAll" ).type() == QVariant::Bool ) + showAll = configurationMap.value( "showAll" ).toBool(); + if ( configurationMap.contains( "themes" ) && configurationMap.value( "themes" ).type() == QVariant::List ) { - ThemeInfoList allThemes; + 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) @@ -149,14 +178,14 @@ PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap ) if ( i.type() == QVariant::Map ) { auto iv = i.toMap(); - allThemes.append( ThemeInfo( iv.value( "theme" ).toString(), iv.value( "image" ).toString() ) ); + listedThemes.append( ThemeInfo( iv.value( "theme" ).toString(), iv.value( "image" ).toString() ) ); } else if ( i.type() == QVariant::String ) - allThemes.append( ThemeInfo( i.toString() ) ); + listedThemes.append( ThemeInfo( i.toString() ) ); - if ( allThemes.length() == 1 ) + if ( listedThemes.length() == 1 ) cDebug() << "WARNING: only one theme enabled in plasmalnf"; - m_widget->setEnabledThemes( allThemes ); + m_widget->setEnabledThemes( listedThemes, showAll ); } else m_widget->setEnabledThemesAll(); // All of them diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.h b/src/modules/plasmalnf/PlasmaLnfViewStep.h index 7fcfc50cc..1fa4139e1 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.h +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.h @@ -61,9 +61,9 @@ public slots: private: PlasmaLnfPage* m_widget; - QString m_lnfPath; - QString m_themeId; - QString m_liveUser; + 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) }; CALAMARES_PLUGIN_FACTORY_DECLARATION( PlasmaLnfViewStepFactory ) diff --git a/src/modules/plasmalnf/ThemeWidget.cpp b/src/modules/plasmalnf/ThemeWidget.cpp index 28e01c2ff..68a8c5f83 100644 --- a/src/modules/plasmalnf/ThemeWidget.cpp +++ b/src/modules/plasmalnf/ThemeWidget.cpp @@ -62,7 +62,7 @@ ThemeWidget::ThemeWidget(const ThemeInfo& info, QWidget* parent) layout->addWidget( image_label, 1 ); layout->addWidget( m_description, 3 ); - connect( m_check, &QRadioButton::clicked, this, &ThemeWidget::clicked ); + connect( m_check, &QRadioButton::toggled, this, &ThemeWidget::clicked ); } void diff --git a/src/modules/plasmalnf/plasmalnf.conf b/src/modules/plasmalnf/plasmalnf.conf index aa9865117..a3a80fcff 100644 --- a/src/modules/plasmalnf/plasmalnf.conf +++ b/src/modules/plasmalnf/plasmalnf.conf @@ -13,8 +13,9 @@ lnftool: "/usr/bin/lookandfeeltool" # 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!). +# 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, +# to change that. # # Themes may be listed by id, (e.g. fluffy-bunny, below) or as a theme # and an image (e.g. breeze) which will be used to show a screenshot. @@ -27,3 +28,26 @@ themes: - theme: org.kde.breezedark.desktop 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. +# Do this only on Live images where you are reasonably sure +# that the user is not going to change the theme out from under +# themselves before running the installer. +# +# If this key is present, its value should be the id of the theme +# which should be pre-selected. If absent, empty, or the pre-selected +# theme is not found on the live system, no theme will be pre-selected. +# +# As a special setting, use "*", to try to find the currently- +# selected theme by reading the Plasma configuration. This requires +# KF5::Config at build- and run-time. +preselect: "*" diff --git a/src/modules/welcome/welcome.conf b/src/modules/welcome/welcome.conf index 18e71b1ef..b7ce5cfcd 100644 --- a/src/modules/welcome/welcome.conf +++ b/src/modules/welcome/welcome.conf @@ -25,6 +25,6 @@ requirements: # If any of these conditions are not met, the user cannot # continue past the welcome page. required: - - storage + # - storage - ram - - root + # - root