Merge branch 'pr-1632' into work-3.3
- merge in recent *calamares* branch FIXES #1632 (PR from Anubhav) FIXES #1886 FIXES #1456 FIXES #517
This commit is contained in:
commit
e15e57600e
16
CHANGES-3.2
16
CHANGES-3.2
@ -8,6 +8,22 @@ 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.57 (unreleased) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Arjen Balfoort (new contributor! Welcome!)
|
||||
- Victor Fuentes
|
||||
|
||||
## Core ##
|
||||
- No core changes yet
|
||||
|
||||
## Modules ##
|
||||
- *fstab* and *luksbootkeyfile* have better support for an **un**encrypted
|
||||
`/boot` partition. #1931 (thanks Arjen)
|
||||
- *packagechooser* and *packagechooserq* can now be given a custom name
|
||||
in the side-panel. #1932 (thanks Victor)
|
||||
|
||||
|
||||
# 3.2.56 (2022-04-22) #
|
||||
|
||||
As of this release, Calamares 3.2 development is winding down. The
|
||||
|
@ -798,8 +798,12 @@ def run():
|
||||
|
||||
fw_type = libcalamares.globalstorage.value("firmwareType")
|
||||
|
||||
if (libcalamares.globalstorage.value("bootLoader") is None and fw_type != "efi"):
|
||||
libcalamares.utils.warning( "Non-EFI system, and no bootloader is set." )
|
||||
if libcalamares.globalstorage.value("bootLoader") is None:
|
||||
# Don't want a bootloader, but do log that this has an effect:
|
||||
if fw_type != "efi":
|
||||
libcalamares.utils.warning( "Non-EFI system, and no bootloader is set." )
|
||||
else:
|
||||
libcalamares.utils.warning( "EFI system, and no bootloader is set." )
|
||||
return None
|
||||
|
||||
partitions = libcalamares.globalstorage.value("partitions")
|
||||
|
32
src/modules/fstab/main.py
Normal file → Executable file
32
src/modules/fstab/main.py
Normal file → Executable file
@ -156,11 +156,23 @@ class FstabGenerator(object):
|
||||
if not mapper_name or not luks_uuid:
|
||||
return None
|
||||
|
||||
password = "/crypto_keyfile.bin"
|
||||
crypttab_options = self.crypttab_options
|
||||
|
||||
# Set crypttab password for partition to none and remove crypttab options
|
||||
# on root partition when /boot is unencrypted
|
||||
if partition["mountPoint"] == "/":
|
||||
if any([p["mountPoint"] == "/boot"
|
||||
and "luksMapperName" not in p
|
||||
for p in self.partitions]):
|
||||
password = "none"
|
||||
crypttab_options = ""
|
||||
|
||||
return dict(
|
||||
name=mapper_name,
|
||||
device="UUID=" + luks_uuid,
|
||||
password="/crypto_keyfile.bin",
|
||||
options=self.crypttab_options,
|
||||
password=password,
|
||||
options=crypttab_options,
|
||||
)
|
||||
|
||||
def print_crypttab_line(self, dct, file=None):
|
||||
@ -218,7 +230,7 @@ class FstabGenerator(object):
|
||||
# Some "fs" names need special handling in /etc/fstab, so remap them.
|
||||
filesystem = partition["fs"].lower()
|
||||
filesystem = FS_MAP.get(filesystem, filesystem)
|
||||
has_luks = "luksMapperName" in partition
|
||||
luks_mapper_name = partition.get("luksMapperName", None)
|
||||
mount_point = partition["mountPoint"]
|
||||
disk_name = disk_name_for_partition(partition)
|
||||
is_ssd = disk_name in self.ssd_disks
|
||||
@ -247,13 +259,23 @@ class FstabGenerator(object):
|
||||
if mount_point == "/":
|
||||
self.root_is_ssd = is_ssd
|
||||
|
||||
if has_luks:
|
||||
device = "/dev/mapper/" + partition["luksMapperName"]
|
||||
# If there's a set-and-not-empty subvolume set, add it
|
||||
if filesystem == "btrfs" and partition.get("subvol",None):
|
||||
options = "subvol={},".format(partition["subvol"]) + options
|
||||
|
||||
device = None
|
||||
if luks_mapper_name:
|
||||
device = "/dev/mapper/" + luks_mapper_name
|
||||
elif partition["uuid"]:
|
||||
device = "UUID=" + partition["uuid"]
|
||||
else:
|
||||
device = partition["device"]
|
||||
|
||||
if not device:
|
||||
# TODO: we get here when the user mounted a previously encrypted partition
|
||||
# This should be catched early in the process
|
||||
return None
|
||||
|
||||
return dict(device=device,
|
||||
mount_point=mount_point,
|
||||
fs=filesystem,
|
||||
|
@ -11,3 +11,10 @@ calamares_add_plugin(luksbootkeyfile
|
||||
SHARED_LIB
|
||||
NO_CONFIG
|
||||
)
|
||||
|
||||
calamares_add_test(
|
||||
luksbootkeyfiletest
|
||||
SOURCES
|
||||
Tests.cpp
|
||||
LuksBootKeyFileJob.cpp
|
||||
)
|
||||
|
@ -150,26 +150,50 @@ setupLuks( const LuksDevice& d )
|
||||
}
|
||||
|
||||
static QVariantList
|
||||
partitions()
|
||||
partitionsFromGlobalStorage()
|
||||
{
|
||||
Calamares::GlobalStorage* globalStorage = Calamares::JobQueue::instance()->globalStorage();
|
||||
return globalStorage->value( QStringLiteral( "partitions" ) ).toList();
|
||||
}
|
||||
|
||||
static bool
|
||||
/// Checks if the partition (represented by @p map) mounts to the given @p path
|
||||
STATICTEST bool
|
||||
hasMountPoint( const QVariantMap& map, const QString& path )
|
||||
{
|
||||
const auto v = map.value( QStringLiteral( "mountPoint" ) );
|
||||
return v.isValid() && QDir::cleanPath( v.toString() ) == path;
|
||||
}
|
||||
|
||||
STATICTEST bool
|
||||
isEncrypted( const QVariantMap& map )
|
||||
{
|
||||
return map.contains( QStringLiteral( "luksMapperName" ) );
|
||||
}
|
||||
|
||||
/// Checks for any partition satisfying @p pred
|
||||
STATICTEST bool
|
||||
anyPartition( bool ( *pred )( const QVariantMap& ) )
|
||||
{
|
||||
const auto partitions = partitionsFromGlobalStorage();
|
||||
return std::find_if( partitions.cbegin(),
|
||||
partitions.cend(),
|
||||
[ &pred ]( const QVariant& partitionVariant ) { return pred( partitionVariant.toMap() ); } )
|
||||
!= partitions.cend();
|
||||
}
|
||||
|
||||
STATICTEST bool
|
||||
hasUnencryptedSeparateBoot()
|
||||
{
|
||||
const QVariantList partitions = ::partitions();
|
||||
for ( const QVariant& partition : partitions )
|
||||
{
|
||||
QVariantMap partitionMap = partition.toMap();
|
||||
QString mountPoint = partitionMap.value( QStringLiteral( "mountPoint" ) ).toString();
|
||||
if ( QDir::cleanPath( mountPoint ) == QStringLiteral( "/boot" ) )
|
||||
{
|
||||
return !partitionMap.contains( QStringLiteral( "luksMapperName" ) );
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return anyPartition(
|
||||
[]( const QVariantMap& partition )
|
||||
{ return hasMountPoint( partition, QStringLiteral( "/boot" ) ) && !isEncrypted( partition ); } );
|
||||
}
|
||||
|
||||
STATICTEST bool
|
||||
hasEncryptedRoot()
|
||||
{
|
||||
return anyPartition( []( const QVariantMap& partition )
|
||||
{ return hasMountPoint( partition, QStringLiteral( "/" ) ) && isEncrypted( partition ); } );
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
@ -218,7 +242,8 @@ LuksBootKeyFileJob::exec()
|
||||
}
|
||||
|
||||
// /boot partition is not encrypted, keyfile must not be used
|
||||
if ( hasUnencryptedSeparateBoot() )
|
||||
// But only if root partition is not encrypted
|
||||
if ( hasUnencryptedSeparateBoot() && !hasEncryptedRoot() )
|
||||
{
|
||||
cDebug() << Logger::SubEntry << "/boot partition is not encrypted, skipping keyfile creation.";
|
||||
return Calamares::JobResult::ok();
|
||||
@ -241,6 +266,12 @@ LuksBootKeyFileJob::exec()
|
||||
|
||||
for ( const auto& d : s.devices )
|
||||
{
|
||||
// Skip setupLuks for root partition if system has an unencrypted /boot
|
||||
if ( d.isRoot && hasUnencryptedSeparateBoot() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !setupLuks( d ) )
|
||||
return Calamares::JobResult::error(
|
||||
tr( "Encrypted rootfs setup error" ),
|
||||
|
169
src/modules/luksbootkeyfile/Tests.cpp
Normal file
169
src/modules/luksbootkeyfile/Tests.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#undef STATICTEST
|
||||
#define STATICTEST extern
|
||||
|
||||
// Implementation details
|
||||
STATICTEST bool hasMountPoint( const QVariantMap& map, const QString& path );
|
||||
|
||||
STATICTEST bool isEncrypted( const QVariantMap& map );
|
||||
|
||||
STATICTEST bool anyPartition( bool ( *pred )( const QVariantMap& ) );
|
||||
|
||||
STATICTEST bool hasUnencryptedSeparateBoot();
|
||||
|
||||
STATICTEST bool hasEncryptedRoot();
|
||||
|
||||
class LuksBootKeyFileTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LuksBootKeyFileTests() {}
|
||||
~LuksBootKeyFileTests() override {}
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void testMountPoint();
|
||||
void testIsEncrypted();
|
||||
void testAnyPartition();
|
||||
};
|
||||
|
||||
void
|
||||
LuksBootKeyFileTests::initTestCase()
|
||||
{
|
||||
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||
cDebug() << "LuksBootKeyFile test started.";
|
||||
|
||||
if ( !Calamares::JobQueue::instance() )
|
||||
{
|
||||
(void)new Calamares::JobQueue();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LuksBootKeyFileTests::testMountPoint()
|
||||
{
|
||||
QVariantMap m; // As if this is a partition data
|
||||
const QString key = QStringLiteral( "mountPoint" );
|
||||
const QString boot = QStringLiteral( "/boot" );
|
||||
const QString root = QStringLiteral( "/" );
|
||||
|
||||
QVERIFY( !hasMountPoint( m, QString() ) );
|
||||
QVERIFY( !hasMountPoint( m, boot ) );
|
||||
|
||||
m.insert( key, boot );
|
||||
QVERIFY( hasMountPoint( m, boot ) );
|
||||
QVERIFY( !hasMountPoint( m, QString() ) );
|
||||
QVERIFY( !hasMountPoint( m, root ) );
|
||||
|
||||
m.insert( key, root );
|
||||
QVERIFY( !hasMountPoint( m, boot ) );
|
||||
QVERIFY( !hasMountPoint( m, QString() ) );
|
||||
QVERIFY( hasMountPoint( m, root ) );
|
||||
|
||||
m.remove( key );
|
||||
QVERIFY( !hasMountPoint( m, root ) );
|
||||
}
|
||||
|
||||
void
|
||||
LuksBootKeyFileTests::testIsEncrypted()
|
||||
{
|
||||
QVariantMap m; // As if this is a partition data
|
||||
const QString key = QStringLiteral( "luksMapperName" );
|
||||
const QString name = QStringLiteral( "any-name" );
|
||||
|
||||
QVERIFY( !isEncrypted( m ) );
|
||||
|
||||
// Even an empty string is considered encrypted
|
||||
m.insert( key, QString() );
|
||||
QVERIFY( isEncrypted( m ) );
|
||||
|
||||
m.insert( key, name );
|
||||
QVERIFY( isEncrypted( m ) );
|
||||
|
||||
m.insert( key, QString() );
|
||||
QVERIFY( isEncrypted( m ) );
|
||||
|
||||
m.remove( key );
|
||||
QVERIFY( !isEncrypted( m ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LuksBootKeyFileTests::testAnyPartition()
|
||||
{
|
||||
// This is kind of annoying: we need to build up
|
||||
// partition data in GS because the functions we're testing
|
||||
// go straight to GS.
|
||||
auto* gs = Calamares::JobQueue::instanceGlobalStorage();
|
||||
QVERIFY( gs );
|
||||
|
||||
const QString partitionsKey = QStringLiteral( "partitions" );
|
||||
const QString mountPointKey = QStringLiteral( "mountPoint" );
|
||||
const QString boot = QStringLiteral( "/boot" );
|
||||
const QString root = QStringLiteral( "/" );
|
||||
|
||||
QVariantList partitions;
|
||||
QVariantMap p;
|
||||
QVERIFY( !gs->contains( partitionsKey ) );
|
||||
|
||||
// Empty list!
|
||||
QVERIFY( !anyPartition( []( const QVariantMap& ) { return true; } ) );
|
||||
|
||||
gs->insert( partitionsKey, partitions );
|
||||
QVERIFY( !anyPartition( []( const QVariantMap& ) { return true; } ) ); // Still an empty list
|
||||
|
||||
partitions.append( p );
|
||||
QCOMPARE( partitions.count(), 1 );
|
||||
gs->insert( partitionsKey, partitions );
|
||||
QVERIFY( anyPartition( []( const QVariantMap& ) { return true; } ) ); // Now a one-element list
|
||||
QVERIFY( !anyPartition( []( const QVariantMap& ) { return false; } ) ); // Now a one-element list
|
||||
|
||||
p.insert( mountPointKey, boot );
|
||||
QVERIFY( hasMountPoint( p, boot ) );
|
||||
partitions.append( p );
|
||||
QCOMPARE( partitions.count(), 2 );
|
||||
|
||||
// Note that GS is not updated yet, so we expect this to fail
|
||||
QEXPECT_FAIL( "", "GS not updated", Continue );
|
||||
QVERIFY( anyPartition(
|
||||
[]( const QVariantMap& partdata )
|
||||
{
|
||||
cDebug() << partdata;
|
||||
return hasMountPoint( partdata, QStringLiteral( "/boot" ) );
|
||||
} ) );
|
||||
|
||||
gs->insert( partitionsKey, partitions ); // Update GS
|
||||
QVERIFY( anyPartition(
|
||||
[]( const QVariantMap& partdata )
|
||||
{
|
||||
cDebug() << partdata;
|
||||
return hasMountPoint( partdata, QStringLiteral( "/boot" ) );
|
||||
} ) );
|
||||
QVERIFY( !anyPartition( []( const QVariantMap& partdata )
|
||||
{ return hasMountPoint( partdata, QStringLiteral( "/" ) ); } ) );
|
||||
QVERIFY( !anyPartition( []( const QVariantMap& partdata ) { return hasMountPoint( partdata, QString() ); } ) );
|
||||
|
||||
QVERIFY( !hasEncryptedRoot() );
|
||||
QVERIFY( hasUnencryptedSeparateBoot() );
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN( LuksBootKeyFileTests )
|
||||
|
||||
#include "utils/moc-warnings.h"
|
||||
|
||||
#include "Tests.moc"
|
@ -237,6 +237,12 @@ Config::setPackageChoice( const QString& packageChoice )
|
||||
emit packageChoiceChanged( m_packageChoice.value_or( QString() ) );
|
||||
}
|
||||
|
||||
QString
|
||||
Config::prettyName() const
|
||||
{
|
||||
return m_stepName ? m_stepName->get() : tr( "Packages" );
|
||||
}
|
||||
|
||||
QString
|
||||
Config::prettyStatus() const
|
||||
{
|
||||
@ -343,4 +349,14 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
cWarning() << "Single-selection QML module must use 'Legacy' method.";
|
||||
}
|
||||
}
|
||||
|
||||
bool labels_ok = false;
|
||||
auto labels = CalamaresUtils::getSubMap( configurationMap, "labels", labels_ok );
|
||||
if ( labels_ok )
|
||||
{
|
||||
if ( labels.contains( "step" ) )
|
||||
{
|
||||
m_stepName = new CalamaresUtils::Locale::TranslatedString( labels, "step" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ public:
|
||||
QString packageChoice() const { return m_packageChoice.value_or( QString() ); }
|
||||
void setPackageChoice( const QString& packageChoice );
|
||||
|
||||
QString prettyName() const;
|
||||
QString prettyStatus() const;
|
||||
|
||||
signals:
|
||||
@ -120,6 +121,7 @@ private:
|
||||
* Reading the property will return an empty QString.
|
||||
*/
|
||||
std::optional< QString > m_packageChoice;
|
||||
CalamaresUtils::Locale::TranslatedString* m_stepName; // As it appears in the sidebar
|
||||
};
|
||||
|
||||
|
||||
|
@ -29,7 +29,6 @@ PackageChooserViewStep::PackageChooserViewStep( QObject* parent )
|
||||
: Calamares::ViewStep( parent )
|
||||
, m_config( new Config( this ) )
|
||||
, m_widget( nullptr )
|
||||
, m_stepName( nullptr )
|
||||
{
|
||||
emit nextStatusChanged( false );
|
||||
}
|
||||
@ -41,14 +40,13 @@ PackageChooserViewStep::~PackageChooserViewStep()
|
||||
{
|
||||
m_widget->deleteLater();
|
||||
}
|
||||
delete m_stepName;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
PackageChooserViewStep::prettyName() const
|
||||
{
|
||||
return m_stepName ? m_stepName->get() : tr( "Packages" );
|
||||
return m_config->prettyName();
|
||||
}
|
||||
|
||||
|
||||
@ -139,16 +137,6 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap
|
||||
m_config->setDefaultId( moduleInstanceKey() );
|
||||
m_config->setConfigurationMap( configurationMap );
|
||||
|
||||
bool labels_ok = false;
|
||||
auto labels = CalamaresUtils::getSubMap( configurationMap, "labels", labels_ok );
|
||||
if ( labels_ok )
|
||||
{
|
||||
if ( labels.contains( "step" ) )
|
||||
{
|
||||
m_stepName = new CalamaresUtils::Locale::TranslatedString( labels, "step" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_widget )
|
||||
{
|
||||
hookupModel();
|
||||
|
@ -50,7 +50,6 @@ private:
|
||||
|
||||
Config* m_config;
|
||||
PackageChooserPage* m_widget;
|
||||
CalamaresUtils::Locale::TranslatedString* m_stepName; // As it appears in the sidebar
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( PackageChooserViewStepFactory )
|
||||
|
@ -29,7 +29,7 @@ PackageChooserQmlViewStep::PackageChooserQmlViewStep( QObject* parent )
|
||||
QString
|
||||
PackageChooserQmlViewStep::prettyName() const
|
||||
{
|
||||
return tr( "Packages" );
|
||||
return m_config->prettyName();
|
||||
}
|
||||
|
||||
QString
|
||||
|
@ -42,6 +42,19 @@
|
||||
#
|
||||
method: legacy
|
||||
|
||||
# Human-visible strings in this module. These are all optional.
|
||||
# The following translated keys are used:
|
||||
# - *step*, used in the overall progress view (left-hand pane)
|
||||
#
|
||||
# Each key can have a [locale] added to it, which is used as
|
||||
# the translated string for that locale. For the strings
|
||||
# associated with the "no-selection" item, see *items*, below
|
||||
# with the explicit item-*id* "".
|
||||
#
|
||||
labels:
|
||||
step: "Packages"
|
||||
step[nl]: "Pakketten"
|
||||
|
||||
# The *packageChoice* value is used for setting the default selection
|
||||
# in the QML view; this should match one of the keys used in the QML
|
||||
# module for package names.
|
||||
|
@ -3,6 +3,7 @@
|
||||
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
|
||||
* SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
|
||||
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-FileCopyrightText: 2021 Anubhav Choudhary <ac.10edu@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
@ -79,7 +80,7 @@ BootLoaderModel::updateInternal()
|
||||
clear();
|
||||
createMbrItems();
|
||||
|
||||
// An empty model is possible if you don't havee permissions: don't crash though.
|
||||
// An empty model is possible if you don't have permissions: don't crash though.
|
||||
if ( rowCount() < 1 )
|
||||
{
|
||||
return;
|
||||
@ -124,10 +125,10 @@ BootLoaderModel::updateInternal()
|
||||
{
|
||||
appendRow( createBootLoaderItem( partitionText, PartitionInfo::mountPoint( partition ), true ) );
|
||||
}
|
||||
|
||||
// Create "don't install bootloader" item
|
||||
appendRow( createBootLoaderItem( tr( "Do not install a boot loader" ), QString(), false ) );
|
||||
}
|
||||
// Create "don't install bootloader" item. This is always available,
|
||||
// also if there was no /boot or / partition found.
|
||||
appendRow( createBootLoaderItem( tr( "Do not install a boot loader" ), QString(), false ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
* SPDX-FileCopyrightText: 2014-2017 Teo Mrnjavac <teo@kde.org>
|
||||
* SPDX-FileCopyrightText: 2017-2019 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-FileCopyrightText: 2019 Collabora Ltd
|
||||
* SPDX-FileCopyrightText: 2021 Anubhav Choudhary <ac.10edu@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
@ -1021,6 +1022,12 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice )
|
||||
QLabel* sizeLabel = new QLabel( m_previewAfterFrame );
|
||||
layout->addWidget( sizeLabel );
|
||||
sizeLabel->setWordWrap( true );
|
||||
|
||||
if ( !m_isEfi )
|
||||
{
|
||||
layout->addWidget( createBootloaderPanel() );
|
||||
}
|
||||
|
||||
connect( m_afterPartitionSplitterWidget,
|
||||
&PartitionSplitterWidget::partitionResized,
|
||||
this,
|
||||
@ -1079,51 +1086,7 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice )
|
||||
|
||||
if ( !m_isEfi )
|
||||
{
|
||||
QWidget* eraseWidget = new QWidget;
|
||||
|
||||
QHBoxLayout* eraseLayout = new QHBoxLayout;
|
||||
eraseWidget->setLayout( eraseLayout );
|
||||
eraseLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
QLabel* eraseBootloaderLabel = new QLabel( eraseWidget );
|
||||
eraseLayout->addWidget( eraseBootloaderLabel );
|
||||
eraseBootloaderLabel->setText( tr( "Boot loader location:" ) );
|
||||
|
||||
m_bootloaderComboBox = createBootloaderComboBox( eraseWidget );
|
||||
connect( m_core->bootLoaderModel(),
|
||||
&QAbstractItemModel::modelReset,
|
||||
[ this ]()
|
||||
{
|
||||
if ( !m_bootloaderComboBox.isNull() )
|
||||
{
|
||||
Calamares::restoreSelectedBootLoader( *m_bootloaderComboBox,
|
||||
m_core->bootLoaderInstallPath() );
|
||||
}
|
||||
} );
|
||||
connect(
|
||||
m_core,
|
||||
&PartitionCoreModule::deviceReverted,
|
||||
this,
|
||||
[ this ]( Device* dev )
|
||||
{
|
||||
Q_UNUSED( dev )
|
||||
if ( !m_bootloaderComboBox.isNull() )
|
||||
{
|
||||
if ( m_bootloaderComboBox->model() != m_core->bootLoaderModel() )
|
||||
{
|
||||
m_bootloaderComboBox->setModel( m_core->bootLoaderModel() );
|
||||
}
|
||||
|
||||
m_bootloaderComboBox->setCurrentIndex( m_lastSelectedDeviceIndex );
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection );
|
||||
// ^ Must be Queued so it's sure to run when the widget is already visible.
|
||||
|
||||
eraseLayout->addWidget( m_bootloaderComboBox );
|
||||
eraseBootloaderLabel->setBuddy( m_bootloaderComboBox );
|
||||
eraseLayout->addStretch();
|
||||
|
||||
layout->addWidget( eraseWidget );
|
||||
layout->addWidget( createBootloaderPanel() );
|
||||
}
|
||||
|
||||
m_previewAfterFrame->show();
|
||||
@ -1235,35 +1198,6 @@ ChoicePage::setupEfiSystemPartitionSelector()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QComboBox*
|
||||
ChoicePage::createBootloaderComboBox( QWidget* parent )
|
||||
{
|
||||
QComboBox* comboForBootloader = new QComboBox( parent );
|
||||
comboForBootloader->setModel( m_core->bootLoaderModel() );
|
||||
|
||||
// When the chosen bootloader device changes, we update the choice in the PCM
|
||||
connect( comboForBootloader,
|
||||
QOverload< int >::of( &QComboBox::currentIndexChanged ),
|
||||
this,
|
||||
[ this ]( int newIndex )
|
||||
{
|
||||
QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() );
|
||||
if ( bootloaderCombo )
|
||||
{
|
||||
QVariant var = bootloaderCombo->itemData( newIndex, BootLoaderModel::BootLoaderPathRole );
|
||||
if ( !var.isValid() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_core->setBootLoaderInstallPath( var.toString() );
|
||||
}
|
||||
} );
|
||||
|
||||
return comboForBootloader;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
force_uncheck( QButtonGroup* grp, PrettyRadioButton* button )
|
||||
{
|
||||
@ -1733,3 +1667,72 @@ ChoicePage::setLastSelectedDeviceIndex( int index )
|
||||
m_lastSelectedDeviceIndex = index;
|
||||
m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex );
|
||||
}
|
||||
|
||||
QWidget*
|
||||
ChoicePage::createBootloaderPanel()
|
||||
{
|
||||
QWidget* panelWidget = new QWidget;
|
||||
|
||||
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||||
panelWidget->setLayout( mainLayout );
|
||||
mainLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
QLabel* widgetLabel = new QLabel( panelWidget );
|
||||
mainLayout->addWidget( widgetLabel );
|
||||
widgetLabel->setText( tr( "Boot loader location:" ) );
|
||||
|
||||
QComboBox* comboForBootloader = new QComboBox( panelWidget );
|
||||
comboForBootloader->setModel( m_core->bootLoaderModel() );
|
||||
|
||||
// When the chosen bootloader device changes, we update the choice in the PCM
|
||||
connect( comboForBootloader,
|
||||
QOverload< int >::of( &QComboBox::currentIndexChanged ),
|
||||
this,
|
||||
[ this ]( int newIndex )
|
||||
{
|
||||
QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() );
|
||||
if ( bootloaderCombo )
|
||||
{
|
||||
QVariant var = bootloaderCombo->itemData( newIndex, BootLoaderModel::BootLoaderPathRole );
|
||||
if ( !var.isValid() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_core->setBootLoaderInstallPath( var.toString() );
|
||||
}
|
||||
} );
|
||||
m_bootloaderComboBox = comboForBootloader;
|
||||
|
||||
connect( m_core->bootLoaderModel(),
|
||||
&QAbstractItemModel::modelReset,
|
||||
[ this ]()
|
||||
{
|
||||
if ( !m_bootloaderComboBox.isNull() )
|
||||
{
|
||||
Calamares::restoreSelectedBootLoader( *m_bootloaderComboBox, m_core->bootLoaderInstallPath() );
|
||||
}
|
||||
} );
|
||||
connect(
|
||||
m_core,
|
||||
&PartitionCoreModule::deviceReverted,
|
||||
this,
|
||||
[ this ]( Device* )
|
||||
{
|
||||
if ( !m_bootloaderComboBox.isNull() )
|
||||
{
|
||||
if ( m_bootloaderComboBox->model() != m_core->bootLoaderModel() )
|
||||
{
|
||||
m_bootloaderComboBox->setModel( m_core->bootLoaderModel() );
|
||||
}
|
||||
|
||||
m_bootloaderComboBox->setCurrentIndex( m_lastSelectedDeviceIndex );
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection );
|
||||
// ^ Must be Queued so it's sure to run when the widget is already visible.
|
||||
|
||||
mainLayout->addWidget( m_bootloaderComboBox );
|
||||
widgetLabel->setBuddy( m_bootloaderComboBox );
|
||||
mainLayout->addStretch();
|
||||
|
||||
return panelWidget;
|
||||
}
|
||||
|
@ -108,7 +108,12 @@ private:
|
||||
void updateNextEnabled();
|
||||
void setupChoices();
|
||||
void checkInstallChoiceRadioButton( Config::InstallChoice choice ); ///< Sets the chosen button to "on"
|
||||
QComboBox* createBootloaderComboBox( QWidget* parentButton );
|
||||
/** @brief Create a panel with "boot loader location:"
|
||||
*
|
||||
* Panel + dropdown and handling for model updates. Returns a pointer
|
||||
* to the panel's widget.
|
||||
*/
|
||||
QWidget* createBootloaderPanel();
|
||||
Device* selectedDevice();
|
||||
|
||||
/* Change the UI depending on the device selected. */
|
||||
|
Loading…
Reference in New Issue
Block a user