2020-08-25 16:05:56 +02:00
|
|
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
2014-09-03 18:09:37 +02:00
|
|
|
*
|
2020-08-22 01:19:58 +02:00
|
|
|
* 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-License-Identifier: GPL-3.0-or-later
|
2014-09-03 18:09:37 +02:00
|
|
|
*
|
2020-08-25 16:05:56 +02:00
|
|
|
* Calamares is Free Software: see the License-Identifier above.
|
2014-09-03 18:09:37 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ChoicePage.h"
|
|
|
|
|
2020-07-30 10:44:10 +02:00
|
|
|
#include "BootInfoWidget.h"
|
|
|
|
#include "DeviceInfoWidget.h"
|
|
|
|
#include "PartitionBarsView.h"
|
|
|
|
#include "PartitionLabelsView.h"
|
|
|
|
#include "PartitionSplitterWidget.h"
|
|
|
|
#include "ReplaceWidget.h"
|
|
|
|
#include "ScanningDialog.h"
|
2015-11-06 17:57:05 +01:00
|
|
|
#include "core/BootLoaderModel.h"
|
2020-07-30 10:44:10 +02:00
|
|
|
#include "core/Config.h"
|
2014-09-19 16:27:39 +02:00
|
|
|
#include "core/DeviceModel.h"
|
2018-09-13 11:50:46 +02:00
|
|
|
#include "core/KPMHelpers.h"
|
2015-09-18 15:41:07 +02:00
|
|
|
#include "core/OsproberEntry.h"
|
2016-01-15 17:53:07 +01:00
|
|
|
#include "core/PartUtils.h"
|
2018-09-13 11:50:46 +02:00
|
|
|
#include "core/PartitionActions.h"
|
|
|
|
#include "core/PartitionCoreModule.h"
|
|
|
|
#include "core/PartitionInfo.h"
|
|
|
|
#include "core/PartitionModel.h"
|
2014-09-19 16:27:39 +02:00
|
|
|
|
2020-05-18 11:01:54 +02:00
|
|
|
#include "Branding.h"
|
2019-06-13 12:27:39 +02:00
|
|
|
#include "GlobalStorage.h"
|
|
|
|
#include "JobQueue.h"
|
|
|
|
#include "partition/PartitionIterator.h"
|
2019-06-13 14:41:33 +02:00
|
|
|
#include "partition/PartitionQuery.h"
|
2020-05-18 11:01:54 +02:00
|
|
|
#include "utils/CalamaresUtilsGui.h"
|
2014-09-19 16:27:39 +02:00
|
|
|
#include "utils/Logger.h"
|
2014-11-11 17:09:33 +01:00
|
|
|
#include "utils/Retranslator.h"
|
2018-09-17 12:42:14 +02:00
|
|
|
#include "utils/Units.h"
|
2020-05-18 11:01:54 +02:00
|
|
|
#include "widgets/PrettyRadioButton.h"
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2015-09-18 17:25:55 +02:00
|
|
|
#include <kpmcore/core/device.h>
|
2016-01-12 11:42:38 +01:00
|
|
|
#include <kpmcore/core/partition.h>
|
2019-04-12 11:21:18 +02:00
|
|
|
#ifdef WITH_KPMCORE4API
|
2018-08-13 17:26:00 +02:00
|
|
|
#include <kpmcore/core/softwareraid.h>
|
2018-09-21 22:19:05 +02:00
|
|
|
#endif
|
2015-09-18 17:25:55 +02:00
|
|
|
|
2014-09-03 18:09:37 +02:00
|
|
|
#include <QBoxLayout>
|
|
|
|
#include <QButtonGroup>
|
2015-10-06 18:56:33 +02:00
|
|
|
#include <QComboBox>
|
2015-05-28 19:24:39 +02:00
|
|
|
#include <QDir>
|
2020-08-22 01:19:58 +02:00
|
|
|
#include <QFutureWatcher>
|
2014-09-03 18:09:37 +02:00
|
|
|
#include <QLabel>
|
2015-09-18 17:25:55 +02:00
|
|
|
#include <QListView>
|
2015-12-24 17:02:50 +01:00
|
|
|
#include <QtConcurrent/QtConcurrent>
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2020-05-18 11:01:54 +02:00
|
|
|
using Calamares::PrettyRadioButton;
|
2020-08-22 01:19:58 +02:00
|
|
|
using CalamaresUtils::Partition::findPartitionByPath;
|
|
|
|
using CalamaresUtils::Partition::isPartitionFreeSpace;
|
|
|
|
using CalamaresUtils::Partition::PartitionIterator;
|
2020-10-02 12:08:42 +02:00
|
|
|
using InstallChoice = Config::InstallChoice;
|
2020-10-02 12:22:53 +02:00
|
|
|
using SwapChoice = Config::SwapChoice;
|
2015-10-06 18:56:33 +02:00
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
/**
|
|
|
|
* @brief ChoicePage::ChoicePage is the default constructor. Called on startup as part of
|
|
|
|
* the module loading code path.
|
|
|
|
* @param parent the QWidget parent.
|
|
|
|
*/
|
2020-07-30 10:44:10 +02:00
|
|
|
ChoicePage::ChoicePage( Config* config, QWidget* parent )
|
2014-09-03 18:09:37 +02:00
|
|
|
: QWidget( parent )
|
2020-07-30 10:44:10 +02:00
|
|
|
, m_config( config )
|
2014-09-03 18:09:37 +02:00
|
|
|
, m_nextEnabled( false )
|
2015-06-14 00:55:26 +02:00
|
|
|
, m_core( nullptr )
|
2016-07-15 11:36:44 +02:00
|
|
|
, m_isEfi( false )
|
2016-02-26 14:02:22 +01:00
|
|
|
, m_grp( nullptr )
|
2015-10-06 18:56:33 +02:00
|
|
|
, m_alongsideButton( nullptr )
|
|
|
|
, m_eraseButton( nullptr )
|
|
|
|
, m_replaceButton( nullptr )
|
|
|
|
, m_somethingElseButton( nullptr )
|
2019-02-12 11:38:53 +01:00
|
|
|
, m_eraseSwapChoiceComboBox( nullptr )
|
2015-11-27 17:25:47 +01:00
|
|
|
, m_deviceInfoWidget( nullptr )
|
2015-12-17 15:39:52 +01:00
|
|
|
, m_beforePartitionBarsView( nullptr )
|
|
|
|
, m_beforePartitionLabelsView( nullptr )
|
2016-01-29 17:07:08 +01:00
|
|
|
, m_bootloaderComboBox( nullptr )
|
2016-09-26 13:14:54 +02:00
|
|
|
, m_enableEncryptionWidget( true )
|
2014-09-03 18:09:37 +02:00
|
|
|
{
|
2015-09-30 17:24:37 +02:00
|
|
|
setupUi( this );
|
2015-10-22 18:37:09 +02:00
|
|
|
|
2019-01-21 13:36:50 +01:00
|
|
|
auto gs = Calamares::JobQueue::instance()->globalStorage();
|
|
|
|
|
2020-05-21 23:13:28 +02:00
|
|
|
m_requiredPartitionTableType = gs->value( "requiredPartitionTableType" ).toStringList();
|
2019-01-21 13:36:50 +01:00
|
|
|
m_enableEncryptionWidget = gs->value( "enableLuksAutomatedPartitioning" ).toBool();
|
2019-01-24 21:20:06 +01:00
|
|
|
|
2015-11-26 15:31:06 +01:00
|
|
|
// Set up drives combo
|
|
|
|
m_mainLayout->setDirection( QBoxLayout::TopToBottom );
|
|
|
|
m_drivesLayout->setDirection( QBoxLayout::LeftToRight );
|
2016-01-27 18:23:56 +01:00
|
|
|
|
|
|
|
BootInfoWidget* bootInfoWidget = new BootInfoWidget( this );
|
2016-01-27 18:27:03 +01:00
|
|
|
m_drivesLayout->insertWidget( 0, bootInfoWidget );
|
|
|
|
m_drivesLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() / 2 );
|
2016-01-27 18:23:56 +01:00
|
|
|
|
2015-11-26 15:31:06 +01:00
|
|
|
m_drivesCombo = new QComboBox( this );
|
|
|
|
m_mainLayout->setStretchFactor( m_drivesLayout, 0 );
|
|
|
|
m_mainLayout->setStretchFactor( m_rightLayout, 1 );
|
|
|
|
m_drivesLabel->setBuddy( m_drivesCombo );
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2015-11-26 15:31:06 +01:00
|
|
|
m_drivesLayout->addWidget( m_drivesCombo );
|
|
|
|
|
2015-11-27 17:25:47 +01:00
|
|
|
m_deviceInfoWidget = new DeviceInfoWidget;
|
|
|
|
m_drivesLayout->addWidget( m_deviceInfoWidget );
|
2016-01-28 13:04:44 +01:00
|
|
|
m_drivesLayout->addStretch();
|
2015-10-22 18:37:09 +02:00
|
|
|
|
2014-09-03 18:09:37 +02:00
|
|
|
m_messageLabel->setWordWrap( true );
|
2015-12-15 17:18:10 +01:00
|
|
|
m_messageLabel->hide();
|
2014-09-03 18:09:37 +02:00
|
|
|
|
|
|
|
CalamaresUtils::unmarginLayout( m_itemsLayout );
|
|
|
|
|
2015-09-30 17:24:37 +02:00
|
|
|
// Drive selector + preview
|
2020-08-22 01:19:58 +02:00
|
|
|
CALAMARES_RETRANSLATE( retranslateUi( this ); m_drivesLabel->setText( tr( "Select storage de&vice:" ) );
|
|
|
|
m_previewBeforeLabel->setText( tr( "Current:" ) );
|
2021-03-16 16:01:25 +01:00
|
|
|
m_previewAfterLabel->setText( tr( "After:" ) ); );
|
2015-09-18 17:25:55 +02:00
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
m_previewBeforeFrame->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding );
|
|
|
|
m_previewAfterFrame->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding );
|
2015-12-31 16:55:18 +01:00
|
|
|
m_previewAfterLabel->hide();
|
2015-10-29 17:34:59 +01:00
|
|
|
m_previewAfterFrame->hide();
|
2016-04-22 16:02:07 +02:00
|
|
|
m_encryptWidget->hide();
|
2016-07-15 11:25:47 +02:00
|
|
|
m_reuseHomeCheckBox->hide();
|
2019-01-21 13:36:50 +01:00
|
|
|
gs->insert( "reuseHome", false );
|
2014-09-03 18:09:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
ChoicePage::~ChoicePage() {}
|
2014-09-03 18:09:37 +02:00
|
|
|
|
|
|
|
|
2015-09-18 17:25:55 +02:00
|
|
|
void
|
2015-12-15 14:00:34 +01:00
|
|
|
ChoicePage::init( PartitionCoreModule* core )
|
2015-09-18 17:25:55 +02:00
|
|
|
{
|
2015-10-06 18:56:33 +02:00
|
|
|
m_core = core;
|
2017-08-28 11:36:21 +02:00
|
|
|
m_isEfi = PartUtils::isEfiSystem();
|
2015-09-18 17:25:55 +02:00
|
|
|
|
2015-10-06 18:56:33 +02:00
|
|
|
setupChoices();
|
2015-09-18 17:25:55 +02:00
|
|
|
|
2015-11-26 15:31:06 +01:00
|
|
|
|
|
|
|
// We need to do this because a PCM revert invalidates the deviceModel.
|
2020-10-12 14:27:01 +02:00
|
|
|
connect( core, &PartitionCoreModule::reverted, this, [=] {
|
2015-11-26 15:31:06 +01:00
|
|
|
m_drivesCombo->setModel( core->deviceModel() );
|
|
|
|
m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex );
|
|
|
|
} );
|
|
|
|
m_drivesCombo->setModel( core->deviceModel() );
|
|
|
|
|
|
|
|
connect( m_drivesCombo,
|
|
|
|
static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ),
|
2020-08-22 01:19:58 +02:00
|
|
|
this,
|
|
|
|
&ChoicePage::applyDeviceChoice );
|
2015-10-29 17:34:59 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
connect( m_encryptWidget, &EncryptWidget::stateChanged, this, &ChoicePage::onEncryptWidgetStateChanged );
|
|
|
|
connect( m_reuseHomeCheckBox, &QCheckBox::stateChanged, this, &ChoicePage::onHomeCheckBoxStateChanged );
|
2016-04-22 16:02:07 +02:00
|
|
|
|
2015-10-06 18:56:33 +02:00
|
|
|
ChoicePage::applyDeviceChoice();
|
2015-09-18 17:25:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-13 10:44:36 +02:00
|
|
|
/** @brief Creates a combobox with the given choices in it.
|
|
|
|
*
|
2019-02-12 13:30:34 +01:00
|
|
|
* Pre-selects the choice given by @p dflt.
|
2018-09-13 10:44:36 +02:00
|
|
|
* No texts are set -- that happens later by the translator functions.
|
|
|
|
*/
|
|
|
|
static inline QComboBox*
|
2019-02-12 13:30:34 +01:00
|
|
|
createCombo( const QSet< SwapChoice >& s, SwapChoice dflt )
|
2018-09-13 10:44:36 +02:00
|
|
|
{
|
|
|
|
QComboBox* box = new QComboBox;
|
2020-08-22 01:19:58 +02:00
|
|
|
for ( SwapChoice c : { SwapChoice::NoSwap,
|
|
|
|
SwapChoice::SmallSwap,
|
|
|
|
SwapChoice::FullSwap,
|
|
|
|
SwapChoice::ReuseSwap,
|
|
|
|
SwapChoice::SwapFile } )
|
2018-12-04 11:01:16 +01:00
|
|
|
if ( s.contains( c ) )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2018-12-04 11:01:16 +01:00
|
|
|
box->addItem( QString(), c );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2019-02-12 13:30:34 +01:00
|
|
|
|
|
|
|
int dfltIndex = box->findData( dflt );
|
|
|
|
if ( dfltIndex >= 0 )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2019-02-12 13:30:34 +01:00
|
|
|
box->setCurrentIndex( dfltIndex );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2019-02-12 13:30:34 +01:00
|
|
|
|
2018-09-13 10:44:36 +02:00
|
|
|
return box;
|
|
|
|
}
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
/**
|
|
|
|
* @brief ChoicePage::setupChoices creates PrettyRadioButton objects for the action
|
|
|
|
* choices.
|
|
|
|
* @warning This must only run ONCE because it creates signal-slot connections for the
|
|
|
|
* actions. When an action is triggered, it runs action-specific code that may
|
|
|
|
* change the internal state of the PCM, and it updates the bottom preview (or
|
|
|
|
* split) widget.
|
|
|
|
* Synchronous loading ends here.
|
|
|
|
*/
|
2014-09-03 18:09:37 +02:00
|
|
|
void
|
2015-10-06 18:56:33 +02:00
|
|
|
ChoicePage::setupChoices()
|
2014-09-03 18:09:37 +02:00
|
|
|
{
|
|
|
|
// sample os-prober output:
|
|
|
|
// /dev/sda2:Windows 7 (loader):Windows:chain
|
|
|
|
// /dev/sda6::Arch:linux
|
|
|
|
//
|
|
|
|
// There are three possibilities we have to consider:
|
|
|
|
// - There are no operating systems present
|
|
|
|
// - There is one operating system present
|
|
|
|
// - There are multiple operating systems present
|
|
|
|
//
|
|
|
|
// There are three outcomes we have to provide:
|
|
|
|
// 1) Wipe+autopartition
|
|
|
|
// 2) Resize+autopartition
|
|
|
|
// 3) Manual
|
|
|
|
// TBD: upgrade option?
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
QSize iconSize( CalamaresUtils::defaultIconSize().width() * 2, CalamaresUtils::defaultIconSize().height() * 2 );
|
2016-01-08 16:35:50 +01:00
|
|
|
m_grp = new QButtonGroup( this );
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2015-10-06 18:56:33 +02:00
|
|
|
m_alongsideButton = new PrettyRadioButton;
|
|
|
|
m_alongsideButton->setIconSize( iconSize );
|
2020-08-22 01:19:58 +02:00
|
|
|
m_alongsideButton->setIcon(
|
|
|
|
CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionAlongside, CalamaresUtils::Original, iconSize ) );
|
2020-07-30 11:51:26 +02:00
|
|
|
m_alongsideButton->addToGroup( m_grp, InstallChoice::Alongside );
|
2015-10-06 18:56:33 +02:00
|
|
|
|
2016-01-28 18:43:35 +01:00
|
|
|
m_eraseButton = new PrettyRadioButton;
|
2015-10-06 18:56:33 +02:00
|
|
|
m_eraseButton->setIconSize( iconSize );
|
2020-08-22 01:19:58 +02:00
|
|
|
m_eraseButton->setIcon(
|
|
|
|
CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionEraseAuto, CalamaresUtils::Original, iconSize ) );
|
2020-07-30 11:51:26 +02:00
|
|
|
m_eraseButton->addToGroup( m_grp, InstallChoice::Erase );
|
2014-12-16 17:04:09 +01:00
|
|
|
|
2015-12-22 13:15:13 +01:00
|
|
|
m_replaceButton = new PrettyRadioButton;
|
2015-11-20 14:49:37 +01:00
|
|
|
|
2015-10-06 18:56:33 +02:00
|
|
|
m_replaceButton->setIconSize( iconSize );
|
2020-08-22 01:19:58 +02:00
|
|
|
m_replaceButton->setIcon(
|
|
|
|
CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionReplaceOs, CalamaresUtils::Original, iconSize ) );
|
2020-07-30 11:51:26 +02:00
|
|
|
m_replaceButton->addToGroup( m_grp, InstallChoice::Replace );
|
2015-10-06 18:56:33 +02:00
|
|
|
|
2018-09-12 17:18:17 +02:00
|
|
|
// Fill up swap options
|
2020-10-06 15:44:14 +02:00
|
|
|
if ( m_config->swapChoices().count() > 1 )
|
2018-12-11 13:52:23 +01:00
|
|
|
{
|
2020-10-06 15:44:14 +02:00
|
|
|
m_eraseSwapChoiceComboBox = createCombo( m_config->swapChoices(), m_config->swapChoice() );
|
2019-02-12 11:38:53 +01:00
|
|
|
m_eraseButton->addOptionsComboBox( m_eraseSwapChoiceComboBox );
|
2018-12-11 13:52:23 +01:00
|
|
|
}
|
2018-09-13 10:44:36 +02:00
|
|
|
|
2015-10-06 18:56:33 +02:00
|
|
|
m_itemsLayout->addWidget( m_alongsideButton );
|
|
|
|
m_itemsLayout->addWidget( m_replaceButton );
|
|
|
|
m_itemsLayout->addWidget( m_eraseButton );
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2015-10-06 18:56:33 +02:00
|
|
|
m_somethingElseButton = new PrettyRadioButton;
|
|
|
|
m_somethingElseButton->setIconSize( iconSize );
|
2020-08-22 01:19:58 +02:00
|
|
|
m_somethingElseButton->setIcon(
|
|
|
|
CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionManual, CalamaresUtils::Original, iconSize ) );
|
2015-10-06 18:56:33 +02:00
|
|
|
m_itemsLayout->addWidget( m_somethingElseButton );
|
2020-07-30 11:51:26 +02:00
|
|
|
m_somethingElseButton->addToGroup( m_grp, InstallChoice::Manual );
|
2015-10-06 18:56:33 +02:00
|
|
|
|
|
|
|
m_itemsLayout->addStretch();
|
|
|
|
|
2020-09-23 11:16:23 +02:00
|
|
|
#if ( QT_VERSION < QT_VERSION_CHECK( 5, 15, 0 ) )
|
|
|
|
auto buttonSignal = QOverload< int, bool >::of( &QButtonGroup::buttonToggled );
|
|
|
|
#else
|
|
|
|
auto buttonSignal = &QButtonGroup::idToggled;
|
|
|
|
#endif
|
2020-10-12 14:27:01 +02:00
|
|
|
connect( m_grp, buttonSignal, this, [this]( int id, bool checked ) {
|
2016-01-08 15:38:01 +01:00
|
|
|
if ( checked ) // An action was picked.
|
2015-10-29 17:34:59 +01:00
|
|
|
{
|
2020-09-29 14:00:49 +02:00
|
|
|
m_config->setInstallChoice( id );
|
2016-04-22 16:02:07 +02:00
|
|
|
updateNextEnabled();
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
emit actionChosen();
|
|
|
|
}
|
2020-08-22 01:19:58 +02:00
|
|
|
else // An action was unpicked, either on its own or because of another selection.
|
2015-10-29 17:34:59 +01:00
|
|
|
{
|
2016-01-08 16:35:50 +01:00
|
|
|
if ( m_grp->checkedButton() == nullptr ) // If no other action is chosen, we must
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
|
|
|
// set m_choice to NoChoice and reset previews.
|
2020-09-29 14:00:49 +02:00
|
|
|
m_config->setInstallChoice( InstallChoice::NoChoice );
|
2016-04-22 16:02:07 +02:00
|
|
|
updateNextEnabled();
|
|
|
|
|
2016-01-08 15:38:01 +01:00
|
|
|
emit actionChosen();
|
|
|
|
}
|
2015-10-29 17:34:59 +01:00
|
|
|
}
|
2015-10-06 18:56:33 +02:00
|
|
|
} );
|
|
|
|
|
|
|
|
m_rightLayout->setStretchFactor( m_itemsLayout, 1 );
|
2015-10-29 17:34:59 +01:00
|
|
|
m_rightLayout->setStretchFactor( m_previewBeforeFrame, 0 );
|
|
|
|
m_rightLayout->setStretchFactor( m_previewAfterFrame, 0 );
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
connect( this, &ChoicePage::actionChosen, this, &ChoicePage::onActionChanged );
|
2019-02-12 11:38:53 +01:00
|
|
|
if ( m_eraseSwapChoiceComboBox )
|
2020-08-22 01:19:58 +02:00
|
|
|
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." ) );
|
2021-03-16 16:01:25 +01:00
|
|
|
updateSwapChoicesTr( m_eraseSwapChoiceComboBox ); );
|
2015-10-06 18:56:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
/**
|
|
|
|
* @brief ChoicePage::selectedDevice queries the device picker (which may be a combo or
|
|
|
|
* a list view) to get a pointer to the currently selected Device.
|
|
|
|
* @return a Device pointer, valid in the current state of the PCM, or nullptr if
|
|
|
|
* something goes wrong.
|
|
|
|
*/
|
|
|
|
Device*
|
|
|
|
ChoicePage::selectedDevice()
|
2015-10-06 18:56:33 +02:00
|
|
|
{
|
2015-10-23 17:45:28 +02:00
|
|
|
Device* currentDevice = nullptr;
|
2020-08-22 01:19:58 +02:00
|
|
|
currentDevice
|
|
|
|
= m_core->deviceModel()->deviceForIndex( m_core->deviceModel()->index( m_drivesCombo->currentIndex() ) );
|
2015-10-06 18:56:33 +02:00
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
return currentDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-09 11:09:24 +01:00
|
|
|
void
|
|
|
|
ChoicePage::hideButtons()
|
|
|
|
{
|
|
|
|
m_eraseButton->hide();
|
|
|
|
m_replaceButton->hide();
|
|
|
|
m_alongsideButton->hide();
|
|
|
|
m_somethingElseButton->hide();
|
|
|
|
}
|
|
|
|
|
2020-09-28 17:46:42 +02:00
|
|
|
void
|
|
|
|
ChoicePage::checkInstallChoiceRadioButton( InstallChoice c )
|
|
|
|
{
|
|
|
|
QSignalBlocker b( m_grp );
|
|
|
|
m_grp->setExclusive( false );
|
2020-09-29 12:22:50 +02:00
|
|
|
// If c == InstallChoice::NoChoice none will match and all are deselected
|
2020-09-29 14:00:49 +02:00
|
|
|
m_eraseButton->setChecked( InstallChoice::Erase == c );
|
2020-09-29 12:22:50 +02:00
|
|
|
m_replaceButton->setChecked( InstallChoice::Replace == c );
|
|
|
|
m_alongsideButton->setChecked( InstallChoice::Alongside == c );
|
|
|
|
m_somethingElseButton->setChecked( InstallChoice::Manual == c );
|
2020-09-28 17:46:42 +02:00
|
|
|
m_grp->setExclusive( true );
|
|
|
|
}
|
|
|
|
|
2018-01-09 11:09:24 +01:00
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
/**
|
|
|
|
* @brief ChoicePage::applyDeviceChoice handler for the selected event of the device
|
|
|
|
* picker. Calls ChoicePage::selectedDevice() to get the current Device*, then
|
|
|
|
* updates the preview widget for the on-disk state (calls ChoicePage::
|
|
|
|
* updateDeviceStatePreview()) and finally sets up the available actions and their
|
|
|
|
* text by calling ChoicePage::setupActions().
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ChoicePage::applyDeviceChoice()
|
|
|
|
{
|
2015-12-17 18:02:14 +01:00
|
|
|
if ( !selectedDevice() )
|
2018-01-09 11:09:24 +01:00
|
|
|
{
|
|
|
|
hideButtons();
|
2015-12-17 18:02:14 +01:00
|
|
|
return;
|
2018-01-09 11:09:24 +01:00
|
|
|
}
|
2015-10-29 17:34:59 +01:00
|
|
|
|
2015-11-05 15:57:15 +01:00
|
|
|
if ( m_core->isDirty() )
|
2015-12-17 18:02:14 +01:00
|
|
|
{
|
2021-03-16 16:08:13 +01:00
|
|
|
ScanningDialog::run(
|
|
|
|
QtConcurrent::run( [=] {
|
|
|
|
QMutexLocker locker( &m_coreMutex );
|
|
|
|
m_core->revertAllDevices();
|
|
|
|
} ),
|
|
|
|
[this] { continueApplyDeviceChoice(); },
|
|
|
|
this );
|
2015-12-17 18:02:14 +01:00
|
|
|
}
|
2016-02-09 13:23:23 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
continueApplyDeviceChoice();
|
|
|
|
}
|
|
|
|
}
|
2015-12-17 18:02:14 +01:00
|
|
|
|
|
|
|
|
2016-02-09 13:23:23 +01:00
|
|
|
void
|
|
|
|
ChoicePage::continueApplyDeviceChoice()
|
|
|
|
{
|
|
|
|
Device* currd = selectedDevice();
|
2015-11-05 15:57:15 +01:00
|
|
|
|
2015-10-30 17:32:00 +01:00
|
|
|
// The device should only be nullptr immediately after a PCM reset.
|
|
|
|
// applyDeviceChoice() will be called again momentarily as soon as we handle the
|
|
|
|
// PartitionCoreModule::reverted signal.
|
|
|
|
if ( !currd )
|
2018-01-09 11:09:24 +01:00
|
|
|
{
|
|
|
|
hideButtons();
|
2015-10-30 17:32:00 +01:00
|
|
|
return;
|
2018-01-09 11:09:24 +01:00
|
|
|
}
|
2015-10-30 17:32:00 +01:00
|
|
|
|
2015-12-17 18:02:14 +01:00
|
|
|
updateDeviceStatePreview();
|
2015-10-23 17:45:28 +02:00
|
|
|
|
2018-01-09 11:09:24 +01:00
|
|
|
// Preview setup done. Now we show/hide choices as needed.
|
2015-12-17 18:02:14 +01:00
|
|
|
setupActions();
|
2015-10-30 17:32:00 +01:00
|
|
|
|
2020-09-28 17:46:42 +02:00
|
|
|
cDebug() << "Previous device" << m_lastSelectedDeviceIndex << "new device" << m_drivesCombo->currentIndex();
|
|
|
|
if ( m_lastSelectedDeviceIndex != m_drivesCombo->currentIndex() )
|
|
|
|
{
|
|
|
|
m_lastSelectedDeviceIndex = m_drivesCombo->currentIndex();
|
|
|
|
m_lastSelectedActionIndex = -1;
|
2020-09-29 14:00:49 +02:00
|
|
|
m_config->setInstallChoice( m_config->initialInstallChoice() );
|
|
|
|
checkInstallChoiceRadioButton( m_config->installChoice() );
|
2020-09-28 17:46:42 +02:00
|
|
|
}
|
2015-11-05 15:57:15 +01:00
|
|
|
|
|
|
|
emit actionChosen();
|
2015-12-17 18:02:14 +01:00
|
|
|
emit deviceChosen();
|
2015-11-05 15:57:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-04 10:22:08 +01:00
|
|
|
void
|
|
|
|
ChoicePage::onActionChanged()
|
|
|
|
{
|
|
|
|
Device* currd = selectedDevice();
|
|
|
|
if ( currd )
|
|
|
|
{
|
2020-09-29 14:00:49 +02:00
|
|
|
applyActionChoice( m_config->installChoice() );
|
2018-12-04 10:22:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 13:21:35 +01:00
|
|
|
void
|
|
|
|
ChoicePage::onEraseSwapChoiceChanged()
|
|
|
|
{
|
|
|
|
if ( m_eraseSwapChoiceComboBox )
|
|
|
|
{
|
2020-10-06 15:44:14 +02:00
|
|
|
m_config->setSwapChoice( m_eraseSwapChoiceComboBox->currentData().toInt() );
|
2019-02-12 13:21:35 +01:00
|
|
|
onActionChanged();
|
|
|
|
}
|
|
|
|
}
|
2018-12-04 10:22:08 +01:00
|
|
|
|
2015-11-05 15:57:15 +01:00
|
|
|
void
|
2020-10-02 12:08:42 +02:00
|
|
|
ChoicePage::applyActionChoice( InstallChoice choice )
|
2015-11-05 15:57:15 +01:00
|
|
|
{
|
2020-09-28 17:46:42 +02:00
|
|
|
cDebug() << "Prev" << m_lastSelectedActionIndex << "InstallChoice" << choice
|
2020-10-02 12:08:42 +02:00
|
|
|
<< Config::installChoiceNames().find( choice );
|
2020-08-22 01:19:58 +02:00
|
|
|
m_beforePartitionBarsView->selectionModel()->disconnect( SIGNAL( currentRowChanged( QModelIndex, QModelIndex ) ) );
|
2015-12-31 16:58:50 +01:00
|
|
|
m_beforePartitionBarsView->selectionModel()->clearSelection();
|
|
|
|
m_beforePartitionBarsView->selectionModel()->clearCurrentIndex();
|
|
|
|
|
2015-11-05 15:57:15 +01:00
|
|
|
switch ( choice )
|
|
|
|
{
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Erase:
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
|
|
|
auto gs = Calamares::JobQueue::instance()->globalStorage();
|
2018-09-17 12:42:14 +02:00
|
|
|
|
2020-05-20 17:22:37 +02:00
|
|
|
PartitionActions::Choices::AutoPartitionOptions options { gs->value( "defaultPartitionTableType" ).toString(),
|
|
|
|
gs->value( "defaultFileSystemType" ).toString(),
|
2020-08-22 01:19:58 +02:00
|
|
|
m_encryptWidget->passphrase(),
|
|
|
|
gs->value( "efiSystemPartition" ).toString(),
|
|
|
|
CalamaresUtils::GiBtoBytes(
|
|
|
|
gs->value( "requiredStorageGiB" ).toDouble() ),
|
2020-10-06 15:44:14 +02:00
|
|
|
m_config->swapChoice() };
|
2020-08-22 01:19:58 +02:00
|
|
|
|
|
|
|
if ( m_core->isDirty() )
|
|
|
|
{
|
2021-03-16 16:08:13 +01:00
|
|
|
ScanningDialog::run(
|
|
|
|
QtConcurrent::run( [=] {
|
|
|
|
QMutexLocker locker( &m_coreMutex );
|
|
|
|
m_core->revertDevice( selectedDevice() );
|
|
|
|
} ),
|
|
|
|
[=] {
|
|
|
|
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
|
|
|
emit deviceChosen();
|
|
|
|
},
|
|
|
|
this );
|
2016-01-07 17:23:29 +01:00
|
|
|
}
|
2020-08-22 01:19:58 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
|
|
|
emit deviceChosen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Replace:
|
2015-12-17 18:02:14 +01:00
|
|
|
if ( m_core->isDirty() )
|
|
|
|
{
|
2021-03-16 16:08:13 +01:00
|
|
|
ScanningDialog::run(
|
|
|
|
QtConcurrent::run( [=] {
|
|
|
|
QMutexLocker locker( &m_coreMutex );
|
|
|
|
m_core->revertDevice( selectedDevice() );
|
|
|
|
} ),
|
|
|
|
[] {},
|
|
|
|
this );
|
2015-12-17 18:02:14 +01:00
|
|
|
}
|
2016-04-22 16:02:07 +02:00
|
|
|
updateNextEnabled();
|
2015-12-17 18:02:14 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
connect( m_beforePartitionBarsView->selectionModel(),
|
|
|
|
SIGNAL( currentRowChanged( QModelIndex, QModelIndex ) ),
|
|
|
|
this,
|
|
|
|
SLOT( onPartitionToReplaceSelected( QModelIndex, QModelIndex ) ),
|
2015-12-31 14:38:28 +01:00
|
|
|
Qt::UniqueConnection );
|
2015-12-18 15:03:31 +01:00
|
|
|
break;
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Alongside:
|
2016-01-11 19:02:34 +01:00
|
|
|
if ( m_core->isDirty() )
|
|
|
|
{
|
2021-03-16 16:08:13 +01:00
|
|
|
ScanningDialog::run(
|
|
|
|
QtConcurrent::run( [=] {
|
|
|
|
QMutexLocker locker( &m_coreMutex );
|
|
|
|
m_core->revertDevice( selectedDevice() );
|
|
|
|
} ),
|
|
|
|
[this] {
|
|
|
|
// We need to reupdate after reverting because the splitter widget is
|
|
|
|
// not a true view.
|
|
|
|
updateActionChoicePreview( m_config->installChoice() );
|
|
|
|
updateNextEnabled();
|
|
|
|
},
|
|
|
|
this );
|
2016-01-11 19:02:34 +01:00
|
|
|
}
|
2016-04-22 16:02:07 +02:00
|
|
|
updateNextEnabled();
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
connect( m_beforePartitionBarsView->selectionModel(),
|
|
|
|
SIGNAL( currentRowChanged( QModelIndex, QModelIndex ) ),
|
|
|
|
this,
|
|
|
|
SLOT( doAlongsideSetupSplitter( QModelIndex, QModelIndex ) ),
|
2016-01-11 19:02:34 +01:00
|
|
|
Qt::UniqueConnection );
|
|
|
|
break;
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::NoChoice:
|
|
|
|
case InstallChoice::Manual:
|
2015-11-05 15:57:15 +01:00
|
|
|
break;
|
|
|
|
}
|
2019-01-21 14:54:09 +01:00
|
|
|
updateActionChoicePreview( choice );
|
2015-10-23 17:45:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-11 19:02:34 +01:00
|
|
|
void
|
2020-08-22 01:19:58 +02:00
|
|
|
ChoicePage::doAlongsideSetupSplitter( const QModelIndex& current, const QModelIndex& previous )
|
2016-01-11 19:02:34 +01:00
|
|
|
{
|
2019-04-17 11:57:46 +02:00
|
|
|
Q_UNUSED( previous )
|
2016-01-11 19:02:34 +01:00
|
|
|
if ( !current.isValid() )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-01-11 19:02:34 +01:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2016-01-12 11:42:38 +01:00
|
|
|
if ( !m_afterPartitionSplitterWidget )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-01-12 11:42:38 +01:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-01-12 11:42:38 +01:00
|
|
|
|
|
|
|
const PartitionModel* modl = qobject_cast< const PartitionModel* >( current.model() );
|
|
|
|
if ( !modl )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-01-12 11:42:38 +01:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-01-12 11:42:38 +01:00
|
|
|
|
|
|
|
Partition* part = modl->partitionForIndex( current );
|
2016-02-26 13:00:08 +01:00
|
|
|
if ( !part )
|
|
|
|
{
|
2020-05-19 15:05:05 +02:00
|
|
|
cDebug() << "Partition not found for index" << current;
|
2016-02-26 13:00:08 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-01-12 11:42:38 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
double requiredStorageGB
|
|
|
|
= Calamares::JobQueue::instance()->globalStorage()->value( "requiredStorageGiB" ).toDouble();
|
2016-01-12 11:42:38 +01:00
|
|
|
|
2019-05-06 16:47:11 +02:00
|
|
|
qint64 requiredStorageB = CalamaresUtils::GiBtoBytes( requiredStorageGB + 0.1 + 2.0 );
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
m_afterPartitionSplitterWidget->setSplitPartition( part->partitionPath(),
|
|
|
|
qRound64( part->used() * 1.1 ),
|
|
|
|
part->capacity() - requiredStorageB,
|
|
|
|
part->capacity() / 2 );
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2016-02-19 16:57:49 +01:00
|
|
|
if ( m_isEfi )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-02-19 16:57:49 +01:00
|
|
|
setupEfiSystemPartitionSelector();
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-02-19 16:51:24 +01:00
|
|
|
|
2016-01-11 19:02:34 +01:00
|
|
|
cDebug() << "Partition selected for Alongside.";
|
2016-05-17 08:46:56 +02:00
|
|
|
|
|
|
|
updateNextEnabled();
|
2016-01-13 17:43:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-05 12:26:28 +02:00
|
|
|
void
|
|
|
|
ChoicePage::onEncryptWidgetStateChanged()
|
|
|
|
{
|
2020-03-10 03:20:03 +01:00
|
|
|
EncryptWidget::Encryption state = m_encryptWidget->state();
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_config->installChoice() == InstallChoice::Erase )
|
2016-05-05 12:26:28 +02:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( state == EncryptWidget::Encryption::Confirmed || state == EncryptWidget::Encryption::Disabled )
|
|
|
|
{
|
2020-09-29 14:00:49 +02:00
|
|
|
applyActionChoice( m_config->installChoice() );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-05-05 12:26:28 +02:00
|
|
|
}
|
2020-09-29 14:00:49 +02:00
|
|
|
else if ( m_config->installChoice() == InstallChoice::Replace )
|
2016-05-27 16:29:03 +02:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( m_beforePartitionBarsView && m_beforePartitionBarsView->selectionModel()->currentIndex().isValid()
|
|
|
|
&& ( state == EncryptWidget::Encryption::Confirmed || state == EncryptWidget::Encryption::Disabled ) )
|
2016-05-27 16:29:03 +02:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
doReplaceSelectedPartition( m_beforePartitionBarsView->selectionModel()->currentIndex() );
|
2016-05-27 16:29:03 +02:00
|
|
|
}
|
|
|
|
}
|
2016-05-05 12:26:28 +02:00
|
|
|
updateNextEnabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-15 11:25:47 +02:00
|
|
|
void
|
|
|
|
ChoicePage::onHomeCheckBoxStateChanged()
|
|
|
|
{
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_config->installChoice() == InstallChoice::Replace
|
2020-08-22 01:19:58 +02:00
|
|
|
&& m_beforePartitionBarsView->selectionModel()->currentIndex().isValid() )
|
2016-07-15 11:25:47 +02:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
doReplaceSelectedPartition( m_beforePartitionBarsView->selectionModel()->currentIndex() );
|
2016-07-15 11:25:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-19 16:33:19 +01:00
|
|
|
void
|
|
|
|
ChoicePage::onLeave()
|
|
|
|
{
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_config->installChoice() == InstallChoice::Alongside )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-02-19 16:33:19 +01:00
|
|
|
doAlongsideApply();
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-02-19 16:33:19 +01:00
|
|
|
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_isEfi
|
|
|
|
&& ( m_config->installChoice() == InstallChoice::Alongside
|
|
|
|
|| m_config->installChoice() == InstallChoice::Replace ) )
|
2016-02-19 16:33:19 +01:00
|
|
|
{
|
|
|
|
QList< Partition* > efiSystemPartitions = m_core->efiSystemPartitions();
|
|
|
|
if ( efiSystemPartitions.count() == 1 )
|
|
|
|
{
|
|
|
|
PartitionInfo::setMountPoint(
|
2020-08-22 01:19:58 +02:00
|
|
|
efiSystemPartitions.first(),
|
|
|
|
Calamares::JobQueue::instance()->globalStorage()->value( "efiSystemPartition" ).toString() );
|
2016-02-19 16:33:19 +01:00
|
|
|
}
|
|
|
|
else if ( efiSystemPartitions.count() > 1 && m_efiComboBox )
|
|
|
|
{
|
|
|
|
PartitionInfo::setMountPoint(
|
2020-08-22 01:19:58 +02:00
|
|
|
efiSystemPartitions.at( m_efiComboBox->currentIndex() ),
|
|
|
|
Calamares::JobQueue::instance()->globalStorage()->value( "efiSystemPartition" ).toString() );
|
2016-02-19 16:33:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
cError() << "cannot set up EFI system partition.\nESP count:" << efiSystemPartitions.count()
|
|
|
|
<< "\nm_efiComboBox:" << m_efiComboBox;
|
2016-02-19 16:33:19 +01:00
|
|
|
}
|
|
|
|
}
|
2020-08-22 01:19:58 +02:00
|
|
|
else // installPath is then passed to the bootloader module for MBR setup
|
2016-02-19 16:33:19 +01:00
|
|
|
{
|
2017-01-18 19:38:12 +01:00
|
|
|
if ( !m_isEfi )
|
|
|
|
{
|
|
|
|
if ( m_bootloaderComboBox.isNull() )
|
|
|
|
{
|
2018-01-09 11:09:24 +01:00
|
|
|
auto d_p = selectedDevice();
|
|
|
|
if ( d_p )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2018-01-09 11:09:24 +01:00
|
|
|
m_core->setBootLoaderInstallPath( d_p->deviceNode() );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2018-01-09 11:09:24 +01:00
|
|
|
else
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2018-02-13 11:07:12 +01:00
|
|
|
cWarning() << "No device selected for bootloader.";
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2017-01-18 19:38:12 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QVariant var = m_bootloaderComboBox->currentData( BootLoaderModel::BootLoaderPathRole );
|
|
|
|
if ( !var.isValid() )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2017-01-18 19:38:12 +01:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2017-01-18 19:38:12 +01:00
|
|
|
m_core->setBootLoaderInstallPath( var.toString() );
|
|
|
|
}
|
|
|
|
}
|
2016-02-19 16:33:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-13 17:43:59 +01:00
|
|
|
void
|
|
|
|
ChoicePage::doAlongsideApply()
|
|
|
|
{
|
|
|
|
Q_ASSERT( m_afterPartitionSplitterWidget->splitPartitionSize() >= 0 );
|
2020-08-22 01:19:58 +02:00
|
|
|
Q_ASSERT( m_afterPartitionSplitterWidget->newPartitionSize() >= 0 );
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2016-06-29 18:21:38 +02:00
|
|
|
QMutexLocker locker( &m_coreMutex );
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
QString path = m_beforePartitionBarsView->selectionModel()
|
|
|
|
->currentIndex()
|
|
|
|
.data( PartitionModel::PartitionPathRole )
|
|
|
|
.toString();
|
2016-01-13 17:43:59 +01:00
|
|
|
|
|
|
|
DeviceModel* dm = m_core->deviceModel();
|
|
|
|
for ( int i = 0; i < dm->rowCount(); ++i )
|
|
|
|
{
|
|
|
|
Device* dev = dm->deviceForIndex( dm->index( i ) );
|
2019-06-13 14:41:33 +02:00
|
|
|
Partition* candidate = findPartitionByPath( { dev }, path );
|
2016-01-13 17:43:59 +01:00
|
|
|
if ( candidate )
|
|
|
|
{
|
|
|
|
qint64 firstSector = candidate->firstSector();
|
|
|
|
qint64 oldLastSector = candidate->lastSector();
|
2020-08-22 01:19:58 +02:00
|
|
|
qint64 newLastSector
|
|
|
|
= firstSector + m_afterPartitionSplitterWidget->splitPartitionSize() / dev->logicalSize();
|
2016-01-13 17:43:59 +01:00
|
|
|
|
|
|
|
m_core->resizePartition( dev, candidate, firstSector, newLastSector );
|
2020-08-22 01:19:58 +02:00
|
|
|
m_core->layoutApply( dev,
|
|
|
|
newLastSector + 2,
|
|
|
|
oldLastSector,
|
|
|
|
m_encryptWidget->passphrase(),
|
|
|
|
candidate->parent(),
|
|
|
|
candidate->roles() );
|
2016-01-13 17:43:59 +01:00
|
|
|
m_core->dumpQueue();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-01-11 19:02:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-24 17:24:26 +01:00
|
|
|
void
|
2020-08-22 01:19:58 +02:00
|
|
|
ChoicePage::onPartitionToReplaceSelected( const QModelIndex& current, const QModelIndex& previous )
|
2015-12-24 17:24:26 +01:00
|
|
|
{
|
2019-04-17 11:57:46 +02:00
|
|
|
Q_UNUSED( previous )
|
2015-12-31 14:50:43 +01:00
|
|
|
if ( !current.isValid() )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2015-12-31 14:50:43 +01:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2015-12-31 14:50:43 +01:00
|
|
|
|
2016-07-15 11:25:47 +02:00
|
|
|
// Reset state on selection regardless of whether this will be used.
|
|
|
|
m_reuseHomeCheckBox->setChecked( false );
|
|
|
|
|
|
|
|
doReplaceSelectedPartition( current );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ChoicePage::doReplaceSelectedPartition( const QModelIndex& current )
|
|
|
|
{
|
|
|
|
if ( !current.isValid() )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-07-15 11:25:47 +02:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-07-15 11:25:47 +02:00
|
|
|
|
2020-10-31 23:37:06 +01:00
|
|
|
// This will be deleted by the second lambda, below.
|
2016-07-22 09:55:55 +02:00
|
|
|
QString* homePartitionPath = new QString();
|
2016-07-15 11:25:47 +02:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
ScanningDialog::run(
|
|
|
|
QtConcurrent::run(
|
2020-10-31 23:37:06 +01:00
|
|
|
[this, current, homePartitionPath]( bool doReuseHomePartition ) {
|
2020-08-22 01:19:58 +02:00
|
|
|
QMutexLocker locker( &m_coreMutex );
|
2016-03-18 11:09:50 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( m_core->isDirty() )
|
2016-03-18 11:09:50 +01:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
m_core->revertDevice( selectedDevice() );
|
2016-03-18 11:09:50 +01:00
|
|
|
}
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
// if the partition is unallocated(free space), we don't replace it but create new one
|
|
|
|
// with the same first and last sector
|
|
|
|
Partition* selectedPartition
|
|
|
|
= static_cast< Partition* >( current.data( PartitionModel::PartitionPtrRole ).value< void* >() );
|
|
|
|
if ( isPartitionFreeSpace( selectedPartition ) )
|
|
|
|
{
|
|
|
|
//NOTE: if the selected partition is free space, we don't deal with
|
|
|
|
// a separate /home partition at all because there's no existing
|
|
|
|
// rootfs to read it from.
|
|
|
|
PartitionRole newRoles = PartitionRole( PartitionRole::Primary );
|
|
|
|
PartitionNode* newParent = selectedDevice()->partitionTable();
|
|
|
|
|
|
|
|
if ( selectedPartition->parent() )
|
2018-09-17 12:42:14 +02:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
Partition* parent = dynamic_cast< Partition* >( selectedPartition->parent() );
|
|
|
|
if ( parent && parent->roles().has( PartitionRole::Extended ) )
|
|
|
|
{
|
|
|
|
newRoles = PartitionRole( PartitionRole::Logical );
|
|
|
|
newParent = findPartitionByPath( { selectedDevice() }, parent->partitionPath() );
|
|
|
|
}
|
|
|
|
}
|
2016-07-15 13:09:07 +02:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
m_core->layoutApply( selectedDevice(),
|
|
|
|
selectedPartition->firstSector(),
|
|
|
|
selectedPartition->lastSector(),
|
|
|
|
m_encryptWidget->passphrase(),
|
|
|
|
newParent,
|
|
|
|
newRoles );
|
2016-07-15 13:09:07 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
// We can't use the PartitionPtrRole because we need to make changes to the
|
|
|
|
// main DeviceModel, not the immutable copy.
|
|
|
|
QString partPath = current.data( PartitionModel::PartitionPathRole ).toString();
|
|
|
|
selectedPartition = findPartitionByPath( { selectedDevice() }, partPath );
|
|
|
|
if ( selectedPartition )
|
|
|
|
{
|
|
|
|
// Find out is the selected partition has a rootfs. If yes, then make the
|
|
|
|
// m_reuseHomeCheckBox visible and set its text to something meaningful.
|
|
|
|
homePartitionPath->clear();
|
|
|
|
for ( const OsproberEntry& osproberEntry : m_core->osproberEntries() )
|
|
|
|
if ( osproberEntry.path == partPath )
|
|
|
|
{
|
|
|
|
*homePartitionPath = osproberEntry.homePath;
|
|
|
|
}
|
|
|
|
if ( homePartitionPath->isEmpty() )
|
|
|
|
{
|
|
|
|
doReuseHomePartition = false;
|
|
|
|
}
|
2016-07-15 11:25:47 +02:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
2016-02-19 16:51:24 +01:00
|
|
|
|
2020-10-12 14:27:01 +02:00
|
|
|
PartitionActions::doReplacePartition( m_core,
|
|
|
|
selectedDevice(),
|
|
|
|
selectedPartition,
|
|
|
|
{ gs->value( "defaultPartitionType" ).toString(),
|
|
|
|
gs->value( "defaultFileSystemType" ).toString(),
|
|
|
|
m_encryptWidget->passphrase() } );
|
2020-08-22 01:19:58 +02:00
|
|
|
Partition* homePartition = findPartitionByPath( { selectedDevice() }, *homePartitionPath );
|
|
|
|
|
|
|
|
if ( homePartition && doReuseHomePartition )
|
|
|
|
{
|
|
|
|
PartitionInfo::setMountPoint( homePartition, "/home" );
|
|
|
|
gs->insert( "reuseHome", true );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gs->insert( "reuseHome", false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-10-31 23:37:06 +01:00
|
|
|
m_reuseHomeCheckBox->isChecked() ),
|
|
|
|
[this, homePartitionPath] {
|
2020-08-22 01:19:58 +02:00
|
|
|
m_reuseHomeCheckBox->setVisible( !homePartitionPath->isEmpty() );
|
|
|
|
if ( !homePartitionPath->isEmpty() )
|
|
|
|
m_reuseHomeCheckBox->setText( tr( "Reuse %1 as home partition for %2." )
|
|
|
|
.arg( *homePartitionPath )
|
|
|
|
.arg( Calamares::Branding::instance()->shortProductName() ) );
|
|
|
|
delete homePartitionPath;
|
|
|
|
|
|
|
|
if ( m_isEfi )
|
|
|
|
setupEfiSystemPartitionSelector();
|
|
|
|
|
|
|
|
updateNextEnabled();
|
|
|
|
if ( !m_bootloaderComboBox.isNull() && m_bootloaderComboBox->currentIndex() < 0 )
|
|
|
|
m_bootloaderComboBox->setCurrentIndex( m_lastSelectedDeviceIndex );
|
|
|
|
},
|
|
|
|
this );
|
2015-12-24 17:24:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
/**
|
2020-10-23 23:14:00 +02:00
|
|
|
* @brief clear and then rebuild the contents of the preview widget
|
|
|
|
*
|
|
|
|
* The preview widget for the current disk is completely re-constructed
|
|
|
|
* based on the on-disk state. This also triggers a rescan in the
|
|
|
|
* PCM to get a Device* copy that's unaffected by subsequent PCM changes.
|
2015-10-29 17:34:59 +01:00
|
|
|
*/
|
2015-10-23 17:45:28 +02:00
|
|
|
void
|
2015-12-17 18:02:14 +01:00
|
|
|
ChoicePage::updateDeviceStatePreview()
|
2015-10-23 17:45:28 +02:00
|
|
|
{
|
2015-10-29 17:34:59 +01:00
|
|
|
//FIXME: this needs to be made async because the rescan can block the UI thread for
|
|
|
|
// a while. --Teo 10/2015
|
2015-12-17 18:02:14 +01:00
|
|
|
Device* currentDevice = selectedDevice();
|
2015-10-23 17:45:28 +02:00
|
|
|
Q_ASSERT( currentDevice );
|
|
|
|
QMutexLocker locker( &m_previewsMutex );
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
cDebug() << "Updating partitioning state widgets.";
|
|
|
|
qDeleteAll( m_previewBeforeFrame->children() );
|
2015-10-23 17:45:28 +02:00
|
|
|
|
2017-09-07 10:04:50 +02:00
|
|
|
auto layout = m_previewBeforeFrame->layout();
|
|
|
|
if ( layout )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2017-09-07 10:04:50 +02:00
|
|
|
layout->deleteLater(); // Doesn't like nullptr
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2017-09-07 10:04:50 +02:00
|
|
|
|
|
|
|
layout = new QVBoxLayout;
|
2015-10-29 17:34:59 +01:00
|
|
|
m_previewBeforeFrame->setLayout( layout );
|
2015-12-03 19:40:06 +01:00
|
|
|
CalamaresUtils::unmarginLayout( layout );
|
|
|
|
layout->setSpacing( 6 );
|
2015-10-06 18:56:33 +02:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
PartitionBarsView::NestedPartitionsMode mode
|
|
|
|
= Calamares::JobQueue::instance()->globalStorage()->value( "drawNestedPartitions" ).toBool()
|
|
|
|
? PartitionBarsView::DrawNestedPartitions
|
|
|
|
: PartitionBarsView::NoNestedPartitions;
|
2015-12-17 15:39:52 +01:00
|
|
|
m_beforePartitionBarsView = new PartitionBarsView( m_previewBeforeFrame );
|
2016-02-10 14:59:17 +01:00
|
|
|
m_beforePartitionBarsView->setNestedPartitionsMode( mode );
|
2015-12-17 15:39:52 +01:00
|
|
|
m_beforePartitionLabelsView = new PartitionLabelsView( m_previewBeforeFrame );
|
2016-02-11 16:00:36 +01:00
|
|
|
m_beforePartitionLabelsView->setExtendedPartitionHidden( mode == PartitionBarsView::NoNestedPartitions );
|
2015-10-23 17:45:28 +02:00
|
|
|
|
2016-09-09 11:25:04 +02:00
|
|
|
Device* deviceBefore = m_core->immutableDeviceCopy( currentDevice );
|
2015-10-23 17:45:28 +02:00
|
|
|
|
2015-12-17 15:39:52 +01:00
|
|
|
PartitionModel* model = new PartitionModel( m_beforePartitionBarsView );
|
2015-12-15 14:00:34 +01:00
|
|
|
model->init( deviceBefore, m_core->osproberEntries() );
|
2015-10-23 17:45:28 +02:00
|
|
|
|
2015-12-17 15:39:52 +01:00
|
|
|
m_beforePartitionBarsView->setModel( model );
|
|
|
|
m_beforePartitionLabelsView->setModel( model );
|
2015-12-17 13:45:11 +01:00
|
|
|
|
|
|
|
// Make the bars and labels view use the same selectionModel.
|
2015-12-17 15:39:52 +01:00
|
|
|
auto sm = m_beforePartitionLabelsView->selectionModel();
|
|
|
|
m_beforePartitionLabelsView->setSelectionModel( m_beforePartitionBarsView->selectionModel() );
|
2017-09-07 10:04:50 +02:00
|
|
|
if ( sm )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2017-09-07 10:04:50 +02:00
|
|
|
sm->deleteLater();
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2015-12-17 13:45:11 +01:00
|
|
|
|
2020-09-29 14:00:49 +02:00
|
|
|
switch ( m_config->installChoice() )
|
2015-12-17 13:45:11 +01:00
|
|
|
{
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Replace:
|
|
|
|
case InstallChoice::Alongside:
|
2015-12-17 15:39:52 +01:00
|
|
|
m_beforePartitionBarsView->setSelectionMode( QAbstractItemView::SingleSelection );
|
|
|
|
m_beforePartitionLabelsView->setSelectionMode( QAbstractItemView::SingleSelection );
|
2015-12-17 13:45:11 +01:00
|
|
|
break;
|
2020-10-31 23:16:48 +01:00
|
|
|
case InstallChoice::NoChoice:
|
|
|
|
case InstallChoice::Erase:
|
|
|
|
case InstallChoice::Manual:
|
2015-12-17 15:39:52 +01:00
|
|
|
m_beforePartitionBarsView->setSelectionMode( QAbstractItemView::NoSelection );
|
|
|
|
m_beforePartitionLabelsView->setSelectionMode( QAbstractItemView::NoSelection );
|
2015-12-17 13:45:11 +01:00
|
|
|
}
|
2015-12-16 18:23:29 +01:00
|
|
|
|
2015-12-17 15:39:52 +01:00
|
|
|
layout->addWidget( m_beforePartitionBarsView );
|
|
|
|
layout->addWidget( m_beforePartitionLabelsView );
|
2015-10-23 17:45:28 +02:00
|
|
|
}
|
2015-10-06 18:56:33 +02:00
|
|
|
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
/**
|
2020-10-23 23:14:00 +02:00
|
|
|
* @brief rebuild the contents of the preview for the PCM-proposed state.
|
|
|
|
*
|
|
|
|
* No rescans here, this should be immediate.
|
|
|
|
*
|
2015-10-29 17:34:59 +01:00
|
|
|
* @param choice the chosen partitioning action.
|
|
|
|
*/
|
|
|
|
void
|
2020-10-02 12:08:42 +02:00
|
|
|
ChoicePage::updateActionChoicePreview( InstallChoice choice )
|
2015-10-29 17:34:59 +01:00
|
|
|
{
|
2015-12-17 18:02:14 +01:00
|
|
|
Device* currentDevice = selectedDevice();
|
2015-10-29 17:34:59 +01:00
|
|
|
Q_ASSERT( currentDevice );
|
2015-12-17 13:45:11 +01:00
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
QMutexLocker locker( &m_previewsMutex );
|
|
|
|
|
|
|
|
cDebug() << "Updating partitioning preview widgets.";
|
|
|
|
qDeleteAll( m_previewAfterFrame->children() );
|
2017-09-07 10:04:50 +02:00
|
|
|
|
|
|
|
auto oldlayout = m_previewAfterFrame->layout();
|
|
|
|
if ( oldlayout )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2017-09-07 10:04:50 +02:00
|
|
|
oldlayout->deleteLater();
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2015-10-29 17:34:59 +01:00
|
|
|
|
|
|
|
QVBoxLayout* layout = new QVBoxLayout;
|
|
|
|
m_previewAfterFrame->setLayout( layout );
|
2015-12-03 19:40:06 +01:00
|
|
|
CalamaresUtils::unmarginLayout( layout );
|
|
|
|
layout->setSpacing( 6 );
|
2015-10-29 17:34:59 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
PartitionBarsView::NestedPartitionsMode mode
|
|
|
|
= Calamares::JobQueue::instance()->globalStorage()->value( "drawNestedPartitions" ).toBool()
|
|
|
|
? PartitionBarsView::DrawNestedPartitions
|
|
|
|
: PartitionBarsView::NoNestedPartitions;
|
2016-02-10 17:02:42 +01:00
|
|
|
|
2016-07-15 11:32:34 +02:00
|
|
|
m_reuseHomeCheckBox->hide();
|
2016-07-15 13:09:07 +02:00
|
|
|
Calamares::JobQueue::instance()->globalStorage()->insert( "reuseHome", false );
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
switch ( choice )
|
|
|
|
{
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Alongside:
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
|
|
|
if ( m_enableEncryptionWidget )
|
2016-01-11 19:02:34 +01:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
m_encryptWidget->show();
|
|
|
|
}
|
|
|
|
m_previewBeforeLabel->setText( tr( "Current:" ) );
|
|
|
|
m_selectLabel->setText( tr( "<strong>Select a partition to shrink, "
|
|
|
|
"then drag the bottom bar to resize</strong>" ) );
|
|
|
|
m_selectLabel->show();
|
|
|
|
|
|
|
|
m_afterPartitionSplitterWidget = new PartitionSplitterWidget( m_previewAfterFrame );
|
|
|
|
m_afterPartitionSplitterWidget->init( selectedDevice(), mode == PartitionBarsView::DrawNestedPartitions );
|
|
|
|
layout->addWidget( m_afterPartitionSplitterWidget );
|
|
|
|
|
|
|
|
QLabel* sizeLabel = new QLabel( m_previewAfterFrame );
|
|
|
|
layout->addWidget( sizeLabel );
|
|
|
|
sizeLabel->setWordWrap( true );
|
|
|
|
connect( m_afterPartitionSplitterWidget,
|
|
|
|
&PartitionSplitterWidget::partitionResized,
|
|
|
|
this,
|
2020-10-12 14:27:01 +02:00
|
|
|
[this, sizeLabel]( const QString& path, qint64 size, qint64 sizeNext ) {
|
2020-08-22 01:19:58 +02:00
|
|
|
Q_UNUSED( path )
|
|
|
|
sizeLabel->setText(
|
|
|
|
tr( "%1 will be shrunk to %2MiB and a new "
|
|
|
|
"%3MiB partition will be created for %4." )
|
|
|
|
.arg( m_beforePartitionBarsView->selectionModel()->currentIndex().data().toString() )
|
|
|
|
.arg( CalamaresUtils::BytesToMiB( size ) )
|
|
|
|
.arg( CalamaresUtils::BytesToMiB( sizeNext ) )
|
|
|
|
.arg( Calamares::Branding::instance()->shortProductName() ) );
|
|
|
|
} );
|
|
|
|
|
|
|
|
m_previewAfterFrame->show();
|
|
|
|
m_previewAfterLabel->show();
|
|
|
|
|
2020-10-31 23:16:48 +01:00
|
|
|
SelectionFilter filter = []( const QModelIndex& index ) {
|
2020-08-22 01:19:58 +02:00
|
|
|
return PartUtils::canBeResized(
|
|
|
|
static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ) );
|
|
|
|
};
|
|
|
|
m_beforePartitionBarsView->setSelectionFilter( filter );
|
|
|
|
m_beforePartitionLabelsView->setSelectionFilter( filter );
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case InstallChoice::Erase:
|
|
|
|
case InstallChoice::Replace:
|
|
|
|
{
|
|
|
|
if ( m_enableEncryptionWidget )
|
|
|
|
{
|
|
|
|
m_encryptWidget->show();
|
|
|
|
}
|
|
|
|
m_previewBeforeLabel->setText( tr( "Current:" ) );
|
|
|
|
m_afterPartitionBarsView = new PartitionBarsView( m_previewAfterFrame );
|
|
|
|
m_afterPartitionBarsView->setNestedPartitionsMode( mode );
|
|
|
|
m_afterPartitionLabelsView = new PartitionLabelsView( m_previewAfterFrame );
|
|
|
|
m_afterPartitionLabelsView->setExtendedPartitionHidden( mode == PartitionBarsView::NoNestedPartitions );
|
|
|
|
m_afterPartitionLabelsView->setCustomNewRootLabel(
|
|
|
|
Calamares::Branding::instance()->string( Calamares::Branding::BootloaderEntryName ) );
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
PartitionModel* model = m_core->partitionModelForDevice( selectedDevice() );
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
// The QObject parents tree is meaningful for memory management here,
|
|
|
|
// see qDeleteAll above.
|
|
|
|
m_afterPartitionBarsView->setModel( model );
|
|
|
|
m_afterPartitionLabelsView->setModel( model );
|
|
|
|
m_afterPartitionBarsView->setSelectionMode( QAbstractItemView::NoSelection );
|
|
|
|
m_afterPartitionLabelsView->setSelectionMode( QAbstractItemView::NoSelection );
|
2016-01-11 19:02:34 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
layout->addWidget( m_afterPartitionBarsView );
|
|
|
|
layout->addWidget( m_afterPartitionLabelsView );
|
2016-01-15 18:20:40 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( !m_isEfi )
|
2015-10-29 17:34:59 +01:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
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 );
|
2020-10-12 14:27:01 +02:00
|
|
|
connect( m_core->bootLoaderModel(), &QAbstractItemModel::modelReset, [this]() {
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( !m_bootloaderComboBox.isNull() )
|
|
|
|
{
|
|
|
|
Calamares::restoreSelectedBootLoader( *m_bootloaderComboBox, m_core->bootLoaderInstallPath() );
|
|
|
|
}
|
|
|
|
} );
|
2021-03-16 16:08:13 +01:00
|
|
|
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 );
|
2020-08-22 01:19:58 +02:00
|
|
|
// ^ Must be Queued so it's sure to run when the widget is already visible.
|
2016-01-28 18:43:35 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
eraseLayout->addWidget( m_bootloaderComboBox );
|
|
|
|
eraseBootloaderLabel->setBuddy( m_bootloaderComboBox );
|
|
|
|
eraseLayout->addStretch();
|
2016-01-28 18:43:35 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
layout->addWidget( eraseWidget );
|
|
|
|
}
|
2015-12-22 12:41:47 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
m_previewAfterFrame->show();
|
|
|
|
m_previewAfterLabel->show();
|
2015-12-22 12:41:47 +01:00
|
|
|
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_config->installChoice() == InstallChoice::Erase )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
|
|
|
m_selectLabel->hide();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-31 23:16:48 +01:00
|
|
|
SelectionFilter filter = []( const QModelIndex& index ) {
|
2020-08-22 01:19:58 +02:00
|
|
|
return PartUtils::canBeReplaced(
|
|
|
|
static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ) );
|
|
|
|
};
|
|
|
|
m_beforePartitionBarsView->setSelectionFilter( filter );
|
|
|
|
m_beforePartitionLabelsView->setSelectionFilter( filter );
|
|
|
|
|
|
|
|
m_selectLabel->show();
|
|
|
|
m_selectLabel->setText( tr( "<strong>Select a partition to install on</strong>" ) );
|
2015-10-29 17:34:59 +01:00
|
|
|
}
|
2020-08-22 01:19:58 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::NoChoice:
|
|
|
|
case InstallChoice::Manual:
|
2015-12-22 12:41:47 +01:00
|
|
|
m_selectLabel->hide();
|
2015-10-29 17:34:59 +01:00
|
|
|
m_previewAfterFrame->hide();
|
2016-01-25 16:58:54 +01:00
|
|
|
m_previewBeforeLabel->setText( tr( "Current:" ) );
|
2015-12-31 16:55:18 +01:00
|
|
|
m_previewAfterLabel->hide();
|
2016-04-22 16:02:07 +02:00
|
|
|
m_encryptWidget->hide();
|
2015-10-29 17:34:59 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-12-17 13:45:11 +01:00
|
|
|
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_isEfi
|
|
|
|
&& ( m_config->installChoice() == InstallChoice::Alongside
|
|
|
|
|| m_config->installChoice() == InstallChoice::Replace ) )
|
2016-02-19 16:33:19 +01:00
|
|
|
{
|
|
|
|
QHBoxLayout* efiLayout = new QHBoxLayout;
|
|
|
|
layout->addLayout( efiLayout );
|
|
|
|
m_efiLabel = new QLabel( m_previewAfterFrame );
|
|
|
|
efiLayout->addWidget( m_efiLabel );
|
|
|
|
m_efiComboBox = new QComboBox( m_previewAfterFrame );
|
|
|
|
efiLayout->addWidget( m_efiComboBox );
|
|
|
|
m_efiLabel->setBuddy( m_efiComboBox );
|
|
|
|
m_efiComboBox->hide();
|
|
|
|
efiLayout->addStretch();
|
|
|
|
}
|
|
|
|
|
2015-12-17 13:45:11 +01:00
|
|
|
// Also handle selection behavior on beforeFrame.
|
2021-03-29 11:06:16 +02:00
|
|
|
QAbstractItemView::SelectionMode previewSelectionMode = QAbstractItemView::NoSelection;
|
2020-09-29 14:00:49 +02:00
|
|
|
switch ( m_config->installChoice() )
|
2015-12-17 13:45:11 +01:00
|
|
|
{
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Replace:
|
|
|
|
case InstallChoice::Alongside:
|
2015-12-17 13:45:11 +01:00
|
|
|
previewSelectionMode = QAbstractItemView::SingleSelection;
|
|
|
|
break;
|
2020-10-31 23:16:48 +01:00
|
|
|
case InstallChoice::NoChoice:
|
|
|
|
case InstallChoice::Erase:
|
|
|
|
case InstallChoice::Manual:
|
2015-12-17 13:45:11 +01:00
|
|
|
previewSelectionMode = QAbstractItemView::NoSelection;
|
|
|
|
}
|
|
|
|
|
2015-12-31 15:02:46 +01:00
|
|
|
m_beforePartitionBarsView->setSelectionMode( previewSelectionMode );
|
|
|
|
m_beforePartitionLabelsView->setSelectionMode( previewSelectionMode );
|
2015-10-29 17:34:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-19 16:57:49 +01:00
|
|
|
void
|
|
|
|
ChoicePage::setupEfiSystemPartitionSelector()
|
|
|
|
{
|
|
|
|
Q_ASSERT( m_isEfi );
|
|
|
|
|
|
|
|
// Only the already existing ones:
|
|
|
|
QList< Partition* > efiSystemPartitions = m_core->efiSystemPartitions();
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( efiSystemPartitions.count() == 0 ) //should never happen
|
2016-02-19 16:57:49 +01:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
m_efiLabel->setText( tr( "An EFI system partition cannot be found anywhere "
|
|
|
|
"on this system. Please go back and use manual "
|
|
|
|
"partitioning to set up %1." )
|
|
|
|
.arg( Calamares::Branding::instance()->shortProductName() ) );
|
2016-04-22 16:02:07 +02:00
|
|
|
updateNextEnabled();
|
2016-02-19 16:57:49 +01:00
|
|
|
}
|
2020-08-22 01:19:58 +02:00
|
|
|
else if ( efiSystemPartitions.count() == 1 ) //probably most usual situation
|
2016-02-19 16:57:49 +01:00
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
m_efiLabel->setText( tr( "The EFI system partition at %1 will be used for "
|
|
|
|
"starting %2." )
|
|
|
|
.arg( efiSystemPartitions.first()->partitionPath() )
|
|
|
|
.arg( Calamares::Branding::instance()->shortProductName() ) );
|
2016-02-19 16:57:49 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_efiComboBox->show();
|
|
|
|
m_efiLabel->setText( tr( "EFI system partition:" ) );
|
|
|
|
for ( int i = 0; i < efiSystemPartitions.count(); ++i )
|
|
|
|
{
|
|
|
|
Partition* efiPartition = efiSystemPartitions.at( i );
|
|
|
|
m_efiComboBox->addItem( efiPartition->partitionPath(), i );
|
|
|
|
|
|
|
|
// We pick an ESP on the currently selected device, if possible
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( efiPartition->devicePath() == selectedDevice()->deviceNode() && efiPartition->number() == 1 )
|
|
|
|
{
|
2016-02-19 16:57:49 +01:00
|
|
|
m_efiComboBox->setCurrentIndex( i );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-02-19 16:57:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-28 18:43:35 +01:00
|
|
|
QComboBox*
|
|
|
|
ChoicePage::createBootloaderComboBox( QWidget* parent )
|
|
|
|
{
|
2020-10-31 23:16:48 +01:00
|
|
|
QComboBox* comboForBootloader = new QComboBox( parent );
|
|
|
|
comboForBootloader->setModel( m_core->bootLoaderModel() );
|
2016-01-28 18:43:35 +01:00
|
|
|
|
|
|
|
// When the chosen bootloader device changes, we update the choice in the PCM
|
2020-10-31 23:16:48 +01:00
|
|
|
connect( comboForBootloader, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, [this]( int newIndex ) {
|
|
|
|
QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() );
|
|
|
|
if ( bootloaderCombo )
|
2016-01-29 16:49:21 +01:00
|
|
|
{
|
2020-10-31 23:16:48 +01:00
|
|
|
QVariant var = bootloaderCombo->itemData( newIndex, BootLoaderModel::BootLoaderPathRole );
|
2016-01-29 17:07:08 +01:00
|
|
|
if ( !var.isValid() )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-01-29 17:07:08 +01:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-01-29 17:07:08 +01:00
|
|
|
m_core->setBootLoaderInstallPath( var.toString() );
|
2016-01-29 16:49:21 +01:00
|
|
|
}
|
2016-01-29 17:07:08 +01:00
|
|
|
} );
|
2016-01-28 18:43:35 +01:00
|
|
|
|
2020-10-31 23:16:48 +01:00
|
|
|
return comboForBootloader;
|
2016-01-28 18:43:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-07 10:55:26 +02:00
|
|
|
static inline void
|
2020-08-22 01:19:58 +02:00
|
|
|
force_uncheck( QButtonGroup* grp, PrettyRadioButton* button )
|
2017-09-07 10:55:26 +02:00
|
|
|
{
|
|
|
|
button->hide();
|
|
|
|
grp->setExclusive( false );
|
2020-05-18 11:01:54 +02:00
|
|
|
button->setChecked( false );
|
2017-09-07 10:55:26 +02:00
|
|
|
grp->setExclusive( true );
|
|
|
|
}
|
|
|
|
|
2018-10-03 19:49:52 +02:00
|
|
|
static inline QDebug&
|
2020-08-22 01:19:58 +02:00
|
|
|
operator<<( QDebug& s, PartitionIterator& it )
|
2018-10-03 19:49:52 +02:00
|
|
|
{
|
|
|
|
s << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
* on the currently selected Device*, bootloader and os-prober output.
|
|
|
|
*/
|
2015-10-23 17:45:28 +02:00
|
|
|
void
|
2015-12-17 18:02:14 +01:00
|
|
|
ChoicePage::setupActions()
|
2015-10-23 17:45:28 +02:00
|
|
|
{
|
2015-12-17 18:02:14 +01:00
|
|
|
Device* currentDevice = selectedDevice();
|
2020-08-22 01:19:58 +02:00
|
|
|
OsproberEntryList osproberEntriesForCurrentDevice = getOsproberEntriesForDevice( currentDevice );
|
2015-11-27 14:47:52 +01:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
cDebug() << "Setting up actions for" << currentDevice->deviceNode() << "with"
|
|
|
|
<< osproberEntriesForCurrentDevice.count() << "entries.";
|
2018-10-03 19:49:52 +02:00
|
|
|
|
2015-11-27 17:25:47 +01:00
|
|
|
if ( currentDevice->partitionTable() )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2015-11-27 17:25:47 +01:00
|
|
|
m_deviceInfoWidget->setPartitionTableType( currentDevice->partitionTable()->type() );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2015-11-27 17:25:47 +01:00
|
|
|
else
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2015-11-27 17:25:47 +01:00
|
|
|
m_deviceInfoWidget->setPartitionTableType( PartitionTable::unknownTableType );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2015-11-27 17:25:47 +01:00
|
|
|
|
2020-10-02 13:04:12 +02:00
|
|
|
if ( m_config->allowManualPartitioning() )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2019-01-07 17:27:40 +01:00
|
|
|
m_somethingElseButton->show();
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2019-01-07 17:27:40 +01:00
|
|
|
else
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2019-01-07 17:27:40 +01:00
|
|
|
force_uncheck( m_grp, m_somethingElseButton );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2018-01-09 11:09:24 +01:00
|
|
|
|
2016-02-12 16:48:29 +01:00
|
|
|
bool atLeastOneCanBeResized = false;
|
2017-09-07 10:55:26 +02:00
|
|
|
bool atLeastOneCanBeReplaced = false;
|
|
|
|
bool atLeastOneIsMounted = false; // Suppress 'erase' if so
|
2018-08-13 17:26:00 +02:00
|
|
|
bool isInactiveRAID = false;
|
2020-05-21 23:13:28 +02:00
|
|
|
bool matchTableType = false;
|
2018-08-13 17:26:00 +02:00
|
|
|
|
2019-04-12 11:21:18 +02:00
|
|
|
#ifdef WITH_KPMCORE4API
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( currentDevice->type() == Device::Type::SoftwareRAID_Device
|
|
|
|
&& static_cast< SoftwareRAID* >( currentDevice )->status() == SoftwareRAID::Status::Inactive )
|
2018-10-03 13:58:50 +02:00
|
|
|
{
|
2019-04-25 13:42:59 +02:00
|
|
|
cDebug() << Logger::SubEntry << "part of an inactive RAID device";
|
2018-08-13 17:26:00 +02:00
|
|
|
isInactiveRAID = true;
|
2018-10-03 13:58:50 +02:00
|
|
|
}
|
2018-09-21 22:19:05 +02:00
|
|
|
#endif
|
2016-02-12 16:48:29 +01:00
|
|
|
|
2020-05-21 23:13:28 +02:00
|
|
|
PartitionTable::TableType tableType = PartitionTable::unknownTableType;
|
|
|
|
if ( currentDevice->partitionTable() )
|
|
|
|
{
|
|
|
|
tableType = currentDevice->partitionTable()->type();
|
2020-10-12 14:27:01 +02:00
|
|
|
matchTableType = m_requiredPartitionTableType.size() == 0
|
|
|
|
|| m_requiredPartitionTableType.contains( PartitionTable::tableTypeToName( tableType ) );
|
2020-05-21 23:13:28 +02:00
|
|
|
}
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
for ( auto it = PartitionIterator::begin( currentDevice ); it != PartitionIterator::end( currentDevice ); ++it )
|
2016-02-12 16:48:29 +01:00
|
|
|
{
|
|
|
|
if ( PartUtils::canBeResized( *it ) )
|
2018-10-03 13:58:50 +02:00
|
|
|
{
|
2019-04-15 14:15:17 +02:00
|
|
|
cDebug() << Logger::SubEntry << "contains resizable" << it;
|
2016-02-12 16:48:29 +01:00
|
|
|
atLeastOneCanBeResized = true;
|
2018-10-03 13:58:50 +02:00
|
|
|
}
|
2016-03-18 12:26:41 +01:00
|
|
|
if ( PartUtils::canBeReplaced( *it ) )
|
2018-10-03 13:58:50 +02:00
|
|
|
{
|
2019-04-15 14:15:17 +02:00
|
|
|
cDebug() << Logger::SubEntry << "contains replaceable" << it;
|
2016-03-18 12:26:41 +01:00
|
|
|
atLeastOneCanBeReplaced = true;
|
2018-10-03 13:58:50 +02:00
|
|
|
}
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( ( *it )->isMounted() )
|
2018-10-03 13:58:50 +02:00
|
|
|
{
|
2017-09-07 10:55:26 +02:00
|
|
|
atLeastOneIsMounted = true;
|
2018-10-03 13:58:50 +02:00
|
|
|
}
|
2016-03-18 12:26:41 +01:00
|
|
|
}
|
|
|
|
|
2015-11-27 14:47:52 +01:00
|
|
|
if ( osproberEntriesForCurrentDevice.count() == 0 )
|
2014-09-03 18:09:37 +02:00
|
|
|
{
|
2014-11-11 17:09:33 +01:00
|
|
|
CALAMARES_RETRANSLATE(
|
2019-02-11 11:32:42 +01:00
|
|
|
cDebug() << "Setting texts for 0 osprober entries";
|
2015-11-27 14:47:52 +01:00
|
|
|
m_messageLabel->setText( tr( "This storage device does not seem to have an operating system on it. "
|
2015-12-03 14:39:23 +01:00
|
|
|
"What would you like to do?<br/>"
|
|
|
|
"You will be able to review and confirm your choices "
|
|
|
|
"before any change is made to the storage device." ) );
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2015-12-15 17:21:45 +01:00
|
|
|
m_eraseButton->setText( tr( "<strong>Erase disk</strong><br/>"
|
2015-12-21 11:28:11 +01:00
|
|
|
"This will <font color=\"red\">delete</font> all data "
|
|
|
|
"currently present on the selected storage device." ) );
|
2016-03-18 12:26:41 +01:00
|
|
|
|
|
|
|
m_alongsideButton->setText( tr( "<strong>Install alongside</strong><br/>"
|
|
|
|
"The installer will shrink a partition to make room for %1." )
|
2020-08-22 01:19:58 +02:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) );
|
2016-03-18 12:26:41 +01:00
|
|
|
|
|
|
|
m_replaceButton->setText( tr( "<strong>Replace a partition</strong><br/>"
|
|
|
|
"Replaces a partition with %1." )
|
2021-03-16 16:01:25 +01:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) ); );
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2015-10-06 18:56:33 +02:00
|
|
|
m_replaceButton->hide();
|
|
|
|
m_alongsideButton->hide();
|
2016-01-08 16:43:58 +01:00
|
|
|
m_grp->setExclusive( false );
|
2020-05-18 11:01:54 +02:00
|
|
|
m_replaceButton->setChecked( false );
|
|
|
|
m_alongsideButton->setChecked( false );
|
2016-01-08 16:43:58 +01:00
|
|
|
m_grp->setExclusive( true );
|
2014-09-03 18:09:37 +02:00
|
|
|
}
|
2015-11-27 14:47:52 +01:00
|
|
|
else if ( osproberEntriesForCurrentDevice.count() == 1 )
|
2014-09-03 18:09:37 +02:00
|
|
|
{
|
2015-11-27 14:47:52 +01:00
|
|
|
QString osName = osproberEntriesForCurrentDevice.first().prettyName;
|
2014-09-23 17:42:11 +02:00
|
|
|
|
|
|
|
if ( !osName.isEmpty() )
|
2014-09-03 18:09:37 +02:00
|
|
|
{
|
2014-11-11 17:09:33 +01:00
|
|
|
CALAMARES_RETRANSLATE(
|
2019-02-11 11:32:42 +01:00
|
|
|
cDebug() << "Setting texts for 1 non-empty osprober entry";
|
2015-11-27 14:47:52 +01:00
|
|
|
m_messageLabel->setText( tr( "This storage device has %1 on it. "
|
2015-12-04 16:23:59 +01:00
|
|
|
"What would you like to do?<br/>"
|
|
|
|
"You will be able to review and confirm your choices "
|
|
|
|
"before any change is made to the storage device." )
|
2020-08-22 01:19:58 +02:00
|
|
|
.arg( osName ) );
|
2014-11-11 17:09:33 +01:00
|
|
|
|
2015-12-15 17:28:21 +01:00
|
|
|
m_alongsideButton->setText( tr( "<strong>Install alongside</strong><br/>"
|
2015-12-21 11:24:06 +01:00
|
|
|
"The installer will shrink a partition to make room for %1." )
|
2020-08-22 01:19:58 +02:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) );
|
2014-11-11 17:09:33 +01:00
|
|
|
|
2015-12-15 17:21:45 +01:00
|
|
|
m_eraseButton->setText( tr( "<strong>Erase disk</strong><br/>"
|
2015-12-21 11:28:11 +01:00
|
|
|
"This will <font color=\"red\">delete</font> all data "
|
|
|
|
"currently present on the selected storage device." ) );
|
2014-12-16 17:04:09 +01:00
|
|
|
|
2015-10-29 17:34:59 +01:00
|
|
|
|
2015-12-15 17:23:13 +01:00
|
|
|
m_replaceButton->setText( tr( "<strong>Replace a partition</strong><br/>"
|
2015-12-21 11:26:12 +01:00
|
|
|
"Replaces a partition with %1." )
|
2021-03-16 16:01:25 +01:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) ); );
|
2014-09-03 18:09:37 +02:00
|
|
|
}
|
2014-09-19 16:27:39 +02:00
|
|
|
else
|
2014-09-23 17:42:11 +02:00
|
|
|
{
|
2014-11-11 17:09:33 +01:00
|
|
|
CALAMARES_RETRANSLATE(
|
2019-02-11 11:32:42 +01:00
|
|
|
cDebug() << "Setting texts for 1 empty osprober entry";
|
2015-11-27 14:47:52 +01:00
|
|
|
m_messageLabel->setText( tr( "This storage device already has an operating system on it. "
|
2015-12-04 16:23:59 +01:00
|
|
|
"What would you like to do?<br/>"
|
|
|
|
"You will be able to review and confirm your choices "
|
|
|
|
"before any change is made to the storage device." ) );
|
2014-11-11 17:09:33 +01:00
|
|
|
|
2015-12-15 17:28:21 +01:00
|
|
|
m_alongsideButton->setText( tr( "<strong>Install alongside</strong><br/>"
|
2015-12-21 11:24:06 +01:00
|
|
|
"The installer will shrink a partition to make room for %1." )
|
2020-08-22 01:19:58 +02:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) );
|
2014-11-11 17:09:33 +01:00
|
|
|
|
2015-12-15 17:21:45 +01:00
|
|
|
m_eraseButton->setText( tr( "<strong>Erase disk</strong><br/>"
|
2015-12-21 11:28:11 +01:00
|
|
|
"This will <font color=\"red\">delete</font> all data "
|
|
|
|
"currently present on the selected storage device." ) );
|
2014-12-16 17:04:09 +01:00
|
|
|
|
2015-12-15 17:23:13 +01:00
|
|
|
m_replaceButton->setText( tr( "<strong>Replace a partition</strong><br/>"
|
2015-12-21 11:26:12 +01:00
|
|
|
"Replaces a partition with %1." )
|
2021-03-16 16:01:25 +01:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) ); );
|
2014-09-23 17:42:11 +02:00
|
|
|
}
|
2014-09-03 18:09:37 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-27 14:47:52 +01:00
|
|
|
// osproberEntriesForCurrentDevice has at least 2 items.
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2014-11-11 17:09:33 +01:00
|
|
|
CALAMARES_RETRANSLATE(
|
2019-02-11 11:32:42 +01:00
|
|
|
cDebug() << "Setting texts for >= 2 osprober entries";
|
|
|
|
|
2015-11-27 14:47:52 +01:00
|
|
|
m_messageLabel->setText( tr( "This storage device has multiple operating systems on it. "
|
2015-12-04 16:23:59 +01:00
|
|
|
"What would you like to do?<br/>"
|
|
|
|
"You will be able to review and confirm your choices "
|
|
|
|
"before any change is made to the storage device." ) );
|
2014-11-11 17:09:33 +01:00
|
|
|
|
2015-12-15 17:28:21 +01:00
|
|
|
m_alongsideButton->setText( tr( "<strong>Install alongside</strong><br/>"
|
2015-12-21 11:24:06 +01:00
|
|
|
"The installer will shrink a partition to make room for %1." )
|
2020-08-22 01:19:58 +02:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) );
|
2014-09-22 17:21:50 +02:00
|
|
|
|
2015-12-15 17:21:45 +01:00
|
|
|
m_eraseButton->setText( tr( "<strong>Erase disk</strong><br/>"
|
2015-12-21 11:28:11 +01:00
|
|
|
"This will <font color=\"red\">delete</font> all data "
|
|
|
|
"currently present on the selected storage device." ) );
|
2014-12-16 17:04:09 +01:00
|
|
|
|
2015-12-15 17:23:13 +01:00
|
|
|
m_replaceButton->setText( tr( "<strong>Replace a partition</strong><br/>"
|
2015-12-21 11:26:12 +01:00
|
|
|
"Replaces a partition with %1." )
|
2021-03-16 16:01:25 +01:00
|
|
|
.arg( Calamares::Branding::instance()->shortVersionedName() ) ); );
|
2014-09-03 18:09:37 +02:00
|
|
|
}
|
|
|
|
|
2019-03-17 21:26:37 +01:00
|
|
|
#ifdef DEBUG_PARTITION_UNSAFE
|
|
|
|
#ifdef DEBUG_PARTITION_LAME
|
|
|
|
// If things can't be broken, allow all the buttons
|
|
|
|
atLeastOneCanBeReplaced = true;
|
|
|
|
atLeastOneCanBeResized = true;
|
|
|
|
atLeastOneIsMounted = false;
|
|
|
|
isInactiveRAID = false;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2016-03-18 12:26:41 +01:00
|
|
|
if ( atLeastOneCanBeReplaced )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-03-18 12:26:41 +01:00
|
|
|
m_replaceButton->show();
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-03-18 12:26:41 +01:00
|
|
|
else
|
2019-04-04 17:37:37 +02:00
|
|
|
{
|
2021-03-29 14:14:05 +02:00
|
|
|
cDebug() << "No partitions available for replace-action.";
|
2017-09-07 10:55:26 +02:00
|
|
|
force_uncheck( m_grp, m_replaceButton );
|
2019-04-04 17:37:37 +02:00
|
|
|
}
|
2016-03-18 12:26:41 +01:00
|
|
|
|
|
|
|
if ( atLeastOneCanBeResized )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2016-03-18 12:26:41 +01:00
|
|
|
m_alongsideButton->show();
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2016-03-18 12:26:41 +01:00
|
|
|
else
|
2019-04-04 17:37:37 +02:00
|
|
|
{
|
2021-03-29 14:14:05 +02:00
|
|
|
cDebug() << "No partitions available for resize-action.";
|
2017-09-07 10:55:26 +02:00
|
|
|
force_uncheck( m_grp, m_alongsideButton );
|
2019-04-04 17:37:37 +02:00
|
|
|
}
|
2017-09-07 10:55:26 +02:00
|
|
|
|
2018-08-13 17:26:00 +02:00
|
|
|
if ( !atLeastOneIsMounted && !isInactiveRAID )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2017-09-07 10:55:26 +02:00
|
|
|
m_eraseButton->show(); // None mounted
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2017-09-07 10:55:26 +02:00
|
|
|
else
|
2018-10-03 13:58:50 +02:00
|
|
|
{
|
2021-03-29 14:14:05 +02:00
|
|
|
cDebug() << "No partitions ("
|
|
|
|
<< "any-mounted?" << atLeastOneIsMounted << "is-raid?" << isInactiveRAID << ") for erase-action.";
|
2017-09-07 10:55:26 +02:00
|
|
|
force_uncheck( m_grp, m_eraseButton );
|
2018-10-03 13:58:50 +02:00
|
|
|
}
|
2016-03-18 12:26:41 +01:00
|
|
|
|
2017-08-28 11:36:21 +02:00
|
|
|
bool isEfi = PartUtils::isEfiSystem();
|
2015-05-28 19:24:39 +02:00
|
|
|
bool efiSystemPartitionFound = !m_core->efiSystemPartitions().isEmpty();
|
|
|
|
|
|
|
|
if ( isEfi && !efiSystemPartitionFound )
|
|
|
|
{
|
2018-02-13 11:07:12 +01:00
|
|
|
cWarning() << "System is EFI but there's no EFI system partition, "
|
2020-08-22 01:19:58 +02:00
|
|
|
"DISABLING alongside and replace features.";
|
2015-10-06 18:56:33 +02:00
|
|
|
m_alongsideButton->hide();
|
|
|
|
m_replaceButton->hide();
|
2015-05-28 19:24:39 +02:00
|
|
|
}
|
2020-06-16 10:34:59 +02:00
|
|
|
|
2020-05-21 23:13:28 +02:00
|
|
|
if ( tableType != PartitionTable::unknownTableType && !matchTableType )
|
|
|
|
{
|
2020-10-16 22:32:32 +02:00
|
|
|
m_messageLabel->setText( tr( "This storage device already has an operating system on it, "
|
|
|
|
"but the partition table <strong>%1</strong> is different from the "
|
|
|
|
"needed <strong>%2</strong>.<br/>" )
|
2020-05-21 23:13:28 +02:00
|
|
|
.arg( PartitionTable::tableTypeToName( tableType ) )
|
|
|
|
.arg( m_requiredPartitionTableType.join( " or " ) ) );
|
|
|
|
m_messageLabel->show();
|
|
|
|
|
|
|
|
cWarning() << "Partition table" << PartitionTable::tableTypeToName( tableType )
|
2020-10-12 14:27:01 +02:00
|
|
|
<< "does not match the requirement " << m_requiredPartitionTableType.join( " or " )
|
2020-10-17 16:41:08 +02:00
|
|
|
<< ", ENABLING erase feature and DISABLING alongside, replace and manual features.";
|
2020-05-21 23:13:28 +02:00
|
|
|
m_eraseButton->show();
|
|
|
|
m_alongsideButton->hide();
|
|
|
|
m_replaceButton->hide();
|
|
|
|
m_somethingElseButton->hide();
|
|
|
|
cDebug() << "Replace button suppressed because partition table type mismatch.";
|
|
|
|
force_uncheck( m_grp, m_replaceButton );
|
|
|
|
}
|
|
|
|
|
2020-10-12 14:27:01 +02:00
|
|
|
if ( m_somethingElseButton->isHidden() && m_alongsideButton->isHidden() && m_replaceButton->isHidden()
|
2020-10-22 19:19:28 +02:00
|
|
|
&& m_eraseButton->isHidden() )
|
2020-06-16 10:34:59 +02:00
|
|
|
{
|
2020-10-12 14:27:01 +02:00
|
|
|
if ( atLeastOneIsMounted )
|
|
|
|
{
|
2020-06-16 10:34:59 +02:00
|
|
|
m_messageLabel->setText( tr( "This storage device has one of its partitions <strong>mounted</strong>." ) );
|
2020-10-12 14:27:01 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_messageLabel->setText(
|
|
|
|
tr( "This storage device is a part of an <strong>inactive RAID</strong> device." ) );
|
|
|
|
}
|
2020-06-16 10:34:59 +02:00
|
|
|
|
|
|
|
m_messageLabel->show();
|
|
|
|
cWarning() << "No buttons available"
|
2020-10-12 14:27:01 +02:00
|
|
|
<< "replaced?" << atLeastOneCanBeReplaced << "resized?" << atLeastOneCanBeResized
|
2020-06-16 10:34:59 +02:00
|
|
|
<< "erased? (not-mounted and not-raid)" << !atLeastOneIsMounted << "and" << !isInactiveRAID;
|
|
|
|
}
|
2014-09-03 18:09:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-27 14:47:52 +01:00
|
|
|
OsproberEntryList
|
|
|
|
ChoicePage::getOsproberEntriesForDevice( Device* device ) const
|
|
|
|
{
|
|
|
|
OsproberEntryList eList;
|
2016-09-01 14:21:05 +02:00
|
|
|
for ( const OsproberEntry& entry : m_core->osproberEntries() )
|
2015-11-27 14:47:52 +01:00
|
|
|
{
|
|
|
|
if ( entry.path.startsWith( device->deviceNode() ) )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2015-11-27 14:47:52 +01:00
|
|
|
eList.append( entry );
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2015-11-27 14:47:52 +01:00
|
|
|
}
|
|
|
|
return eList;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-03 18:09:37 +02:00
|
|
|
bool
|
2015-04-15 12:20:01 +02:00
|
|
|
ChoicePage::isNextEnabled() const
|
2014-09-03 18:09:37 +02:00
|
|
|
{
|
|
|
|
return m_nextEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-29 13:59:06 +02:00
|
|
|
bool
|
|
|
|
ChoicePage::calculateNextEnabled() const
|
2014-09-03 18:09:37 +02:00
|
|
|
{
|
2016-04-22 16:02:07 +02:00
|
|
|
bool enabled = false;
|
2018-01-09 11:09:24 +01:00
|
|
|
auto sm_p = m_beforePartitionBarsView ? m_beforePartitionBarsView->selectionModel() : nullptr;
|
|
|
|
|
2020-09-29 14:00:49 +02:00
|
|
|
switch ( m_config->installChoice() )
|
2016-04-22 16:02:07 +02:00
|
|
|
{
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::NoChoice:
|
2020-07-29 13:59:06 +02:00
|
|
|
cDebug() << "No partitioning choice";
|
|
|
|
return false;
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Replace:
|
|
|
|
case InstallChoice::Alongside:
|
2020-07-29 13:59:06 +02:00
|
|
|
if ( !( sm_p && sm_p->currentIndex().isValid() ) )
|
|
|
|
{
|
|
|
|
cDebug() << "No partition selected";
|
|
|
|
return false;
|
|
|
|
}
|
2020-07-29 17:56:30 +02:00
|
|
|
enabled = true;
|
2016-04-22 16:02:07 +02:00
|
|
|
break;
|
2020-07-30 11:51:26 +02:00
|
|
|
case InstallChoice::Erase:
|
|
|
|
case InstallChoice::Manual:
|
2016-04-22 16:02:07 +02:00
|
|
|
enabled = true;
|
|
|
|
}
|
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
if ( !enabled )
|
2020-07-29 13:59:06 +02:00
|
|
|
{
|
|
|
|
cDebug() << "No valid choice made";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_isEfi
|
|
|
|
&& ( m_config->installChoice() == InstallChoice::Alongside
|
|
|
|
|| m_config->installChoice() == InstallChoice::Replace ) )
|
2016-04-22 16:02:07 +02:00
|
|
|
{
|
|
|
|
if ( m_core->efiSystemPartitions().count() == 0 )
|
2020-07-29 13:59:06 +02:00
|
|
|
{
|
|
|
|
cDebug() << "No EFI partition for alongside or replace";
|
|
|
|
return false;
|
|
|
|
}
|
2016-04-22 16:02:07 +02:00
|
|
|
}
|
|
|
|
|
2020-09-29 14:00:49 +02:00
|
|
|
if ( m_config->installChoice() != InstallChoice::Manual && m_encryptWidget->isVisible() )
|
2020-07-29 13:59:06 +02:00
|
|
|
{
|
|
|
|
switch ( m_encryptWidget->state() )
|
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
case EncryptWidget::Encryption::Unconfirmed:
|
|
|
|
cDebug() << "No passphrase provided";
|
|
|
|
return false;
|
|
|
|
case EncryptWidget::Encryption::Disabled:
|
|
|
|
case EncryptWidget::Encryption::Confirmed:
|
|
|
|
// Checkbox not checked, **or** passphrases match
|
|
|
|
break;
|
2020-07-29 13:59:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-04-22 16:02:07 +02:00
|
|
|
|
2020-07-29 13:59:06 +02:00
|
|
|
return true;
|
|
|
|
}
|
2014-09-03 18:09:37 +02:00
|
|
|
|
2020-07-29 13:59:06 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
ChoicePage::updateNextEnabled()
|
|
|
|
{
|
|
|
|
bool enabled = calculateNextEnabled();
|
|
|
|
|
|
|
|
if ( enabled != m_nextEnabled )
|
|
|
|
{
|
|
|
|
m_nextEnabled = enabled;
|
|
|
|
emit nextStatusChanged( enabled );
|
|
|
|
}
|
2014-09-03 18:09:37 +02:00
|
|
|
}
|
2014-09-19 16:27:39 +02:00
|
|
|
|
2018-09-12 17:18:17 +02:00
|
|
|
void
|
2020-08-22 01:19:58 +02:00
|
|
|
ChoicePage::updateSwapChoicesTr( QComboBox* box )
|
2018-09-12 17:18:17 +02:00
|
|
|
{
|
|
|
|
if ( !box )
|
2020-08-22 01:19:58 +02:00
|
|
|
{
|
2018-09-12 17:18:17 +02:00
|
|
|
return;
|
2020-08-22 01:19:58 +02:00
|
|
|
}
|
2018-09-12 17:18:17 +02:00
|
|
|
|
2020-08-22 01:19:58 +02:00
|
|
|
static_assert( SwapChoice::NoSwap == 0, "Enum values out-of-sync" );
|
2018-09-12 17:18:17 +02:00
|
|
|
for ( int index = 0; index < box->count(); ++index )
|
|
|
|
{
|
|
|
|
bool ok = false;
|
|
|
|
int value = 0;
|
|
|
|
|
|
|
|
switch ( value = box->itemData( index ).toInt( &ok ) )
|
|
|
|
{
|
2020-08-22 01:19:58 +02:00
|
|
|
// 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;
|
2018-09-12 17:18:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-10 16:28:05 +01:00
|
|
|
|
|
|
|
int
|
|
|
|
ChoicePage::lastSelectedDeviceIndex()
|
|
|
|
{
|
|
|
|
return m_lastSelectedDeviceIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChoicePage::setLastSelectedDeviceIndex( int index )
|
|
|
|
{
|
|
|
|
m_lastSelectedDeviceIndex = index;
|
|
|
|
m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex );
|
|
|
|
}
|