mirror of
https://github.com/parchlinux/calamares.git
synced 2025-06-28 01:45:36 -04:00
Merge branch 'master' into requirements-checking
This commit is contained in:
commit
43eae0bc47
437 changed files with 41760 additions and 9847 deletions
|
@ -1,7 +1,8 @@
|
|||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2017-2019, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,34 +21,39 @@
|
|||
#include "ChoicePage.h"
|
||||
|
||||
#include "core/BootLoaderModel.h"
|
||||
#include "core/PartitionActions.h"
|
||||
#include "core/PartitionCoreModule.h"
|
||||
#include "core/DeviceModel.h"
|
||||
#include "core/PartitionModel.h"
|
||||
#include "core/KPMHelpers.h"
|
||||
#include "core/OsproberEntry.h"
|
||||
#include "core/PartUtils.h"
|
||||
#include "core/PartitionActions.h"
|
||||
#include "core/PartitionCoreModule.h"
|
||||
#include "core/PartitionInfo.h"
|
||||
#include "core/PartitionIterator.h"
|
||||
#include "core/PartitionModel.h"
|
||||
|
||||
#include "ReplaceWidget.h"
|
||||
#include "PrettyRadioButton.h"
|
||||
#include "BootInfoWidget.h"
|
||||
#include "DeviceInfoWidget.h"
|
||||
#include "PartitionBarsView.h"
|
||||
#include "PartitionLabelsView.h"
|
||||
#include "PartitionSplitterWidget.h"
|
||||
#include "BootInfoWidget.h"
|
||||
#include "DeviceInfoWidget.h"
|
||||
#include "PrettyRadioButton.h"
|
||||
#include "ReplaceWidget.h"
|
||||
#include "ScanningDialog.h"
|
||||
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
#include "utils/Units.h"
|
||||
|
||||
#include "Branding.h"
|
||||
#include "core/KPMHelpers.h"
|
||||
#include "JobQueue.h"
|
||||
#include "GlobalStorage.h"
|
||||
#include "core/PartitionInfo.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
#ifdef WITH_KPMCOREGT33
|
||||
#include <kpmcore/core/softwareraid.h>
|
||||
#endif
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QButtonGroup>
|
||||
|
@ -58,16 +64,32 @@
|
|||
#include <QFutureWatcher>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
using PartitionActions::Choices::SwapChoice;
|
||||
|
||||
/** @brief Given a set of swap choices, return a sensible value from it.
|
||||
*
|
||||
* "Sensible" here means: if there is one value, use it; otherwise, use
|
||||
* NoSwap if there are no choices, or if NoSwap is one of the choices, in the set.
|
||||
* If that's not possible, any value from the set.
|
||||
*/
|
||||
SwapChoice pickOne( const SwapChoiceSet& s )
|
||||
{
|
||||
if ( s.count() == 0 )
|
||||
return SwapChoice::NoSwap;
|
||||
if ( s.count() == 1 )
|
||||
return *( s.begin() );
|
||||
if ( s.contains( SwapChoice::NoSwap ) )
|
||||
return SwapChoice::NoSwap;
|
||||
// Here, count > 1 but NoSwap is not a member.
|
||||
return *( s.begin() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ChoicePage::ChoicePage is the default constructor. Called on startup as part of
|
||||
* the module loading code path.
|
||||
* @param compactMode if true, the drive selector will be a combo box on top, otherwise it
|
||||
* will show up as a list view.
|
||||
* @param parent the QWidget parent.
|
||||
*/
|
||||
ChoicePage::ChoicePage( QWidget* parent )
|
||||
ChoicePage::ChoicePage( const SwapChoiceSet& swapChoices, QWidget* parent )
|
||||
: QWidget( parent )
|
||||
, m_nextEnabled( false )
|
||||
, m_core( nullptr )
|
||||
|
@ -78,21 +100,25 @@ ChoicePage::ChoicePage( QWidget* parent )
|
|||
, m_eraseButton( nullptr )
|
||||
, m_replaceButton( nullptr )
|
||||
, m_somethingElseButton( nullptr )
|
||||
, m_eraseSwapChoiceComboBox( nullptr )
|
||||
, m_deviceInfoWidget( nullptr )
|
||||
, m_beforePartitionBarsView( nullptr )
|
||||
, m_beforePartitionLabelsView( nullptr )
|
||||
, m_bootloaderComboBox( nullptr )
|
||||
, m_lastSelectedDeviceIndex( -1 )
|
||||
, m_enableEncryptionWidget( true )
|
||||
, m_availableSwapChoices( swapChoices )
|
||||
, m_eraseSwapChoice( pickOne( swapChoices ) )
|
||||
, m_allowManualPartitioning( true )
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
m_defaultFsType = Calamares::JobQueue::instance()->
|
||||
globalStorage()->
|
||||
value( "defaultFileSystemType" ).toString();
|
||||
m_enableEncryptionWidget = Calamares::JobQueue::instance()->
|
||||
globalStorage()->
|
||||
value( "enableLuksAutomatedPartitioning" ).toBool();
|
||||
auto gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
|
||||
m_defaultFsType = gs->value( "defaultFileSystemType" ).toString();
|
||||
m_enableEncryptionWidget = gs->value( "enableLuksAutomatedPartitioning" ).toBool();
|
||||
m_allowManualPartitioning = gs->value( "allowManualPartitioning" ).toBool();
|
||||
|
||||
if ( FileSystem::typeForName( m_defaultFsType ) == FileSystem::Unknown )
|
||||
m_defaultFsType = "ext4";
|
||||
|
||||
|
@ -134,7 +160,7 @@ ChoicePage::ChoicePage( QWidget* parent )
|
|||
m_previewAfterFrame->hide();
|
||||
m_encryptWidget->hide();
|
||||
m_reuseHomeCheckBox->hide();
|
||||
Calamares::JobQueue::instance()->globalStorage()->insert( "reuseHome", false );
|
||||
gs->insert( "reuseHome", false );
|
||||
}
|
||||
|
||||
|
||||
|
@ -173,6 +199,26 @@ ChoicePage::init( PartitionCoreModule* core )
|
|||
}
|
||||
|
||||
|
||||
/** @brief Creates a combobox with the given choices in it.
|
||||
*
|
||||
* Pre-selects the choice given by @p dflt.
|
||||
* No texts are set -- that happens later by the translator functions.
|
||||
*/
|
||||
static inline QComboBox*
|
||||
createCombo( const QSet< SwapChoice >& s, SwapChoice dflt )
|
||||
{
|
||||
QComboBox* box = new QComboBox;
|
||||
for ( SwapChoice c : { SwapChoice::NoSwap, SwapChoice::SmallSwap, SwapChoice::FullSwap, SwapChoice::ReuseSwap, SwapChoice::SwapFile } )
|
||||
if ( s.contains( c ) )
|
||||
box->addItem( QString(), c );
|
||||
|
||||
int dfltIndex = box->findData( dflt );
|
||||
if ( dfltIndex >= 0 )
|
||||
box->setCurrentIndex( dfltIndex );
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ChoicePage::setupChoices creates PrettyRadioButton objects for the action
|
||||
* choices.
|
||||
|
@ -226,15 +272,19 @@ ChoicePage::setupChoices()
|
|||
iconSize ) );
|
||||
m_grp->addButton( m_replaceButton->buttonWidget(), Replace );
|
||||
|
||||
// Fill up swap options
|
||||
// .. TODO: only if enabled in the config
|
||||
if ( m_availableSwapChoices.count() > 1 )
|
||||
{
|
||||
m_eraseSwapChoiceComboBox = createCombo( m_availableSwapChoices, m_eraseSwapChoice );
|
||||
m_eraseButton->addOptionsComboBox( m_eraseSwapChoiceComboBox );
|
||||
}
|
||||
|
||||
m_itemsLayout->addWidget( m_alongsideButton );
|
||||
m_itemsLayout->addWidget( m_replaceButton );
|
||||
m_itemsLayout->addWidget( m_eraseButton );
|
||||
|
||||
m_somethingElseButton = new PrettyRadioButton;
|
||||
CALAMARES_RETRANSLATE(
|
||||
m_somethingElseButton->setText( tr( "<strong>Manual partitioning</strong><br/>"
|
||||
"You can create or resize partitions yourself." ) );
|
||||
)
|
||||
m_somethingElseButton->setIconSize( iconSize );
|
||||
m_somethingElseButton->setIcon( CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionManual,
|
||||
CalamaresUtils::Original,
|
||||
|
@ -244,12 +294,12 @@ ChoicePage::setupChoices()
|
|||
|
||||
m_itemsLayout->addStretch();
|
||||
|
||||
connect( m_grp, static_cast< void( QButtonGroup::* )( int, bool ) >( &QButtonGroup::buttonToggled ),
|
||||
connect( m_grp, QOverload<int, bool>::of( &QButtonGroup::buttonToggled ),
|
||||
this, [ this ]( int id, bool checked )
|
||||
{
|
||||
if ( checked ) // An action was picked.
|
||||
{
|
||||
m_choice = static_cast< Choice >( id );
|
||||
m_choice = static_cast< InstallChoice >( id );
|
||||
updateNextEnabled();
|
||||
|
||||
emit actionChosen();
|
||||
|
@ -271,14 +321,16 @@ ChoicePage::setupChoices()
|
|||
m_rightLayout->setStretchFactor( m_previewAfterFrame, 0 );
|
||||
|
||||
connect( this, &ChoicePage::actionChosen,
|
||||
this, [=]
|
||||
{
|
||||
Device* currd = selectedDevice();
|
||||
if ( currd )
|
||||
{
|
||||
applyActionChoice( currentChoice() );
|
||||
}
|
||||
} );
|
||||
this, &ChoicePage::onActionChanged );
|
||||
if ( m_eraseSwapChoiceComboBox )
|
||||
connect( m_eraseSwapChoiceComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &ChoicePage::onEraseSwapChoiceChanged );
|
||||
|
||||
CALAMARES_RETRANSLATE(
|
||||
m_somethingElseButton->setText( tr( "<strong>Manual partitioning</strong><br/>"
|
||||
"You can create or resize partitions yourself." ) );
|
||||
updateSwapChoicesTr( m_eraseSwapChoiceComboBox );
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
@ -373,7 +425,27 @@ ChoicePage::continueApplyDeviceChoice()
|
|||
|
||||
|
||||
void
|
||||
ChoicePage::applyActionChoice( ChoicePage::Choice choice )
|
||||
ChoicePage::onActionChanged()
|
||||
{
|
||||
Device* currd = selectedDevice();
|
||||
if ( currd )
|
||||
{
|
||||
applyActionChoice( currentChoice() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePage::onEraseSwapChoiceChanged()
|
||||
{
|
||||
if ( m_eraseSwapChoiceComboBox )
|
||||
{
|
||||
m_eraseSwapChoice = static_cast<PartitionActions::Choices::SwapChoice>( m_eraseSwapChoiceComboBox->currentData().toInt() );
|
||||
onActionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePage::applyActionChoice( ChoicePage::InstallChoice choice )
|
||||
{
|
||||
m_beforePartitionBarsView->selectionModel()->
|
||||
disconnect( SIGNAL( currentRowChanged( QModelIndex, QModelIndex ) ) );
|
||||
|
@ -383,30 +455,37 @@ ChoicePage::applyActionChoice( ChoicePage::Choice choice )
|
|||
switch ( choice )
|
||||
{
|
||||
case Erase:
|
||||
if ( m_core->isDirty() )
|
||||
{
|
||||
ScanningDialog::run( QtConcurrent::run( [ = ]
|
||||
{
|
||||
QMutexLocker locker( &m_coreMutex );
|
||||
m_core->revertDevice( selectedDevice() );
|
||||
} ),
|
||||
[ = ]
|
||||
{
|
||||
PartitionActions::doAutopartition( m_core,
|
||||
selectedDevice(),
|
||||
m_encryptWidget->passphrase() );
|
||||
emit deviceChosen();
|
||||
},
|
||||
this );
|
||||
}
|
||||
else
|
||||
{
|
||||
PartitionActions::doAutopartition( m_core,
|
||||
selectedDevice(),
|
||||
m_encryptWidget->passphrase() );
|
||||
emit deviceChosen();
|
||||
}
|
||||
auto gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
|
||||
PartitionActions::Choices::AutoPartitionOptions options {
|
||||
gs->value( "defaultFileSystemType" ).toString(),
|
||||
m_encryptWidget->passphrase(),
|
||||
gs->value( "efiSystemPartition" ).toString(),
|
||||
CalamaresUtils::GiBtoBytes( gs->value( "requiredStorageGB" ).toDouble() ),
|
||||
m_eraseSwapChoice
|
||||
};
|
||||
|
||||
if ( m_core->isDirty() )
|
||||
{
|
||||
ScanningDialog::run( QtConcurrent::run( [ = ]
|
||||
{
|
||||
QMutexLocker locker( &m_coreMutex );
|
||||
m_core->revertDevice( selectedDevice() );
|
||||
} ),
|
||||
[ = ]
|
||||
{
|
||||
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
||||
emit deviceChosen();
|
||||
},
|
||||
this );
|
||||
}
|
||||
else
|
||||
{
|
||||
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
||||
emit deviceChosen();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Replace:
|
||||
if ( m_core->isDirty() )
|
||||
|
@ -453,7 +532,7 @@ ChoicePage::applyActionChoice( ChoicePage::Choice choice )
|
|||
case Manual:
|
||||
break;
|
||||
}
|
||||
updateActionChoicePreview( currentChoice() );
|
||||
updateActionChoicePreview( choice );
|
||||
}
|
||||
|
||||
|
||||
|
@ -484,6 +563,7 @@ ChoicePage::doAlongsideSetupSplitter( const QModelIndex& current,
|
|||
->value( "requiredStorageGB" )
|
||||
.toDouble();
|
||||
|
||||
// TODO: make this consistent
|
||||
qint64 requiredStorageB = qRound64( requiredStorageGB + 0.1 + 2.0 ) * 1024 * 1024 * 1024;
|
||||
|
||||
m_afterPartitionSplitterWidget->setSplitPartition(
|
||||
|
@ -622,39 +702,10 @@ ChoicePage::doAlongsideApply()
|
|||
dev->logicalSize();
|
||||
|
||||
m_core->resizePartition( dev, candidate, firstSector, newLastSector );
|
||||
Partition* newPartition = nullptr;
|
||||
QString luksPassphrase = m_encryptWidget->passphrase();
|
||||
if ( luksPassphrase.isEmpty() )
|
||||
{
|
||||
newPartition = KPMHelpers::createNewPartition(
|
||||
candidate->parent(),
|
||||
*dev,
|
||||
candidate->roles(),
|
||||
FileSystem::typeForName( m_defaultFsType ),
|
||||
newLastSector + 2, // *
|
||||
oldLastSector
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
newPartition = KPMHelpers::createNewEncryptedPartition(
|
||||
candidate->parent(),
|
||||
*dev,
|
||||
candidate->roles(),
|
||||
FileSystem::typeForName( m_defaultFsType ),
|
||||
newLastSector + 2, // *
|
||||
oldLastSector,
|
||||
luksPassphrase
|
||||
);
|
||||
}
|
||||
PartitionInfo::setMountPoint( newPartition, "/" );
|
||||
PartitionInfo::setFormat( newPartition, true );
|
||||
// * for some reason ped_disk_add_partition refuses to create a new partition
|
||||
// if it starts on the sector immediately after the last used sector, so we
|
||||
// have to push it one sector further, therefore + 2 instead of + 1.
|
||||
|
||||
m_core->createPartition( dev, newPartition );
|
||||
|
||||
m_core->layoutApply( dev, newLastSector + 2, oldLastSector,
|
||||
m_encryptWidget->passphrase(), candidate->parent(),
|
||||
candidate->roles()
|
||||
);
|
||||
m_core->dumpQueue();
|
||||
|
||||
break;
|
||||
|
@ -722,33 +773,10 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current )
|
|||
}
|
||||
}
|
||||
|
||||
Partition* newPartition = nullptr;
|
||||
if ( m_encryptWidget->state() == EncryptWidget::EncryptionConfirmed )
|
||||
{
|
||||
newPartition = KPMHelpers::createNewEncryptedPartition(
|
||||
newParent,
|
||||
*selectedDevice(),
|
||||
newRoles,
|
||||
FileSystem::typeForName( m_defaultFsType ),
|
||||
selectedPartition->firstSector(),
|
||||
selectedPartition->lastSector(),
|
||||
m_encryptWidget->passphrase() );
|
||||
}
|
||||
else
|
||||
{
|
||||
newPartition = KPMHelpers::createNewPartition(
|
||||
newParent,
|
||||
*selectedDevice(),
|
||||
newRoles,
|
||||
FileSystem::typeForName( m_defaultFsType ),
|
||||
selectedPartition->firstSector(),
|
||||
selectedPartition->lastSector() );
|
||||
}
|
||||
|
||||
PartitionInfo::setMountPoint( newPartition, "/" );
|
||||
PartitionInfo::setFormat( newPartition, true );
|
||||
|
||||
m_core->createPartition( selectedDevice(), newPartition);
|
||||
m_core->layoutApply( selectedDevice(), selectedPartition->firstSector(),
|
||||
selectedPartition->lastSector(),
|
||||
m_encryptWidget->passphrase(), newParent, newRoles
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -768,14 +796,19 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current )
|
|||
if ( homePartitionPath->isEmpty() )
|
||||
doReuseHomePartition = false;
|
||||
|
||||
PartitionActions::doReplacePartition( m_core,
|
||||
selectedDevice(),
|
||||
selectedPartition,
|
||||
m_encryptWidget->passphrase() );
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
|
||||
PartitionActions::doReplacePartition(
|
||||
m_core,
|
||||
selectedDevice(),
|
||||
selectedPartition,
|
||||
{
|
||||
gs->value( "defaultFileSystemType" ).toString(),
|
||||
m_encryptWidget->passphrase()
|
||||
} );
|
||||
Partition* homePartition = KPMHelpers::findPartitionByPath( { selectedDevice() },
|
||||
*homePartitionPath );
|
||||
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
if ( homePartition && doReuseHomePartition )
|
||||
{
|
||||
PartitionInfo::setMountPoint( homePartition, "/home" );
|
||||
|
@ -888,7 +921,7 @@ ChoicePage::updateDeviceStatePreview()
|
|||
* @param choice the chosen partitioning action.
|
||||
*/
|
||||
void
|
||||
ChoicePage::updateActionChoicePreview( ChoicePage::Choice choice )
|
||||
ChoicePage::updateActionChoicePreview( ChoicePage::InstallChoice choice )
|
||||
{
|
||||
Device* currentDevice = selectedDevice();
|
||||
Q_ASSERT( currentDevice );
|
||||
|
@ -1132,7 +1165,7 @@ ChoicePage::createBootloaderComboBox( QWidget* parent )
|
|||
bcb->setModel( m_core->bootLoaderModel() );
|
||||
|
||||
// When the chosen bootloader device changes, we update the choice in the PCM
|
||||
connect( bcb, static_cast< void (QComboBox::*)(int) >( &QComboBox::currentIndexChanged ),
|
||||
connect( bcb, QOverload<int>::of( &QComboBox::currentIndexChanged ),
|
||||
this, [this]( int newIndex )
|
||||
{
|
||||
QComboBox* bcb = qobject_cast< QComboBox* >( sender() );
|
||||
|
@ -1158,6 +1191,13 @@ force_uncheck(QButtonGroup* grp, PrettyRadioButton* button)
|
|||
grp->setExclusive( true );
|
||||
}
|
||||
|
||||
static inline QDebug&
|
||||
operator <<( QDebug& s, PartitionIterator& it )
|
||||
{
|
||||
s << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ChoicePage::setupActions happens every time a new Device* is selected in the
|
||||
* device picker. Sets up the text and visibility of the partitioning actions based
|
||||
|
@ -1171,32 +1211,57 @@ ChoicePage::setupActions()
|
|||
OsproberEntryList osproberEntriesForCurrentDevice =
|
||||
getOsproberEntriesForDevice( currentDevice );
|
||||
|
||||
cDebug() << "Setting up actions for" << currentDevice->deviceNode()
|
||||
<< "with" << osproberEntriesForCurrentDevice.count() << "entries.";
|
||||
|
||||
if ( currentDevice->partitionTable() )
|
||||
m_deviceInfoWidget->setPartitionTableType( currentDevice->partitionTable()->type() );
|
||||
else
|
||||
m_deviceInfoWidget->setPartitionTableType( PartitionTable::unknownTableType );
|
||||
|
||||
// Manual partitioning is always a possibility
|
||||
m_somethingElseButton->show();
|
||||
if ( m_allowManualPartitioning )
|
||||
m_somethingElseButton->show();
|
||||
else
|
||||
force_uncheck( m_grp, m_somethingElseButton );
|
||||
|
||||
bool atLeastOneCanBeResized = false;
|
||||
bool atLeastOneCanBeReplaced = false;
|
||||
bool atLeastOneIsMounted = false; // Suppress 'erase' if so
|
||||
bool isInactiveRAID = false;
|
||||
|
||||
#ifdef WITH_KPMCOREGT33
|
||||
if ( currentDevice->type() == Device::Type::SoftwareRAID_Device &&
|
||||
static_cast< SoftwareRAID* >(currentDevice)->status() == SoftwareRAID::Status::Inactive )
|
||||
{
|
||||
cDebug() << ".. part of an inactive RAID device";
|
||||
isInactiveRAID = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( auto it = PartitionIterator::begin( currentDevice );
|
||||
it != PartitionIterator::end( currentDevice ); ++it )
|
||||
{
|
||||
if ( PartUtils::canBeResized( *it ) )
|
||||
{
|
||||
cDebug() << ".. contains resizable" << it;
|
||||
atLeastOneCanBeResized = true;
|
||||
}
|
||||
if ( PartUtils::canBeReplaced( *it ) )
|
||||
{
|
||||
cDebug() << ".. contains replacable" << it;
|
||||
atLeastOneCanBeReplaced = true;
|
||||
}
|
||||
if ( (*it)->isMounted() )
|
||||
{
|
||||
cDebug() << ".. contains mounted" << it;
|
||||
atLeastOneIsMounted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( osproberEntriesForCurrentDevice.count() == 0 )
|
||||
{
|
||||
CALAMARES_RETRANSLATE(
|
||||
cDebug() << "Setting texts for 0 osprober entries";
|
||||
m_messageLabel->setText( tr( "This storage device does not seem to have an operating system on it. "
|
||||
"What would you like to do?<br/>"
|
||||
"You will be able to review and confirm your choices "
|
||||
|
@ -1229,6 +1294,7 @@ ChoicePage::setupActions()
|
|||
if ( !osName.isEmpty() )
|
||||
{
|
||||
CALAMARES_RETRANSLATE(
|
||||
cDebug() << "Setting texts for 1 non-empty osprober entry";
|
||||
m_messageLabel->setText( tr( "This storage device has %1 on it. "
|
||||
"What would you like to do?<br/>"
|
||||
"You will be able to review and confirm your choices "
|
||||
|
@ -1252,6 +1318,7 @@ ChoicePage::setupActions()
|
|||
else
|
||||
{
|
||||
CALAMARES_RETRANSLATE(
|
||||
cDebug() << "Setting texts for 1 empty osprober entry";
|
||||
m_messageLabel->setText( tr( "This storage device already has an operating system on it. "
|
||||
"What would you like to do?<br/>"
|
||||
"You will be able to review and confirm your choices "
|
||||
|
@ -1276,6 +1343,8 @@ ChoicePage::setupActions()
|
|||
// osproberEntriesForCurrentDevice has at least 2 items.
|
||||
|
||||
CALAMARES_RETRANSLATE(
|
||||
cDebug() << "Setting texts for >= 2 osprober entries";
|
||||
|
||||
m_messageLabel->setText( tr( "This storage device has multiple operating systems on it. "
|
||||
"What would you like to do?<br/>"
|
||||
"You will be able to review and confirm your choices "
|
||||
|
@ -1305,10 +1374,15 @@ ChoicePage::setupActions()
|
|||
else
|
||||
force_uncheck( m_grp, m_alongsideButton );
|
||||
|
||||
if ( !atLeastOneIsMounted )
|
||||
if ( !atLeastOneIsMounted && !isInactiveRAID )
|
||||
m_eraseButton->show(); // None mounted
|
||||
else
|
||||
{
|
||||
cDebug() << "Erase button suppressed"
|
||||
<< "mount?" << atLeastOneIsMounted
|
||||
<< "raid?" << isInactiveRAID;
|
||||
force_uncheck( m_grp, m_eraseButton );
|
||||
}
|
||||
|
||||
bool isEfi = PartUtils::isEfiSystem();
|
||||
bool efiSystemPartitionFound = !m_core->efiSystemPartitions().isEmpty();
|
||||
|
@ -1343,7 +1417,7 @@ ChoicePage::isNextEnabled() const
|
|||
}
|
||||
|
||||
|
||||
ChoicePage::Choice
|
||||
ChoicePage::InstallChoice
|
||||
ChoicePage::currentChoice() const
|
||||
{
|
||||
return m_choice;
|
||||
|
@ -1391,3 +1465,55 @@ ChoicePage::updateNextEnabled()
|
|||
emit nextStatusChanged( enabled );
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePage::updateSwapChoicesTr(QComboBox* box)
|
||||
{
|
||||
if ( !box )
|
||||
return;
|
||||
|
||||
static_assert(SwapChoice::NoSwap == 0, "Enum values out-of-sync");
|
||||
for ( int index = 0; index < box->count(); ++index )
|
||||
{
|
||||
bool ok = false;
|
||||
int value = 0;
|
||||
|
||||
switch ( value = box->itemData( index ).toInt( &ok ) )
|
||||
{
|
||||
// case 0:
|
||||
case SwapChoice::NoSwap:
|
||||
// toInt() returns 0 on failure, so check for ok
|
||||
if ( ok ) // It was explicitly set to 0
|
||||
box->setItemText( index, tr( "No Swap" ) );
|
||||
else
|
||||
cWarning() << "Box item" << index << box->itemText( index ) << "has non-integer role.";
|
||||
break;
|
||||
case SwapChoice::ReuseSwap:
|
||||
box->setItemText( index, tr( "Reuse Swap" ) );
|
||||
break;
|
||||
case SwapChoice::SmallSwap:
|
||||
box->setItemText( index, tr( "Swap (no Hibernate)" ) );
|
||||
break;
|
||||
case SwapChoice::FullSwap:
|
||||
box->setItemText( index, tr( "Swap (with Hibernate)" ) );
|
||||
break;
|
||||
case SwapChoice::SwapFile:
|
||||
box->setItemText( index, tr( "Swap to file" ) );
|
||||
break;
|
||||
default:
|
||||
cWarning() << "Box item" << index << box->itemText( index ) << "has role" << value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ChoicePage::lastSelectedDeviceIndex()
|
||||
{
|
||||
return m_lastSelectedDeviceIndex;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePage::setLastSelectedDeviceIndex( int index )
|
||||
{
|
||||
m_lastSelectedDeviceIndex = index;
|
||||
m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex );
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2018-2019, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,9 +26,11 @@
|
|||
#include <QWidget>
|
||||
|
||||
#include "core/OsproberEntry.h"
|
||||
#include "core/PartitionActions.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
|
||||
class QBoxLayout;
|
||||
class QComboBox;
|
||||
|
@ -43,6 +46,7 @@ class DeviceInfoWidget;
|
|||
|
||||
class Device;
|
||||
|
||||
using SwapChoiceSet = QSet< PartitionActions::Choices::SwapChoice >;
|
||||
|
||||
/**
|
||||
* @brief The ChoicePage class is the first page of the partitioning interface.
|
||||
|
@ -53,7 +57,7 @@ class ChoicePage : public QWidget, private Ui::ChoicePage
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Choice
|
||||
enum InstallChoice
|
||||
{
|
||||
NoChoice,
|
||||
Alongside,
|
||||
|
@ -62,7 +66,7 @@ public:
|
|||
Manual
|
||||
};
|
||||
|
||||
explicit ChoicePage( QWidget* parent = nullptr );
|
||||
explicit ChoicePage( const SwapChoiceSet& swapChoices, QWidget* parent = nullptr );
|
||||
virtual ~ChoicePage();
|
||||
|
||||
/**
|
||||
|
@ -84,7 +88,7 @@ public:
|
|||
* currently selected partitioning mode (with a PrettyRadioButton).
|
||||
* @return the enum Choice value.
|
||||
*/
|
||||
Choice currentChoice() const;
|
||||
InstallChoice currentChoice() const;
|
||||
|
||||
/**
|
||||
* @brief onLeave runs when control passes from this page to another one.
|
||||
|
@ -95,7 +99,10 @@ public:
|
|||
* @brief applyActionChoice reacts to a choice of partitioning mode.
|
||||
* @param choice the partitioning action choice.
|
||||
*/
|
||||
void applyActionChoice( ChoicePage::Choice choice );
|
||||
void applyActionChoice( ChoicePage::InstallChoice choice );
|
||||
|
||||
int lastSelectedDeviceIndex();
|
||||
void setLastSelectedDeviceIndex( int index );
|
||||
|
||||
signals:
|
||||
void nextStatusChanged( bool );
|
||||
|
@ -109,6 +116,11 @@ private slots:
|
|||
void onEncryptWidgetStateChanged();
|
||||
void onHomeCheckBoxStateChanged();
|
||||
|
||||
/// @brief Calls applyActionChoice() as needed.
|
||||
void onActionChanged();
|
||||
/// @brief Calls onActionChanged() as needed.
|
||||
void onEraseSwapChoiceChanged();
|
||||
|
||||
private:
|
||||
void updateNextEnabled();
|
||||
void setupChoices();
|
||||
|
@ -121,18 +133,21 @@ private:
|
|||
void continueApplyDeviceChoice(); // .. called after scan
|
||||
|
||||
void updateDeviceStatePreview();
|
||||
void updateActionChoicePreview( ChoicePage::Choice choice );
|
||||
void updateActionChoicePreview( ChoicePage::InstallChoice choice );
|
||||
void setupActions();
|
||||
OsproberEntryList getOsproberEntriesForDevice( Device* device ) const;
|
||||
void doAlongsideApply();
|
||||
void setupEfiSystemPartitionSelector();
|
||||
|
||||
// Translations support
|
||||
void updateSwapChoicesTr( QComboBox* box );
|
||||
|
||||
bool m_nextEnabled;
|
||||
PartitionCoreModule* m_core;
|
||||
|
||||
QMutex m_previewsMutex;
|
||||
|
||||
Choice m_choice;
|
||||
InstallChoice m_choice;
|
||||
|
||||
bool m_isEfi;
|
||||
QComboBox* m_drivesCombo;
|
||||
|
@ -142,6 +157,7 @@ private:
|
|||
PrettyRadioButton* m_eraseButton;
|
||||
PrettyRadioButton* m_replaceButton;
|
||||
PrettyRadioButton* m_somethingElseButton;
|
||||
QComboBox* m_eraseSwapChoiceComboBox; // UI, see also m_eraseSwapChoice
|
||||
|
||||
DeviceInfoWidget* m_deviceInfoWidget;
|
||||
|
||||
|
@ -158,6 +174,10 @@ private:
|
|||
|
||||
QString m_defaultFsType;
|
||||
bool m_enableEncryptionWidget;
|
||||
SwapChoiceSet m_availableSwapChoices; // What is available
|
||||
PartitionActions::Choices::SwapChoice m_eraseSwapChoice; // what is selected
|
||||
|
||||
bool m_allowManualPartitioning;
|
||||
|
||||
QMutex m_coreMutex;
|
||||
};
|
||||
|
|
|
@ -72,7 +72,7 @@ CreatePartitionDialog::CreatePartitionDialog( Device* device, PartitionNode* par
|
|||
m_ui->encryptWidget->setText( tr( "En&crypt" ) );
|
||||
m_ui->encryptWidget->hide();
|
||||
|
||||
if (m_device->type() == Device::Type::Disk_Device) {
|
||||
if (m_device->type() != Device::Type::LVM_Device) {
|
||||
m_ui->lvNameLabel->hide();
|
||||
m_ui->lvNameLineEdit->hide();
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ void
|
|||
standardMountPoints(QComboBox& combo)
|
||||
{
|
||||
combo.clear();
|
||||
combo.addItem( combo.tr( "(no mount point)" ) );
|
||||
combo.addItem( QObject::tr( "(no mount point)" ) );
|
||||
combo.addItems( standardMountPoints() );
|
||||
}
|
||||
|
||||
|
|
|
@ -185,26 +185,35 @@ PartitionLabelsView::buildTexts( const QModelIndex& index ) const
|
|||
|
||||
if ( index.data( PartitionModel::IsPartitionNewRole ).toBool() )
|
||||
{
|
||||
QString mountPoint = index.sibling( index.row(),
|
||||
PartitionModel::MountPointColumn )
|
||||
.data().toString();
|
||||
if ( mountPoint == "/" )
|
||||
firstLine = m_customNewRootLabel.isEmpty() ?
|
||||
tr( "Root" ) :
|
||||
m_customNewRootLabel;
|
||||
else if ( mountPoint == "/home" )
|
||||
firstLine = tr( "Home" );
|
||||
else if ( mountPoint == "/boot" )
|
||||
firstLine = tr( "Boot" );
|
||||
else if ( mountPoint.contains( "/efi" ) &&
|
||||
index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::Fat32 )
|
||||
firstLine = tr( "EFI system" );
|
||||
else if ( index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::LinuxSwap )
|
||||
firstLine = tr( "Swap" );
|
||||
else if ( !mountPoint.isEmpty() )
|
||||
firstLine = tr( "New partition for %1" ).arg( mountPoint );
|
||||
QString label = index.data( PartitionModel::FileSystemLabelRole ).toString();
|
||||
|
||||
if ( !label.isEmpty() )
|
||||
{
|
||||
firstLine = label;
|
||||
}
|
||||
else
|
||||
firstLine = tr( "New partition" );
|
||||
{
|
||||
QString mountPoint = index.sibling( index.row(),
|
||||
PartitionModel::MountPointColumn )
|
||||
.data().toString();
|
||||
if ( mountPoint == "/" )
|
||||
firstLine = m_customNewRootLabel.isEmpty() ?
|
||||
tr( "Root" ) :
|
||||
m_customNewRootLabel;
|
||||
else if ( mountPoint == "/home" )
|
||||
firstLine = tr( "Home" );
|
||||
else if ( mountPoint == "/boot" )
|
||||
firstLine = tr( "Boot" );
|
||||
else if ( mountPoint.contains( "/efi" ) &&
|
||||
index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::Fat32 )
|
||||
firstLine = tr( "EFI system" );
|
||||
else if ( index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::LinuxSwap )
|
||||
firstLine = tr( "Swap" );
|
||||
else if ( !mountPoint.isEmpty() )
|
||||
firstLine = tr( "New partition for %1" ).arg( mountPoint );
|
||||
else
|
||||
firstLine = tr( "New partition" );
|
||||
}
|
||||
}
|
||||
else if ( index.data( PartitionModel::OsproberNameRole ).toString().isEmpty() )
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* Copyright 2015-2016, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2018, Andrius Štikonas <andrius@stikonas.eu>
|
||||
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.com>
|
||||
* Copyright 2019, Collabora Ltd
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -47,6 +49,9 @@
|
|||
// KPMcore
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
#ifdef WITH_KPMCOREGT33
|
||||
#include <kpmcore/core/softwareraid.h>
|
||||
#endif
|
||||
#include <kpmcore/ops/deactivatevolumegroupoperation.h>
|
||||
#include <kpmcore/ops/removevolumegroupoperation.h>
|
||||
|
||||
|
@ -146,6 +151,7 @@ PartitionPage::updateButtons()
|
|||
bool isInVG = m_core->isInVG( partition );
|
||||
|
||||
create = isFree;
|
||||
|
||||
// Keep it simple for now: do not support editing extended partitions as
|
||||
// it does not work with our current edit implementation which is
|
||||
// actually remove + add. This would not work with extended partitions
|
||||
|
@ -159,9 +165,25 @@ PartitionPage::updateButtons()
|
|||
|
||||
if ( m_ui->deviceComboBox->currentIndex() >= 0 )
|
||||
{
|
||||
Device* device = nullptr;
|
||||
QModelIndex deviceIndex = m_core->deviceModel()->index( m_ui->deviceComboBox->currentIndex(), 0 );
|
||||
if ( m_core->deviceModel()->deviceForIndex( deviceIndex )->type() != Device::Type::LVM_Device )
|
||||
if ( deviceIndex.isValid() )
|
||||
device = m_core->deviceModel()->deviceForIndex( deviceIndex );
|
||||
if ( !device )
|
||||
cWarning() << "Device for updateButtons is nullptr";
|
||||
else if ( device->type() != Device::Type::LVM_Device )
|
||||
{
|
||||
createTable = true;
|
||||
|
||||
#ifdef WITH_KPMCOREGT33
|
||||
if ( device->type() == Device::Type::SoftwareRAID_Device &&
|
||||
static_cast< SoftwareRAID* >(device)->status() == SoftwareRAID::Status::Inactive )
|
||||
{
|
||||
createTable = false;
|
||||
create = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
currentDeviceIsVG = true;
|
||||
|
@ -559,7 +581,7 @@ void
|
|||
PartitionPage::onPartitionModelReset()
|
||||
{
|
||||
m_ui->partitionTreeView->expandAll();
|
||||
updateButtons();
|
||||
// updateButtons();
|
||||
updateBootLoaderIndex();
|
||||
}
|
||||
|
||||
|
@ -592,3 +614,15 @@ PartitionPage::getCurrentUsedMountpoints()
|
|||
|
||||
return mountPoints;
|
||||
}
|
||||
|
||||
int
|
||||
PartitionPage::selectedDeviceIndex()
|
||||
{
|
||||
return m_ui->deviceComboBox->currentIndex();
|
||||
}
|
||||
|
||||
void
|
||||
PartitionPage::selectDeviceByIndex ( int index )
|
||||
{
|
||||
m_ui->deviceComboBox->setCurrentIndex( index );
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -46,6 +47,9 @@ public:
|
|||
|
||||
void onRevertClicked();
|
||||
|
||||
int selectedDeviceIndex();
|
||||
void selectDeviceByIndex( int index );
|
||||
|
||||
private:
|
||||
QScopedPointer< Ui_PartitionPage > m_ui;
|
||||
PartitionCoreModule* m_core;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
|
||||
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include "gui/PartitionViewStep.h"
|
||||
|
||||
#include "core/DeviceModel.h"
|
||||
#include "core/PartitionActions.h"
|
||||
#include "core/PartitionCoreModule.h"
|
||||
#include "core/PartitionModel.h"
|
||||
#include "core/KPMHelpers.h"
|
||||
|
@ -34,6 +36,7 @@
|
|||
#include "CalamaresVersion.h"
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/NamedEnum.h"
|
||||
#include "utils/Retranslator.h"
|
||||
#include "widgets/WaitingWidget.h"
|
||||
#include "GlobalStorage.h"
|
||||
|
@ -92,7 +95,7 @@ PartitionViewStep::continueLoading()
|
|||
Q_ASSERT( !m_manualPartitionPage );
|
||||
|
||||
m_manualPartitionPage = new PartitionPage( m_core );
|
||||
m_choicePage = new ChoicePage();
|
||||
m_choicePage = new ChoicePage( m_swapChoices );
|
||||
|
||||
m_choicePage->init( m_core );
|
||||
|
||||
|
@ -140,7 +143,7 @@ PartitionViewStep::createSummaryWidget() const
|
|||
widget->setLayout( mainLayout );
|
||||
mainLayout->setMargin( 0 );
|
||||
|
||||
ChoicePage::Choice choice = m_choicePage->currentChoice();
|
||||
ChoicePage::InstallChoice choice = m_choicePage->currentChoice();
|
||||
|
||||
QFormLayout* formLayout = new QFormLayout( widget );
|
||||
const int MARGIN = CalamaresUtils::defaultFontHeight() / 2;
|
||||
|
@ -287,6 +290,7 @@ PartitionViewStep::next()
|
|||
if ( m_choicePage->currentChoice() == ChoicePage::Manual )
|
||||
{
|
||||
m_widget->setCurrentWidget( m_manualPartitionPage );
|
||||
m_manualPartitionPage->selectDeviceByIndex( m_choicePage->lastSelectedDeviceIndex() );
|
||||
if ( m_core->isDirty() )
|
||||
m_manualPartitionPage->onRevertClicked();
|
||||
}
|
||||
|
@ -316,7 +320,10 @@ void
|
|||
PartitionViewStep::back()
|
||||
{
|
||||
if ( m_widget->currentWidget() != m_choicePage )
|
||||
{
|
||||
m_widget->setCurrentWidget( m_choicePage );
|
||||
m_choicePage->setLastSelectedDeviceIndex( m_manualPartitionPage->selectedDeviceIndex() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -472,72 +479,160 @@ PartitionViewStep::onLeave()
|
|||
}
|
||||
|
||||
|
||||
static PartitionActions::Choices::SwapChoice
|
||||
nameToChoice( QString name, bool& ok )
|
||||
{
|
||||
using namespace PartitionActions::Choices;
|
||||
|
||||
static const NamedEnumTable<SwapChoice> names {
|
||||
{ QStringLiteral( "none" ), SwapChoice::NoSwap },
|
||||
{ QStringLiteral( "small" ), SwapChoice::SmallSwap },
|
||||
{ QStringLiteral( "suspend" ), SwapChoice::FullSwap },
|
||||
{ QStringLiteral( "reuse" ), SwapChoice::ReuseSwap },
|
||||
{ QStringLiteral( "file" ), SwapChoice::SwapFile }
|
||||
};
|
||||
|
||||
return names.find( name, ok );
|
||||
}
|
||||
|
||||
/** @brief translate @p defaultFS into a recognized name
|
||||
*
|
||||
* Makes several attempts to translate the string into a
|
||||
* name that KPMCore will recognize.
|
||||
*/
|
||||
static QString
|
||||
findFS( QString defaultFS )
|
||||
{
|
||||
QStringList fsLanguage { QLatin1Literal( "C" ) }; // Required language list to turn off localization
|
||||
if ( defaultFS.isEmpty() )
|
||||
{
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* is missing, using ext4";
|
||||
defaultFS = QStringLiteral( "ext4" );
|
||||
}
|
||||
if ( FileSystem::typeForName( defaultFS, fsLanguage ) != FileSystem::Unknown )
|
||||
{
|
||||
cDebug() << "Partition-module setting *defaultFileSystemType*" << defaultFS;
|
||||
return defaultFS;
|
||||
}
|
||||
|
||||
// Second pass: try case-insensitive
|
||||
const auto fstypes = FileSystem::types();
|
||||
for ( FileSystem::Type t : fstypes )
|
||||
{
|
||||
if ( 0 == QString::compare( defaultFS, FileSystem::nameForType( t, fsLanguage ), Qt::CaseInsensitive ) )
|
||||
{
|
||||
defaultFS = FileSystem::nameForType( t, fsLanguage );
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* changed" << defaultFS;
|
||||
return defaultFS;
|
||||
}
|
||||
}
|
||||
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* is bad (" << defaultFS << ") using ext4.";
|
||||
defaultFS = QStringLiteral( "ext4" );
|
||||
#ifdef DEBUG_FILESYSTEMS
|
||||
// This bit is for distro's debugging their settings, and shows
|
||||
// all the strings that KPMCore is matching against for FS type.
|
||||
{
|
||||
Logger::CDebug d;
|
||||
using TR = Logger::DebugRow< int, QString >;
|
||||
const auto fstypes = FileSystem::types();
|
||||
d << "Available types (" << fstypes.count() << ')';
|
||||
for ( FileSystem::Type t : fstypes )
|
||||
d << TR( static_cast<int>( t ), FileSystem::nameForType( t, fsLanguage ) );
|
||||
}
|
||||
#endif
|
||||
return defaultFS;
|
||||
}
|
||||
|
||||
void
|
||||
PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
// Copy the efiSystemPartition setting to the global storage. It is needed not only in
|
||||
// the EraseDiskPage, but also in the bootloader configuration modules (grub, bootloader).
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
if ( configurationMap.contains( "efiSystemPartition" ) &&
|
||||
configurationMap.value( "efiSystemPartition" ).type() == QVariant::String &&
|
||||
!configurationMap.value( "efiSystemPartition" ).toString().isEmpty() )
|
||||
gs->insert( "efiSystemPartition", configurationMap.value( "efiSystemPartition" ).toString() );
|
||||
else
|
||||
gs->insert( "efiSystemPartition", QStringLiteral( "/boot/efi" ) );
|
||||
QString efiSP = CalamaresUtils::getString( configurationMap, "efiSystemPartition" );
|
||||
if ( efiSP.isEmpty() )
|
||||
efiSP = QStringLiteral( "/boot/efi" );
|
||||
gs->insert( "efiSystemPartition", efiSP );
|
||||
|
||||
if ( configurationMap.contains( "ensureSuspendToDisk" ) &&
|
||||
configurationMap.value( "ensureSuspendToDisk" ).type() == QVariant::Bool )
|
||||
gs->insert( "ensureSuspendToDisk", configurationMap.value( "ensureSuspendToDisk" ).toBool() );
|
||||
else
|
||||
gs->insert( "ensureSuspendToDisk", true );
|
||||
// SWAP SETTINGS
|
||||
//
|
||||
// This is a bit convoluted because there's legacy settings to handle as well
|
||||
// as the new-style list of choices, with mapping back-and-forth.
|
||||
if ( configurationMap.contains( "userSwapChoices" ) &&
|
||||
( configurationMap.contains( "ensureSuspendToDisk" ) || configurationMap.contains( "neverCreateSwap" ) ) )
|
||||
cError() << "Partition-module configuration mixes old- and new-style swap settings.";
|
||||
|
||||
if ( configurationMap.contains( "neverCreateSwap" ) &&
|
||||
configurationMap.value( "neverCreateSwap" ).type() == QVariant::Bool )
|
||||
gs->insert( "neverCreateSwap", configurationMap.value( "neverCreateSwap" ).toBool() );
|
||||
else
|
||||
gs->insert( "neverCreateSwap", false );
|
||||
if ( configurationMap.contains( "ensureSuspendToDisk" ) )
|
||||
cWarning() << "Partition-module setting *ensureSuspendToDisk* is deprecated.";
|
||||
bool ensureSuspendToDisk = CalamaresUtils::getBool( configurationMap, "ensureSuspendToDisk", true );
|
||||
|
||||
if ( configurationMap.contains( "drawNestedPartitions" ) &&
|
||||
configurationMap.value( "drawNestedPartitions" ).type() == QVariant::Bool )
|
||||
if ( configurationMap.contains( "neverCreateSwap" ) )
|
||||
cWarning() << "Partition-module setting *neverCreateSwap* is deprecated.";
|
||||
bool neverCreateSwap = CalamaresUtils::getBool( configurationMap, "neverCreateSwap", false );
|
||||
|
||||
QSet< PartitionActions::Choices::SwapChoice > choices; // Available swap choices
|
||||
if ( configurationMap.contains( "userSwapChoices" ) )
|
||||
{
|
||||
gs->insert( "drawNestedPartitions",
|
||||
configurationMap.value( "drawNestedPartitions", false ).toBool() );
|
||||
}
|
||||
else
|
||||
gs->insert( "drawNestedPartitions", false );
|
||||
// We've already warned about overlapping settings with the
|
||||
// legacy *ensureSuspendToDisk* and *neverCreateSwap*.
|
||||
QStringList l = configurationMap[ "userSwapChoices" ].toStringList();
|
||||
|
||||
if ( configurationMap.contains( "alwaysShowPartitionLabels" ) &&
|
||||
configurationMap.value( "alwaysShowPartitionLabels" ).type() == QVariant::Bool )
|
||||
{
|
||||
gs->insert( "alwaysShowPartitionLabels",
|
||||
configurationMap.value( "alwaysShowPartitionLabels", true ).toBool() );
|
||||
}
|
||||
else
|
||||
gs->insert( "alwaysShowPartitionLabels", true );
|
||||
|
||||
if ( configurationMap.contains( "defaultFileSystemType" ) &&
|
||||
configurationMap.value( "defaultFileSystemType" ).type() == QVariant::String &&
|
||||
!configurationMap.value( "defaultFileSystemType" ).toString().isEmpty() )
|
||||
{
|
||||
QString typeString = configurationMap.value( "defaultFileSystemType" ).toString();
|
||||
gs->insert( "defaultFileSystemType", typeString );
|
||||
if ( FileSystem::typeForName( typeString ) == FileSystem::Unknown )
|
||||
for ( const auto& item : l )
|
||||
{
|
||||
cWarning() << "bad default filesystem configuration for partition module. Reverting to ext4 as default.";
|
||||
gs->insert( "defaultFileSystemType", "ext4" );
|
||||
bool ok = false;
|
||||
auto v = PartitionActions::Choices::nameToChoice( item, ok );
|
||||
if ( ok )
|
||||
choices.insert( v );
|
||||
}
|
||||
}
|
||||
else
|
||||
gs->insert( "defaultFileSystemType", QStringLiteral( "ext4" ) );
|
||||
|
||||
if ( configurationMap.contains( "enableLuksAutomatedPartitioning" ) &&
|
||||
configurationMap.value( "enableLuksAutomatedPartitioning" ).type() == QVariant::Bool )
|
||||
{
|
||||
gs->insert( "enableLuksAutomatedPartitioning",
|
||||
configurationMap.value( "enableLuksAutomatedPartitioning" ).toBool() );
|
||||
if ( choices.isEmpty() )
|
||||
{
|
||||
cWarning() << "Partition-module configuration for *userSwapChoices* is empty:" << l;
|
||||
choices.insert( PartitionActions::Choices::SwapChoice::FullSwap );
|
||||
}
|
||||
|
||||
// suspend if it's one of the possible choices; suppress swap only if it's
|
||||
// the **only** choice available.
|
||||
ensureSuspendToDisk = choices.contains( PartitionActions::Choices::SwapChoice::FullSwap );
|
||||
neverCreateSwap = ( choices.count() == 1 ) && choices.contains( PartitionActions::Choices::SwapChoice::NoSwap );
|
||||
}
|
||||
else
|
||||
gs->insert( "enableLuksAutomatedPartitioning", true );
|
||||
{
|
||||
// Convert the legacy settings into a single setting for now.
|
||||
if ( neverCreateSwap )
|
||||
choices.insert( PartitionActions::Choices::SwapChoice::NoSwap );
|
||||
else if ( ensureSuspendToDisk )
|
||||
choices.insert( PartitionActions::Choices::SwapChoice::FullSwap );
|
||||
else
|
||||
choices.insert( PartitionActions::Choices::SwapChoice::SmallSwap );
|
||||
}
|
||||
|
||||
// Not all are supported right now // FIXME
|
||||
static const char unsupportedSetting[] = "Partition-module does not support *userSwapChoices* setting";
|
||||
|
||||
#define COMPLAIN_UNSUPPORTED(x) \
|
||||
if ( choices.contains( x ) ) \
|
||||
{ cWarning() << unsupportedSetting << PartitionActions::Choices::choiceToName( x ); choices.remove( x ); }
|
||||
|
||||
COMPLAIN_UNSUPPORTED( PartitionActions::Choices::SwapChoice::SwapFile )
|
||||
COMPLAIN_UNSUPPORTED( PartitionActions::Choices::SwapChoice::ReuseSwap )
|
||||
#undef COMPLAIN_UNSUPPORTED
|
||||
|
||||
m_swapChoices = choices;
|
||||
|
||||
// These gs settings seem to be unused (in upstream Calamares) outside of
|
||||
// the partition module itself.
|
||||
gs->insert( "ensureSuspendToDisk", ensureSuspendToDisk );
|
||||
gs->insert( "neverCreateSwap", neverCreateSwap );
|
||||
|
||||
// OTHER SETTINGS
|
||||
//
|
||||
gs->insert( "drawNestedPartitions", CalamaresUtils::getBool( configurationMap, "drawNestedPartitions", false ) );
|
||||
gs->insert( "alwaysShowPartitionLabels", CalamaresUtils::getBool( configurationMap, "alwaysShowPartitionLabels", true ) );
|
||||
gs->insert( "enableLuksAutomatedPartitioning", CalamaresUtils::getBool( configurationMap, "enableLuksAutomatedPartitioning", true ) );
|
||||
gs->insert( "allowManualPartitioning", CalamaresUtils::getBool( configurationMap, "allowManualPartitioning", true ) );
|
||||
gs->insert( "defaultFileSystemType", findFS( CalamaresUtils::getString( configurationMap, "defaultFileSystemType" ) ) );
|
||||
|
||||
|
||||
// Now that we have the config, we load the PartitionCoreModule in the background
|
||||
|
@ -555,6 +650,15 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
|||
QFuture< void > future =
|
||||
QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
|
||||
m_future->setFuture( future );
|
||||
|
||||
if ( configurationMap.contains( "partitionLayout" ) )
|
||||
{
|
||||
m_core->initLayout( configurationMap.values( "partitionLayout" ).at(0).toList() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_core->initLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,10 @@
|
|||
|
||||
#include <PluginDllMacro.h>
|
||||
|
||||
#include "core/PartitionActions.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
class ChoicePage;
|
||||
class PartitionPage;
|
||||
|
@ -81,6 +84,8 @@ private:
|
|||
|
||||
QWidget* m_waitingWidget;
|
||||
QFutureWatcher<void>* m_future;
|
||||
|
||||
QSet< PartitionActions::Choices::SwapChoice > m_swapChoices;
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( PartitionViewStepFactory )
|
||||
|
|
|
@ -21,29 +21,34 @@
|
|||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "widgets/ClickableLabel.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QBoxLayout>
|
||||
|
||||
|
||||
PrettyRadioButton::PrettyRadioButton( QWidget* parent )
|
||||
: QWidget( parent )
|
||||
, m_label( new ClickableLabel )
|
||||
, m_radio( new QRadioButton )
|
||||
, m_mainLayout( new QGridLayout )
|
||||
, m_optionsLayout( nullptr )
|
||||
{
|
||||
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||||
setLayout( mainLayout );
|
||||
setLayout( m_mainLayout );
|
||||
|
||||
m_radio = new QRadioButton;
|
||||
m_label = new ClickableLabel;
|
||||
|
||||
connect( m_label, &ClickableLabel::clicked,
|
||||
m_radio, &QRadioButton::click );
|
||||
m_label->setBuddy( m_radio );
|
||||
|
||||
m_label->setWordWrap( true );
|
||||
m_label->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
|
||||
|
||||
mainLayout->addWidget( m_radio );
|
||||
mainLayout->addWidget( m_label );
|
||||
mainLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
m_mainLayout->addWidget( m_radio, 0, 0 );
|
||||
m_mainLayout->addWidget( m_label, 0, 1 );
|
||||
m_mainLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
|
||||
connect( m_label, &ClickableLabel::clicked,
|
||||
m_radio, &QRadioButton::click );
|
||||
connect( m_radio, &QRadioButton::toggled,
|
||||
this, &PrettyRadioButton::toggleOptions );
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,3 +85,32 @@ PrettyRadioButton::buttonWidget() const
|
|||
{
|
||||
return m_radio;
|
||||
}
|
||||
|
||||
void
|
||||
PrettyRadioButton::addOptionsComboBox( QComboBox* box )
|
||||
{
|
||||
if ( !box )
|
||||
return;
|
||||
|
||||
if ( !m_optionsLayout )
|
||||
{
|
||||
QWidget* w = new QWidget;
|
||||
m_optionsLayout = new QHBoxLayout;
|
||||
m_optionsLayout->setAlignment( Qt::AlignmentFlag::AlignLeft );
|
||||
m_optionsLayout->addStretch( 1 );
|
||||
|
||||
w->setLayout( m_optionsLayout );
|
||||
m_mainLayout->addWidget( w, 1, 1 );
|
||||
|
||||
toggleOptions( m_radio->isChecked() );
|
||||
}
|
||||
|
||||
m_optionsLayout->insertWidget( m_optionsLayout->count()-1, box );
|
||||
}
|
||||
|
||||
void
|
||||
PrettyRadioButton::toggleOptions( bool toggle )
|
||||
{
|
||||
if ( m_optionsLayout )
|
||||
m_optionsLayout->parentWidget()->setVisible( toggle );
|
||||
}
|
||||
|
|
|
@ -22,7 +22,17 @@
|
|||
#include <QRadioButton>
|
||||
|
||||
class ClickableLabel;
|
||||
class QComboBox;
|
||||
class QGridLayout;
|
||||
class QHBoxLayout;
|
||||
|
||||
/** @brief A radio button with fancy label next to it.
|
||||
*
|
||||
* The radio button itself can be retrieved with buttonWidget(),
|
||||
* and the whole behaves a lot like a label. Extra options can be
|
||||
* added to the display (options are hidden when the button is
|
||||
* not selected) with addOptionsComboBox().
|
||||
*/
|
||||
class PrettyRadioButton : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -40,9 +50,18 @@ public:
|
|||
|
||||
virtual QRadioButton* buttonWidget() const;
|
||||
|
||||
/** @brief Add an options drop-down to this button. */
|
||||
void addOptionsComboBox( QComboBox* );
|
||||
|
||||
protected slots:
|
||||
/// Options are hidden when the radio button is off
|
||||
void toggleOptions( bool checked );
|
||||
|
||||
protected:
|
||||
ClickableLabel* m_label;
|
||||
QRadioButton* m_radio;
|
||||
QGridLayout* m_mainLayout;
|
||||
QHBoxLayout* m_optionsLayout;
|
||||
};
|
||||
|
||||
#endif // PRETTYRADIOBUTTON_H
|
||||
|
|
|
@ -85,6 +85,8 @@ ReplaceWidget::reset()
|
|||
void
|
||||
ReplaceWidget::applyChanges()
|
||||
{
|
||||
auto gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
|
||||
PartitionModel* model = qobject_cast< PartitionModel* >( m_ui->partitionTreeView->model() );
|
||||
if ( model )
|
||||
{
|
||||
|
@ -93,7 +95,9 @@ ReplaceWidget::applyChanges()
|
|||
{
|
||||
Device* dev = model->device();
|
||||
|
||||
PartitionActions::doReplacePartition( m_core, dev, partition );
|
||||
PartitionActions::doReplacePartition(
|
||||
m_core, dev, partition,
|
||||
{ gs->value( "defaultFileSystemType" ).toString(), QString() } );
|
||||
|
||||
if ( m_isEfi )
|
||||
{
|
||||
|
@ -102,17 +106,13 @@ ReplaceWidget::applyChanges()
|
|||
{
|
||||
PartitionInfo::setMountPoint(
|
||||
efiSystemPartitions.first(),
|
||||
Calamares::JobQueue::instance()->
|
||||
globalStorage()->
|
||||
value( "efiSystemPartition" ).toString() );
|
||||
gs->value( "efiSystemPartition" ).toString() );
|
||||
}
|
||||
else if ( efiSystemPartitions.count() > 1 )
|
||||
{
|
||||
PartitionInfo::setMountPoint(
|
||||
efiSystemPartitions.at( m_ui->bootComboBox->currentIndex() ),
|
||||
Calamares::JobQueue::instance()->
|
||||
globalStorage()->
|
||||
value( "efiSystemPartition" ).toString() );
|
||||
gs->value( "efiSystemPartition" ).toString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue