diff --git a/CHANGES b/CHANGES index e6da1eb55..58602f256 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,19 @@ contributors are listed. Note that Calamares does not have a historical changelog -- this log starts with version 3.2.0. The release notes on the website will have to do for older versions. +# 3.2.24 (unreleased) # + +This release contains contributions from (alphabetically by first name): + - Gaël PORTAY + +## Core ## + - There is now a bash-completions script for Calamares; turn on + the (CMake-time) option INSTALL_COMPLETION to get it. (Thanks Gaël) + +## Modules ## + - No module changes yet + + # 3.2.23 (2020-04-17) # This release contains contributions from (alphabetically by first name): diff --git a/CMakeLists.txt b/CMakeLists.txt index b122301eb..6d4b3c4e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during develop # option( INSTALL_CONFIG "Install configuration files" OFF ) option( INSTALL_POLKIT "Install Polkit configuration" ON ) +option( INSTALL_COMPLETION "Install shell completions" OFF ) option( BUILD_TESTING "Build the testing tree." ON ) option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON ) option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." OFF ) @@ -389,6 +390,13 @@ list( SORT CALAMARES_TRANSLATION_LANGUAGES ) add_subdirectory( lang ) # i18n tools +if ( INSTALL_COMPLETION ) + if( NOT CMAKE_INSTALL_BASHCOMPLETIONDIR ) + set( CMAKE_INSTALL_BASHCOMPLETIONDIR "${CMAKE_INSTALL_DATADIR}/bash-completion/completions" ) + endif() + + install( FILES ${CMAKE_SOURCE_DIR}/data/completion/bash/calamares DESTINATION "${CMAKE_INSTALL_BASHCOMPLETIONDIR}" ) +endif() ### Example Distro # diff --git a/data/completion/bash/calamares b/data/completion/bash/calamares new file mode 100644 index 000000000..47c2bb268 --- /dev/null +++ b/data/completion/bash/calamares @@ -0,0 +1,36 @@ +# === This file is part of Calamares - === +# +# Copyright 2020, Gaël PORTAY +# +# Calamares is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Calamares is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Calamares. If not, see . + +_calamares() +{ + local cur prev words cword + _init_completion || return + + case "$prev" in + -D) + COMPREPLY=( $( compgen -W "$( seq 0 1 8 )" -- "$cur" ) ) + return + ;; + -c|--config) + _filedir + return + ;; + esac + + COMPREPLY=( $( compgen -W "-h --help -v --version -d --debug -D -c --config -X -xdg-config -T --debug-translation" -- "$cur" ) ) +} && +complete -F _calamares calamares diff --git a/lang/calamares_eo.ts b/lang/calamares_eo.ts index e7d9636d0..5173f5527 100644 --- a/lang/calamares_eo.ts +++ b/lang/calamares_eo.ts @@ -6,17 +6,17 @@ The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. - + La <strong>praŝarga ĉirkaŭaĵo</strong> de ĉi tiu sistemo.<br><br>Pli maljuna x86 sistemoj subtenas nur <strong>BIOS</strong>.<br>Pli sistemoj kutime uzas <strong>EFI</strong>, sed povos ankaŭ aspektas kiel BIOS, sed ŝaltita en kongrua reĝimo. This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. - + Tio ĉi sistemo estis ŝaltita per <strong>EFI</strong> praŝarga ĉirkaŭaĵo.<br><br>Agordi praŝargo el EFI, la instalilo devas disponigi praŝargilon, kiel: <strong>GRUB</strong> aŭ <strong>systemd-boot</strong> sur <strong>EFI Sistema Subdisko</strong>. Tio estas aŭtomata, krom se vi selektas manan dispartigon, tiukaze vi devas selekti ĝin, aŭ kreias unu mane. This system was started with a <strong>BIOS</strong> boot environment.<br><br>To configure startup from a BIOS environment, this installer must install a boot loader, like <strong>GRUB</strong>, either at the beginning of a partition or on the <strong>Master Boot Record</strong> near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own. - + Tio ĉi sistemo estis ŝaltita per <strong>BIOS</strong> praŝarga ĉirkaŭaĵo.<br><br>Agordi praŝargo el BIOS, la instalilo devas disponigi praŝargilon, kiel: <strong>GRUB</strong>, ĉe la komenco de subdisko aŭ sur la<strong>Ĉefa Ŝargodosiero</strong> apud la komencao de la subdiska tablo (preferred). Tio estas aŭtomata, krom se vi selektas manan dispartigon, tiukaze vi devas manipuli ĝin mane. @@ -24,22 +24,22 @@ Master Boot Record of %1 - + Ĉefa Ŝargodosiero de %1 Boot Partition - + Praŝarga Subdisko System Partition - + Sistema Subdisko Do not install a boot loader - + Ne instalu praŝargilon @@ -52,7 +52,7 @@ Blank Page - + Senskriba Paĝo @@ -65,12 +65,12 @@ GlobalStorage - + GlobalStorage JobQueue - + JobQueue @@ -101,17 +101,17 @@ Reload Stylesheet - + Reŝargu Stilfolio Widget Tree - + KromprogrametArbo Debug information - + Sencimiga Informaĵo @@ -124,7 +124,7 @@ Install - Instali + Instalu @@ -513,17 +513,17 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. Current: - + Nune: After: - + Poste: <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. Having a GPT partition table and <strong>fat32 512Mb /boot partition is a must for UEFI installs</strong>, either use an existing without formatting or create one. - + <strong>Manan aranĝaĵon de subdisko</strong><br/>Vi povas kreii aŭ regrandigi subdiskon ajne. @@ -543,7 +543,7 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. Boot loader location: - + Allokigo de la Praŝargilo: @@ -801,7 +801,7 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. Create a Partition - Kreiu Subdisko + Kreiu Subdiskon @@ -1153,12 +1153,12 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. Format - + Strukturu Warning: Formatting the partition will erase all existing data. - + Averto: Strukturi la subdiskon, forviŝos ĉiujn eksistantajn datumojn. @@ -1173,7 +1173,7 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. MiB - + MiB @@ -1272,32 +1272,32 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. <h1>All done.</h1><br/>%1 has been set up on your computer.<br/>You may now start using your new system. - + <h1>Plenumita!</h1><br/>%1 estis agordita sur vian komputilon.<br/>Vi povas nun ekuzi vian novan sistemon. <html><head/><body><p>When this box is checked, your system will restart immediately when you click on <span style="font-style:italic;">Done</span> or close the setup program.</p></body></html> - + <html><head/><body><p>Se ĉi tio elektobutono estas elektita, via sistemo restartos senprokraste, kiam vi klikas <span style="font-style:italic;">Finita</span> aŭ vi malfermas la agordilon.</p></body></html> <h1>All done.</h1><br/>%1 has been installed on your computer.<br/>You may now restart into your new system, or continue using the %2 Live environment. - + <h1>Plenumita!</h1><br/>%1 estis instalita sur vian komputilon.<br/>Vi povas nun restartigas en vian novan sistemon, aŭ vi povas pluiri uzi la %2 aŭtonoman sistemon. <html><head/><body><p>When this box is checked, your system will restart immediately when you click on <span style="font-style:italic;">Done</span> or close the installer.</p></body></html> - + <html><head/><body><p>Se ĉi tio elektobutono estas elektita, via sistemo restartos senprokraste, kiam vi klikas <span style="font-style:italic;">Finita</span> aŭ vi malfermas la instalilon.</p></body></html> <h1>Setup Failed</h1><br/>%1 has not been set up on your computer.<br/>The error message was: %2. - + <h1>Agorado Malsukcesis</h1><br/>%1 ne estis agordita sur vian komputilon.<br/>La erara mesaĝo estis: %2. <h1>Installation Failed</h1><br/>%1 has not been installed on your computer.<br/>The error message was: %2. - + <h1>Instalaĵo Malsukcesis</h1><br/>%1 ne estis instalita sur vian komputilon.<br/>La erara mesaĝo estis: %2. @@ -1305,27 +1305,27 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. Finish - + Pretigu Setup Complete - + Agordaĵo Plenumita Installation Complete - + Instalaĵo Plenumita The setup of %1 is complete. - + La agordaĵo de %1 estas plenumita. The installation of %1 is complete. - + La instalaĵo de %1 estas plenumita. @@ -1333,22 +1333,22 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. Format partition %1 (file system: %2, size: %3 MiB) on %4. - + Strukturu subdiskon %1 (dosiersistemo: %2, grandeco: %3 MiB) ja %4. Format <strong>%3MiB</strong> partition <strong>%1</strong> with file system <strong>%2</strong>. - + Strukturu <strong>%3MiB</strong> subdiskon <strong>%1</strong> kiel dosiersistemo <strong>%2</strong>. Formatting partition %1 with file system %2. - + Strukturanta subdiskon %1 kiel dosiersistemo %2. The installer failed to format partition %1 on disk '%2'. - + La instalilo malsukcesis strukturi ls subdiskon %1 sur disko '%2'. @@ -2539,12 +2539,12 @@ La instalilo forlasos kaj ĉiuj ŝanĝoj perdos. Current: - + Nune: After: - + Poste: @@ -2746,7 +2746,7 @@ Output: unformatted - + nestrukturita diff --git a/lang/calamares_ja.ts b/lang/calamares_ja.ts index 870d85e79..8c14c1456 100644 --- a/lang/calamares_ja.ts +++ b/lang/calamares_ja.ts @@ -3665,7 +3665,7 @@ Output: <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. - + <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. diff --git a/lang/calamares_sv.ts b/lang/calamares_sv.ts index d0a8d06a5..f1acd343c 100644 --- a/lang/calamares_sv.ts +++ b/lang/calamares_sv.ts @@ -623,12 +623,12 @@ Alla ändringar kommer att gå förlorade. Swap (no Hibernate) - + Swap (utan viloläge) Swap (with Hibernate) - + Swap (med viloläge) @@ -1789,12 +1789,12 @@ Alla ändringar kommer att gå förlorade. Browser software - + Webbläsare Browser package - + Webbläsare @@ -1839,7 +1839,7 @@ Alla ändringar kommer att gå förlorade. Office - + Kontorsprogram @@ -3723,7 +3723,7 @@ Utdata: Refresh - + Ladda om @@ -3768,7 +3768,7 @@ Utdata: <h3>Welcome to the %1 <quote>%2</quote> installer</h3> - + <h3>Välkommen till %1 <quote>%2</quote> installeraren</h3> diff --git a/lang/calamares_tr_TR.ts b/lang/calamares_tr_TR.ts index eaa871552..42738f7a8 100644 --- a/lang/calamares_tr_TR.ts +++ b/lang/calamares_tr_TR.ts @@ -3673,7 +3673,7 @@ Kuruluma devam edebilirsiniz fakat bazı özellikler devre dışı kalabilir. <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. - + <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Telif Hakkı 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Telif Hakkı 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Teşekkrürler <a href="https://calamares.io/team/">Calamares takımı</a> ve <a href="https://www.transifex.com/calamares/calamares/">Calamares çeviri ekibi</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> gelişim sponsoru <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Özgür Yazılım diff --git a/src/branding/default/banner.png b/src/branding/default/banner.png new file mode 100644 index 000000000..d1baeee85 Binary files /dev/null and b/src/branding/default/banner.png differ diff --git a/src/branding/default/branding.desc b/src/branding/default/branding.desc index b6694d1f4..53884e311 100644 --- a/src/branding/default/branding.desc +++ b/src/branding/default/branding.desc @@ -106,6 +106,11 @@ strings: # These images are loaded from the branding module directory. # +# productBanner is an optional image, which if present, will be shown +# on the welcome page of the application, above the welcome text. +# It is intended to have a width much greater than height. +# It is displayed at 64px height (also on HiDPI). +# Recommended size is 64px tall, and up to 460px wide. # productIcon is used as the window icon, and will (usually) be used # by the window manager to represent the application. This image # should be square, and may be displayed by the window manager @@ -121,8 +126,9 @@ strings: # # These filenames can also use substitutions from os-release (see above). images: - productLogo: "squid.png" + # productBanner: "banner.png" productIcon: "squid.png" + productLogo: "squid.png" productWelcome: "languages.png" # The slideshow is displayed during execution steps (e.g. when the diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index 91dce96cd..dd6f01fb1 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -226,6 +226,16 @@ calamares_add_test( partition/Tests.cpp ) +if( KPMcore_FOUND ) + calamares_add_test( + libcalamarespartitionkpmtest + SOURCES + partition/KPMTests.cpp + LIBRARIES + ${OPTIONAL_PRIVATE_LIBRARIES} + ) +endif() + calamares_add_test( libcalamareslocaletest SOURCES @@ -244,8 +254,8 @@ calamares_add_test( modulesystem/Tests.cpp ) -if( BUILD_TESTING ) - add_executable( test_geoip geoip/test_geoip.cpp ${geoip_src} ) - target_link_libraries( test_geoip calamares Qt5::Network yamlcpp ) - calamares_automoc( test_geoip ) -endif() +# This is not an actual test, it's a test / demo application +# for experimenting with GeoIP. +add_executable( test_geoip geoip/test_geoip.cpp ${geoip_src} ) +target_link_libraries( test_geoip calamares Qt5::Network yamlcpp ) +calamares_automoc( test_geoip ) diff --git a/src/libcalamares/locale/Tests.cpp b/src/libcalamares/locale/Tests.cpp index bf71fb0a2..6cbe980be 100644 --- a/src/libcalamares/locale/Tests.cpp +++ b/src/libcalamares/locale/Tests.cpp @@ -37,6 +37,7 @@ void LocaleTests::initTestCase() { // Otherwise plain get() is dubious in the TranslatableConfiguration tests + QLocale::setDefault( QLocale( QStringLiteral( "en_US" ) ) ); QVERIFY( ( QLocale().name() == "C" ) || ( QLocale().name() == "en_US" ) ); } diff --git a/src/libcalamares/partition/KPMTests.cpp b/src/libcalamares/partition/KPMTests.cpp new file mode 100644 index 000000000..7468d3938 --- /dev/null +++ b/src/libcalamares/partition/KPMTests.cpp @@ -0,0 +1,82 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "utils/Logger.h" + +#include + +#include + +class KPMTests : public QObject +{ + Q_OBJECT +public: + KPMTests(); + ~KPMTests() override; +private Q_SLOTS: + void initTestCase(); + + void testFlagNames(); +}; + +KPMTests::KPMTests() {} + +KPMTests::~KPMTests() {} + +void +KPMTests::initTestCase() +{ + Logger::setupLogLevel( Logger::LOGDEBUG ); +} + +void +KPMTests::testFlagNames() +{ + int f = 1; + QStringList names; + QString s; + while ( !( s = PartitionTable::flagName( static_cast< PartitionTable::Flag >( f ) ) ).isEmpty() ) + { + cDebug() << f << s; + names.append( s ); + + f <<= 1; + } + + QCOMPARE( PartitionTable::flagName( static_cast< PartitionTable::Flag >( 1 ) ), QStringLiteral( "boot" ) ); + +#ifdef WITH_KPMCORE4API + // KPMCore 4 unifies the flags and handles them internally + QCOMPARE( PartitionTable::flagName( PartitionTable::Flag::Boot ), QStringLiteral( "boot" ) ); + QVERIFY( names.contains( QStringLiteral( "boot" ) ) ); + QVERIFY( !names.contains( QStringLiteral( "esp" ) ) ); +#else + // KPMCore 3 has separate flags + QCOMPARE( PartitionTable::flagName( PartitionTable::FlagBoot ), QStringLiteral( "boot" ) ); + QCOMPARE( PartitionTable::flagName( PartitionTable::FlagEsp ), QStringLiteral( "esp" ) ); + QVERIFY( names.contains( QStringLiteral( "boot" ) ) ); + QVERIFY( names.contains( QStringLiteral( "esp" ) ) ); +#endif +} + + +QTEST_GUILESS_MAIN( KPMTests ) + +#include "utils/moc-warnings.h" + +#include "KPMTests.moc" diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.cpp b/src/libcalamares/utils/CalamaresUtilsSystem.cpp index 651ac2c1e..327bece92 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.cpp +++ b/src/libcalamares/utils/CalamaresUtilsSystem.cpp @@ -195,7 +195,7 @@ System::runCommand( System::RunLocation location, ? ( static_cast< int >( std::chrono::milliseconds( timeoutSec ).count() ) ) : -1 ) ) { - ( cWarning() << "Process" << args.first() << "timed out after" << timeoutSec.count() << "s. Output so far:\n" ).noquote().nospace() << process.readAllStandardOutput(); + cWarning() << "Process" << args.first() << "timed out after" << timeoutSec.count() << "s. Output so far:\n" << Logger::NoQuote{} << process.readAllStandardOutput(); return ProcessResult::Code::TimedOut; } @@ -203,7 +203,7 @@ System::runCommand( System::RunLocation location, if ( process.exitStatus() == QProcess::CrashExit ) { - ( cWarning() << "Process" << args.first() << "crashed. Output so far:\n" ).noquote().nospace() << output; + cWarning() << "Process" << args.first() << "crashed. Output so far:\n" << Logger::NoQuote{} << output; return ProcessResult::Code::Crashed; } @@ -212,7 +212,7 @@ System::runCommand( System::RunLocation location, bool showDebug = ( !Calamares::Settings::instance() ) || ( Calamares::Settings::instance()->debugMode() ); if ( ( r != 0 ) || showDebug ) { - ( cDebug() << "Target cmd:" << RedactedList( args ) << "output:\n" ).noquote().nospace() << output; + cDebug() << "Target cmd:" << RedactedList( args ) << "output:\n" << Logger::NoQuote{} << output; } return ProcessResult( r, output ); } diff --git a/src/libcalamares/utils/Logger.h b/src/libcalamares/utils/Logger.h index fe4b98fd4..24198e256 100644 --- a/src/libcalamares/utils/Logger.h +++ b/src/libcalamares/utils/Logger.h @@ -33,6 +33,9 @@ struct FuncSuppressor const char* m_s; }; +struct NoQuote {}; +struct Quote {}; + DLLEXPORT extern const FuncSuppressor Continuation; DLLEXPORT extern const FuncSuppressor SubEntry; @@ -74,6 +77,18 @@ operator<<( QDebug& s, const FuncSuppressor& f ) return s << f.m_s; } +inline QDebug& +operator<<( QDebug& s, const NoQuote& ) +{ + return s.noquote().nospace(); +} + +inline QDebug& +operator<<( QDebug& s, const Quote& ) +{ + return s.quote().space(); +} + /** * @brief The full path of the log file. */ diff --git a/src/libcalamaresui/Branding.cpp b/src/libcalamaresui/Branding.cpp index ff7e43fb8..67054a902 100644 --- a/src/libcalamaresui/Branding.cpp +++ b/src/libcalamaresui/Branding.cpp @@ -73,10 +73,11 @@ const QStringList Branding::s_stringEntryStrings = const QStringList Branding::s_imageEntryStrings = { - "productLogo", + "productBanner", "productIcon", - "productWelcome", - "productWallpaper" + "productLogo", + "productWallpaper", + "productWelcome" }; const QStringList Branding::s_styleEntryStrings = @@ -537,7 +538,7 @@ Branding::initSimpleSettings( const YAML::Node& doc ) [[noreturn]] void Branding::bail( const QString& message ) { - cError() << "FATAL in" << m_descriptorPath << "\n" + message; + cError() << "FATAL in" << m_descriptorPath << Logger::Continuation << Logger::NoQuote{} << message; ::exit( EXIT_FAILURE ); } diff --git a/src/libcalamaresui/Branding.h b/src/libcalamaresui/Branding.h index 023f1a511..847f28d89 100644 --- a/src/libcalamaresui/Branding.h +++ b/src/libcalamaresui/Branding.h @@ -67,10 +67,11 @@ public: enum ImageEntry : short { - ProductLogo, + ProductBanner, ProductIcon, - ProductWelcome, - ProductWallpaper + ProductLogo, + ProductWallpaper, + ProductWelcome }; Q_ENUM( ImageEntry ) diff --git a/src/modules/locale/Tests.cpp b/src/modules/locale/Tests.cpp index b07482ce7..af37a664b 100644 --- a/src/modules/locale/Tests.cpp +++ b/src/modules/locale/Tests.cpp @@ -25,12 +25,14 @@ #include +#include + QTEST_MAIN( LocaleTests ) -LocaleTests::LocaleTests() { } +LocaleTests::LocaleTests() {} -LocaleTests::~LocaleTests() { } +LocaleTests::~LocaleTests() {} void LocaleTests::initTestCase() @@ -147,6 +149,122 @@ LocaleTests::testTZImages() } } - QEXPECT_FAIL("", "TZ Images not yet all fixed", Continue); + QEXPECT_FAIL( "", "TZ Images not yet all fixed", Continue ); QCOMPARE( overlapcount, 0 ); } + +bool +operator<( const QPoint& l, const QPoint& r ) +{ + if ( l.x() < r.x() ) + { + return true; + } + if ( l.x() > r.x() ) + { + return false; + } + return l.y() < r.y(); +} + +void +listAll( const QPoint& p, const CalamaresUtils::Locale::CStringPairList& zones ) +{ + using namespace CalamaresUtils::Locale; + for ( const auto* pz : zones ) + { + const TZZone* zone = dynamic_cast< const TZZone* >( pz ); + if ( p == TimeZoneImageList::getLocationPosition( zone->longitude(), zone->latitude() ) ) + { + cError() << Logger::SubEntry << zone->zone(); + } + } +} + +void +LocaleTests::testTZLocations() +{ + using namespace CalamaresUtils::Locale; + const CStringPairList& regions = TZRegion::fromZoneTab(); + + int overlapcount = 0; + for ( const auto* pr : regions ) + { + const TZRegion* region = dynamic_cast< const TZRegion* >( pr ); + QVERIFY( region ); + + Logger::setupLogLevel( Logger::LOGDEBUG ); + cDebug() << "Region" << region->region() << "zones #" << region->zones().count(); + Logger::setupLogLevel( Logger::LOGERROR ); + + std::set< QPoint > occupied; + + const auto zones = region->zones(); + QVERIFY( zones.count() > 0 ); + for ( const auto* pz : zones ) + { + const TZZone* zone = dynamic_cast< const TZZone* >( pz ); + QVERIFY( zone ); + + auto pos = TimeZoneImageList::getLocationPosition( zone->longitude(), zone->latitude() ); + if ( occupied.find( pos ) != occupied.end() ) + { + cError() << "Zone" << zone->zone() << "occupies same spot as .."; + listAll( pos, zones ); + overlapcount++; + } + occupied.insert( pos ); + } + } + + QEXPECT_FAIL( "", "TZ Images contain pixel-overlaps", Continue ); + QCOMPARE( overlapcount, 0 ); +} + +const CalamaresUtils::Locale::TZZone* +findZone( const QString& name ) +{ + using namespace CalamaresUtils::Locale; + const CStringPairList& regions = TZRegion::fromZoneTab(); + + for ( const auto* pr : regions ) + { + const TZRegion* region = dynamic_cast< const TZRegion* >( pr ); + if ( !region ) + { + continue; + } + const auto zones = region->zones(); + for ( const auto* pz : zones ) + { + const TZZone* zone = dynamic_cast< const TZZone* >( pz ); + if ( !zone ) + { + continue; + } + + if ( zone->zone() == name ) + { + return zone; + } + } + } + return nullptr; +} + +void +LocaleTests::testSpecificLocations() +{ + const auto* gibraltar = findZone( "Gibraltar" ); + const auto* ceuta = findZone( "Ceuta" ); + QVERIFY( gibraltar ); + QVERIFY( ceuta ); + + auto gpos = TimeZoneImageList::getLocationPosition( gibraltar->longitude(), gibraltar->latitude() ); + auto cpos = TimeZoneImageList::getLocationPosition( ceuta->longitude(), ceuta->latitude() ); + QEXPECT_FAIL( "", "Gibraltar and Ceuta are really close", Continue ); + QVERIFY( gpos != cpos ); + QVERIFY( gibraltar->latitude() > ceuta->latitude() ); + QEXPECT_FAIL( "", "Gibraltar and Ceuta are really close", Continue ); + QVERIFY( gpos.y() < cpos.y() ); // Gibraltar is north of Ceuta +} diff --git a/src/modules/locale/Tests.h b/src/modules/locale/Tests.h index e0ca7ad0b..e01b1a25c 100644 --- a/src/modules/locale/Tests.h +++ b/src/modules/locale/Tests.h @@ -37,7 +37,9 @@ private Q_SLOTS: void testSplitLocaleConfiguration(); // Check the TZ images for consistency - void testTZImages(); + void testTZImages(); // No overlaps in images + void testTZLocations(); // No overlaps in locations + void testSpecificLocations(); }; #endif diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index 5e785c9d1..d0de2c0d4 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -151,6 +151,10 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO KPM_PARTITION_FLAG( None ) ); PartitionInfo::setFormat( efiPartition, true ); PartitionInfo::setMountPoint( efiPartition, o.efiPartitionMountPoint ); + if ( gs->contains( "efiSystemPartitionName" ) ) + { + efiPartition->setLabel( gs->value( "efiSystemPartitionName" ).toString() ); + } core->createPartition( dev, efiPartition, KPM_PARTITION_FLAG_ESP ); firstFreeSector = lastSector + 1; } diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index ed35fafa4..c9bdd03f9 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -417,6 +417,12 @@ PartitionViewStep::onLeave() { QString espMountPoint = Calamares::JobQueue::instance()->globalStorage()->value( "efiSystemPartition" ).toString(); +#ifdef WITH_KPMCORE4API + auto espFlag = PartitionTable::Flag::Boot; +#else + auto espFlag = PartitionTable::FlagEsp; +#endif + QString espFlagName = PartitionTable::flagName( espFlag ); Partition* esp = m_core->findPartitionByMountPoint( espMountPoint ); QString message; @@ -428,12 +434,12 @@ PartitionViewStep::onLeave() "

" "To configure an EFI system partition, go back and " "select or create a FAT32 filesystem with the " - "esp flag enabled and mount point " + "%3 flag enabled and mount point " "%2.

" "You can continue without setting up an EFI system " "partition but your system may fail to start." ) .arg( *Calamares::Branding::ShortProductName ) - .arg( espMountPoint ); + .arg( espMountPoint, espFlagName ); } else if ( esp && !PartUtils::isEfiBootable( esp ) ) { @@ -441,14 +447,14 @@ PartitionViewStep::onLeave() description = tr( "An EFI system partition is necessary to start %1." "

" "A partition was configured with mount point " - "%2 but its esp " + "%2 but its %3 " "flag is not set.
" "To set the flag, go back and edit the partition." "

" "You can continue without setting the flag but your " "system may fail to start." ) .arg( *Calamares::Branding::ShortProductName ) - .arg( espMountPoint ); + .arg( espMountPoint, espFlagName ); } if ( !message.isEmpty() ) @@ -538,6 +544,12 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) gs->insert( "efiSystemPartitionSize", CalamaresUtils::getString( configurationMap, "efiSystemPartitionSize" ) ); } + // Read and parse key efiSystemPartitionName + if ( configurationMap.contains( "efiSystemPartitionName" ) ) + { + gs->insert( "efiSystemPartitionName", CalamaresUtils::getString( configurationMap, "efiSystemPartitionName" ) ); + } + // SWAP SETTINGS // // This is a bit convoluted because there's legacy settings to handle as well diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.cpp b/src/modules/partition/jobs/FillGlobalStorageJob.cpp index ac65b5ff6..a302a3f31 100644 --- a/src/modules/partition/jobs/FillGlobalStorageJob.cpp +++ b/src/modules/partition/jobs/FillGlobalStorageJob.cpp @@ -107,7 +107,7 @@ mapForPartition( Partition* partition, const QString& uuid ) Logger::CDebug deb; using TR = Logger::DebugRow< const char* const, const QString& >; deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode() - << TR( "mtpoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() ) + << TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() ) << TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid ) << TR( "claimed", map[ "claimed" ].toString() ); diff --git a/src/modules/partition/partition.conf b/src/modules/partition/partition.conf index 241e4ea05..f6cc34ee4 100644 --- a/src/modules/partition/partition.conf +++ b/src/modules/partition/partition.conf @@ -7,6 +7,10 @@ efiSystemPartition: "/boot/efi" # If nothing is specified, the default size of 300MiB will be used. # efiSystemPartitionSize: 300M +# This optional setting specifies the name of the EFI system partition. +# If nothing is specified, the partition name is left unset. +# efiSystemPartitionName: EFI + # In autogenerated partitioning, allow the user to select a swap size? # If there is exactly one choice, no UI is presented, and the user # cannot make a choice -- this setting is used. If there is more than diff --git a/src/modules/partition/tests/ClearMountsJobTests.cpp b/src/modules/partition/tests/ClearMountsJobTests.cpp index 1f01c4638..17ff48945 100644 --- a/src/modules/partition/tests/ClearMountsJobTests.cpp +++ b/src/modules/partition/tests/ClearMountsJobTests.cpp @@ -42,7 +42,11 @@ getPartitionsForDevice_other(const QString& deviceName) process.start(); process.waitForFinished(); - const QString partitions = process.readAllStandardOutput(); + const QString partitions = process.readAllStandardOutput().trimmed(); + if ( partitions.isEmpty() ) + { + return QStringList(); + } const QStringList partitionsList = partitions.simplified().split( ' ' ); return partitionsList; diff --git a/src/modules/umount/main.py b/src/modules/umount/main.py index a337c481a..454222c5c 100644 --- a/src/modules/umount/main.py +++ b/src/modules/umount/main.py @@ -98,7 +98,9 @@ def run(): lst.sort(key=lambda x: x[1], reverse=True) for device, mount_point in lst: - subprocess.check_call(["umount", "-lv", mount_point]) + # On success, no output; if the command fails, its output is + # in the exception object. + subprocess.check_output(["umount", "-lv", mount_point], stderr=subprocess.STDOUT) os.rmdir(root_mount_point) diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index e4be00fe7..89fde33a0 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -51,7 +51,45 @@ WelcomePage::WelcomePage( Config* conf, QWidget* parent ) , m_languages( nullptr ) , m_conf( conf ) { + using Branding = Calamares::Branding; + const int defaultFontHeight = CalamaresUtils::defaultFontHeight(); + ui->setupUi( this ); + ui->aboutButton->setIcon( CalamaresUtils::defaultPixmap( + CalamaresUtils::Information, + CalamaresUtils::Original, + 2 * QSize( defaultFontHeight, defaultFontHeight ) ) ); + + // insert system-check widget below welcome text + const int welcome_text_idx = ui->verticalLayout->indexOf( ui->mainText ); + ui->verticalLayout->insertWidget( welcome_text_idx + 1, m_checkingWidget ); + + // insert optional logo banner image above welcome text + QString bannerPath = Branding::instance()->imagePath( Branding::ProductBanner ); + if ( !bannerPath.isEmpty() ) + { + // If the name is not empty, the file exists -- Branding checks that at startup + QPixmap bannerPixmap = QPixmap( bannerPath ); + if ( !bannerPixmap.isNull() ) + { + QLabel* bannerLabel = new QLabel; + bannerLabel->setPixmap( bannerPixmap ); + bannerLabel->setMinimumHeight( 64 ); + bannerLabel->setAlignment( Qt::AlignCenter ); + ui->aboveTextSpacer->changeSize( 20, defaultFontHeight ); // Shrink it down + ui->aboveTextSpacer->invalidate(); + ui->verticalLayout->insertSpacing( welcome_text_idx, defaultFontHeight ); + ui->verticalLayout->insertWidget( welcome_text_idx, bannerLabel ); + } + } + + initLanguages(); + + cDebug() << "Welcome string" << Calamares::Branding::instance()->welcomeStyleCalamares() + << *Calamares::Branding::VersionedName; + CALAMARES_RETRANSLATE_SLOT( &WelcomePage::retranslate ) + + connect( ui->aboutButton, &QPushButton::clicked, this, &WelcomePage::showAboutBox ); connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsComplete, m_checkingWidget, @@ -60,28 +98,6 @@ WelcomePage::WelcomePage( Config* conf, QWidget* parent ) &Calamares::ModuleManager::requirementsProgress, m_checkingWidget, &CheckerContainer::requirementsProgress ); - ui->setupUi( this ); - - ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() * 2 ); - initLanguages(); - - ui->mainText->setAlignment( Qt::AlignCenter ); - ui->mainText->setWordWrap( true ); - ui->mainText->setOpenExternalLinks( true ); - - cDebug() << "Welcome string" << Calamares::Branding::instance()->welcomeStyleCalamares() - << *Calamares::Branding::VersionedName; - - CALAMARES_RETRANSLATE_SLOT( &WelcomePage::retranslate ) - - ui->aboutButton->setIcon( CalamaresUtils::defaultPixmap( - CalamaresUtils::Information, - CalamaresUtils::Original, - 2 * QSize( CalamaresUtils::defaultFontHeight(), CalamaresUtils::defaultFontHeight() ) ) ); - connect( ui->aboutButton, &QPushButton::clicked, this, &WelcomePage::showAboutBox ); - - int welcome_text_idx = ui->verticalLayout->indexOf( ui->mainText ); - ui->verticalLayout->insertWidget( welcome_text_idx + 1, m_checkingWidget ); } void diff --git a/src/modules/welcome/WelcomePage.ui b/src/modules/welcome/WelcomePage.ui index 590029558..04b89f256 100644 --- a/src/modules/welcome/WelcomePage.ui +++ b/src/modules/welcome/WelcomePage.ui @@ -17,7 +17,7 @@ - + Qt::Vertical @@ -43,6 +43,12 @@ <Calamares welcome text> + + Qt::AlignCenter + + + true + @@ -78,15 +84,15 @@ - - Select application and system language - 2 0 + + Select application and system language + diff --git a/src/modules/welcomeq/img/language-icon-48px.png b/src/modules/welcomeq/img/language-icon-48px.png new file mode 100644 index 000000000..4012a4bee Binary files /dev/null and b/src/modules/welcomeq/img/language-icon-48px.png differ diff --git a/src/modules/welcomeq/release_notes.qml b/src/modules/welcomeq/release_notes.qml new file mode 100644 index 000000000..ce9d1d4af --- /dev/null +++ b/src/modules/welcomeq/release_notes.qml @@ -0,0 +1,100 @@ +/* === This file is part of Calamares - === + * + * Copyright 2020, Anke Boersma + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +import io.calamares.ui 1.0 + +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Window 2.2 +import QtQuick.Layouts 1.3 + +Rectangle { + width: parent.width + height: parent.height + focus: true + color: "#f2f2f2" + + Flickable { + id: flick + anchors.fill: parent + contentHeight: 3500 + + ScrollBar.vertical: ScrollBar { + id: fscrollbar + width: 10 + policy: ScrollBar.AlwaysOn + } + + TextArea { + id: intro + x: 130 + y: 8 + width: 640 + font.pointSize: 14 + textFormat: Text.RichText + antialiasing: true + activeFocusOnPress: false + wrapMode: Text.WordWrap + + text: qsTr("

%1

+

This an example QML file, showing options in RichText with Flickable content.

+ +

QML with RichText can use HTML tags, Flickable content is useful for touchscreens.

+ +

This is bold text

+

This is italic text

+

This is underlined text

+

This text will be center-aligned.

+

This is strikethrough

+ +

Code example: + ls -l /home

+ +

Lists:

+
    +
  • Intel CPU systems
  • +
  • AMD CPU systems
  • +
+ +

The vertical scrollbar is adjustable, current width set to 10.

").arg(Branding.string(Branding.VersionedName)) + + } + } + + ToolButton { + id: toolButton + x: 19 + y: 29 + width: 105 + height: 48 + text: qsTr("Back") + hoverEnabled: true + onClicked: load.source = "" + + Image { + id: image1 + x: 0 + y: 13 + width: 22 + height: 22 + source: "img/chevron-left-solid.svg" + fillMode: Image.PreserveAspectFit + } + } + +} diff --git a/src/modules/welcomeq/welcomeq.qml b/src/modules/welcomeq/welcomeq.qml index 729b61b28..6330f5116 100644 --- a/src/modules/welcomeq/welcomeq.qml +++ b/src/modules/welcomeq/welcomeq.qml @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with Calamares. If not, see . */ +import io.calamares.core 1.0 import io.calamares.ui 1.0 import QtQuick 2.10 @@ -29,21 +30,21 @@ Page { id: welcome - header: Item - { + header: Item { width: parent.width height: parent.height - Text - { + Text { id: welcomeTopText anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top + horizontalAlignment: Text.AlignHCenter + padding: 40 // In QML, QString::arg() only takes one argument - text: qsTr("

Welcome to the %1 %2 installer

").arg(Branding.string(Branding.ProductName)).arg(Branding.string(Branding.Version)) + text: qsTr("

Welcome to the %1 %2 installer

+

This program will ask you some questions and set up %1 on your computer.

").arg(Branding.string(Branding.ProductName)).arg(Branding.string(Branding.Version)) } - Image - { + Image { id: welcomeImage anchors.centerIn: parent // imagePath() returns a full pathname, so make it refer to the filesystem @@ -55,36 +56,31 @@ Page fillMode: Image.PreserveAspectFit } - RowLayout - { + RowLayout { id: buttonBar - width: parent.width + width: parent.width / 1.5 height: 64 anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter spacing: Kirigami.Units.largeSpacing* 2 -/* Traditionally Calamares has had an "About" button that talks about - * Calamares itself, which just isn't a very useful thing in someone - * else's installation ISO. - */ - Button - { + Button { Layout.fillWidth: true text: qsTr("About") icon.name: "dialog-information" Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.4) Kirigami.Theme.textColor: Kirigami.Theme.textColor - visible: false + visible: true onClicked: { - //onClicked: load.source = "file:/usr/share/calamares/branding/kaos_branding/show.qml" + //onClicked: load.source = "file:/usr/share/calamares/branding/default/show.qml" onClicked: load.source = "about.qml" } } - Button - { + + Button { Layout.fillWidth: true text: qsTr("Support") icon.name: "system-help" @@ -94,8 +90,8 @@ Page visible: config.supportUrl !== "" onClicked: Qt.openUrlExternally(config.supportUrl) } - Button - { + + Button { Layout.fillWidth: true text: qsTr("Known issues") icon.name: "tools-report-bug" @@ -105,8 +101,8 @@ Page visible: config.knownIssuesUrl !== "" onClicked: Qt.openUrlExternally(config.knownIssuesUrl) } - Button - { + + Button { Layout.fillWidth: true text: qsTr("Release notes") icon.name: "folder-text" @@ -114,10 +110,11 @@ Page Kirigami.Theme.textColor: Kirigami.Theme.textColor visible: config.releaseNotesUrl !== "" - onClicked: Qt.openUrlExternally(config.releaseNotesUrl) + onClicked: load.source = "release_notes.qml" + //onClicked: load.source = "file:/usr/share/calamares/release_notes.qml" } - Button - { + + Button { Layout.fillWidth: true text: qsTr("Donate") icon.name: "taxes-finances" @@ -128,8 +125,41 @@ Page onClicked: Qt.openUrlExternally(config.donateUrl) } } - Loader - { + + RowLayout { + id: languageBar + width: parent.width /1.2 + height: 48 + + anchors.bottom: parent.bottom + anchors.bottomMargin: parent.height /7 + anchors.horizontalCenter: parent.horizontalCenter + spacing: Kirigami.Units.largeSpacing* 4 + + Rectangle { + width: parent.width + Layout.fillWidth: true + focus: true + Image { + id: image + height: 48 + fillMode: Image.PreserveAspectFit + source: "img/language-icon-48px.png" + } + + ComboBox { + id: languages + anchors.left: image.right + width: languageBar.width /1.1 + textRole: "label" + currentIndex: 4 //model.currentIndex + model: config.languagesModel + onCurrentIndexChanged: console.debug(currentText, currentIndex) + } + } + } + + Loader { id:load anchors.fill: parent } diff --git a/src/modules/welcomeq/welcomeq.qrc b/src/modules/welcomeq/welcomeq.qrc index 84e598a27..71431254e 100644 --- a/src/modules/welcomeq/welcomeq.qrc +++ b/src/modules/welcomeq/welcomeq.qrc @@ -2,7 +2,9 @@ welcomeq.qml about.qml + release_notes.qml img/squid.png img/chevron-left-solid.svg + img/language-icon-48px.png