Compare commits
4 Commits
v3.3.7
...
partitionq
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cbeeb06e59 | ||
![]() |
dc7f91797c | ||
![]() |
abaf7630ad | ||
![]() |
a84783d5e2 |
@@ -335,6 +335,8 @@ PartitionCoreModule::doInit()
|
||||
{
|
||||
scanForEfiSystemPartitions();
|
||||
}
|
||||
|
||||
emit initCompleted();
|
||||
}
|
||||
|
||||
PartitionCoreModule::~PartitionCoreModule()
|
||||
|
@@ -51,6 +51,9 @@ class QStandardItemModel;
|
||||
class PartitionCoreModule : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QAbstractListModel* deviceModel READ deviceModel CONSTANT FINAL )
|
||||
Q_PROPERTY( QStandardItemModel* bootLoaderModel READ bootLoaderModel CONSTANT FINAL )
|
||||
|
||||
public:
|
||||
/**
|
||||
* This helper class calls refresh() on the module
|
||||
@@ -239,6 +242,7 @@ Q_SIGNALS:
|
||||
void isDirtyChanged( bool value );
|
||||
void reverted();
|
||||
void deviceReverted( Device* device );
|
||||
void initCompleted();
|
||||
|
||||
private:
|
||||
void refreshAfterModelChange();
|
||||
|
109
src/modules/partitionq/CMakeLists.txt
Normal file
109
src/modules/partitionq/CMakeLists.txt
Normal file
@@ -0,0 +1,109 @@
|
||||
# === This file is part of Calamares - <https://calamares.io> ===
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||
# SPDX-FileCopyrightText: 2022 Aditya Mehra <aix.m@outlook.com>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
if( NOT WITH_QML )
|
||||
calamares_skip_module( "partitionq (QML is not supported in this build)" )
|
||||
return()
|
||||
endif()
|
||||
|
||||
# When debugging the timezone widget, add this debugging definition
|
||||
# to have a debugging-friendly timezone widget, debug logging,
|
||||
# and no intrusive timezone-setting while clicking around.
|
||||
option( DEBUG_PARTITION_UNSAFE "Allow unsafe partitioning choices." OFF )
|
||||
option( DEBUG_PARTITION_BAIL_OUT "Unsafe partitioning will error out on exec." ON )
|
||||
option( DEBUG_PARTITION_SKIP "Don't actually do any partitioning." OFF)
|
||||
|
||||
include_directories( ${CMAKE_SOURCE_DIR} ) # for KPMCoreHelper
|
||||
|
||||
# This is very chatty, useful mostly if you don't know what KPMCore offers.
|
||||
option( DEBUG_FILESYSTEMS "Log all available Filesystems from KPMCore." OFF )
|
||||
|
||||
set( _partition_defs )
|
||||
if( DEBUG_PARTITION_UNSAFE )
|
||||
if( DEBUG_PARTITION_BAIL_OUT )
|
||||
list( APPEND _partition_defs DEBUG_PARTITION_BAIL_OUT )
|
||||
endif()
|
||||
list( APPEND _partition_defs DEBUG_PARTITION_UNSAFE )
|
||||
endif()
|
||||
if ( DEBUG_FILESYSTEMS )
|
||||
list( APPEND _partition_defs DEBUG_FILESYSTEMS )
|
||||
endif()
|
||||
if( DEBUG_PARTITION_SKIP )
|
||||
list( APPEND _partition_defs DEBUG_PARTITION_SKIP )
|
||||
endif()
|
||||
|
||||
find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE)
|
||||
|
||||
include( KPMcoreHelper )
|
||||
|
||||
find_package( KF5Config CONFIG )
|
||||
find_package( KF5I18n CONFIG )
|
||||
|
||||
if ( KPMcore_FOUND AND Qt5DBus_FOUND AND KF5CoreAddons_FOUND AND KF5Config_FOUND )
|
||||
list( APPEND _partition_defs ${KPMcore_API_DEFINITIONS} )
|
||||
include_directories( ${KPMCORE_INCLUDE_DIR} )
|
||||
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
|
||||
|
||||
# Because we're sharing sources with the regular partition module
|
||||
set( _partition ${CMAKE_CURRENT_SOURCE_DIR}/../partition )
|
||||
# set( _partitionCore ${CMAKE_CURRENT_SOURCE_DIR}/../partition/core )
|
||||
# set( _partitionJobs ${CMAKE_CURRENT_SOURCE_DIR}/../partition/jobs )
|
||||
|
||||
|
||||
include_directories( ${_partition} )
|
||||
|
||||
calamares_add_plugin( partitionq
|
||||
TYPE viewmodule
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
SOURCES
|
||||
PartitionQmlViewStep.cpp
|
||||
ChoicePageQml.cpp
|
||||
FlatPartitionModel.cpp
|
||||
${_partition}/Config.cpp
|
||||
${_partition}/core/PartUtils.cpp
|
||||
${_partition}/core/DeviceModel.cpp
|
||||
${_partition}/core/PartitionInfo.cpp
|
||||
${_partition}/core/PartitionCoreModule.cpp
|
||||
${_partition}/core/BootLoaderModel.cpp
|
||||
${_partition}/core/ColorUtils.cpp
|
||||
${_partition}/core/DeviceList.cpp
|
||||
${_partition}/core/KPMHelpers.cpp
|
||||
${_partition}/core/PartitionActions.cpp
|
||||
${_partition}/core/PartitionLayout.cpp
|
||||
${_partition}/core/PartitionModel.cpp
|
||||
${_partition}/jobs/AutoMountManagementJob.cpp
|
||||
${_partition}/jobs/ChangeFilesystemLabelJob.cpp
|
||||
${_partition}/jobs/ClearMountsJob.cpp
|
||||
${_partition}/jobs/ClearTempMountsJob.cpp
|
||||
${_partition}/jobs/CreatePartitionJob.cpp
|
||||
${_partition}/jobs/CreatePartitionTableJob.cpp
|
||||
${_partition}/jobs/CreateVolumeGroupJob.cpp
|
||||
${_partition}/jobs/DeactivateVolumeGroupJob.cpp
|
||||
${_partition}/jobs/DeletePartitionJob.cpp
|
||||
${_partition}/jobs/FillGlobalStorageJob.cpp
|
||||
${_partition}/jobs/FormatPartitionJob.cpp
|
||||
${_partition}/jobs/PartitionJob.cpp
|
||||
${_partition}/jobs/RemoveVolumeGroupJob.cpp
|
||||
${_partition}/jobs/ResizePartitionJob.cpp
|
||||
${_partition}/jobs/ResizeVolumeGroupJob.cpp
|
||||
${_partition}/jobs/SetPartitionFlagsJob.cpp
|
||||
|
||||
RESOURCES
|
||||
partitionq.qrc
|
||||
LINK_PRIVATE_LIBRARIES
|
||||
kpmcore
|
||||
KF5::CoreAddons
|
||||
COMPILE_DEFINITIONS ${_partition_defs}
|
||||
SHARED_LIB
|
||||
)
|
||||
|
||||
else()
|
||||
if ( NOT KPMcore_FOUND )
|
||||
calamares_skip_module( "partition (missing suitable KPMcore)" )
|
||||
else()
|
||||
calamares_skip_module( "partition (missing dependencies for KPMcore)" )
|
||||
endif()
|
||||
endif()
|
987
src/modules/partitionq/ChoicePageQml.cpp
Normal file
987
src/modules/partitionq/ChoicePageQml.cpp
Normal file
@@ -0,0 +1,987 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2014-2017 Teo Mrnjavac <teo@kde.org>
|
||||
* SPDX-FileCopyrightText: 2017-2019 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-FileCopyrightText: 2019 Collabora Ltd
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ChoicePageQml.h"
|
||||
#include "Config.h"
|
||||
#include "FlatPartitionModel.h"
|
||||
#include "core/BootLoaderModel.h"
|
||||
#include "core/DeviceModel.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/PartitionModel.h"
|
||||
|
||||
#include "Branding.h"
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "partition/PartitionIterator.h"
|
||||
#include "partition/PartitionQuery.h"
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
#include "utils/Units.h"
|
||||
|
||||
#include <kpmcore/core/device.h>
|
||||
#ifdef WITH_KPMCORE4API
|
||||
#include <kpmcore/core/softwareraid.h>
|
||||
#endif
|
||||
|
||||
#include <QFutureWatcher>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
using CalamaresUtils::Partition::findPartitionByPath;
|
||||
using CalamaresUtils::Partition::isPartitionFreeSpace;
|
||||
using CalamaresUtils::Partition::PartitionIterator;
|
||||
using InstallChoice = Config::InstallChoice;
|
||||
using SwapChoice = Config::SwapChoice;
|
||||
|
||||
/**
|
||||
* @brief ChoicePage::ChoicePage is the default constructor. Called on startup as part of
|
||||
* the module loading code path.
|
||||
* @param parent the QObject parent.
|
||||
*/
|
||||
ChoicePageQml::ChoicePageQml( Config* config, QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_config( config )
|
||||
, m_nextEnabled( false )
|
||||
, m_core( nullptr )
|
||||
, m_isEfi( false )
|
||||
, m_enableEncryptionWidget( true )
|
||||
, m_partitionModel( new PartitionModel( this ) )
|
||||
, m_partitionListModel( nullptr )
|
||||
{
|
||||
auto gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
m_enableEncryptionWidget = gs->value( "enableLuksAutomatedPartitioning" ).toBool();
|
||||
gs->insert( "reuseHome", false );
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::init( PartitionCoreModule* core )
|
||||
{
|
||||
m_core = core;
|
||||
m_isEfi = PartUtils::isEfiSystem();
|
||||
|
||||
ChoicePageQml::applyDeviceChoice();
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setDeviceIndex( int index )
|
||||
{
|
||||
m_deviceIndex = index;
|
||||
ChoicePageQml::applyDeviceChoice();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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*
|
||||
ChoicePageQml::selectedDevice()
|
||||
{
|
||||
Device* currentDevice = nullptr;
|
||||
currentDevice
|
||||
= m_core->deviceModel()->deviceForIndex( m_core->deviceModel()->index( m_deviceIndex ) );
|
||||
|
||||
return currentDevice;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setInstallChoice(int choice){
|
||||
if(choice == InstallChoiceType::EraseChoice){
|
||||
m_config->setInstallChoice( InstallChoice::Erase );
|
||||
} else if(choice == InstallChoiceType::ReplaceChoice){
|
||||
m_config->setInstallChoice( InstallChoice::Replace );
|
||||
} else if(choice == InstallChoiceType::AlongSideChoice){
|
||||
m_config->setInstallChoice( InstallChoice::Alongside );
|
||||
} else if(choice == InstallChoiceType::ManualChoice){
|
||||
m_config->setInstallChoice( InstallChoice::Manual );
|
||||
}
|
||||
|
||||
Device* currd = selectedDevice();
|
||||
if ( currd )
|
||||
{
|
||||
applyActionChoice( m_config->installChoice() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setPartitionModelForDevice()
|
||||
{
|
||||
Device* currd = selectedDevice();
|
||||
if ( !currd )
|
||||
{
|
||||
return;
|
||||
}
|
||||
OsproberEntryList osproberEntriesForCurrentDevice = getOsproberEntriesForDevice( currd );
|
||||
m_partitionModel->init(currd, osproberEntriesForCurrentDevice);
|
||||
}
|
||||
|
||||
PartitionModel*
|
||||
ChoicePageQml::partitionModel() const
|
||||
{
|
||||
return m_partitionModel;
|
||||
}
|
||||
|
||||
PartitionListModel*
|
||||
ChoicePageQml::partitionListModel() const
|
||||
{
|
||||
return m_partitionListModel;
|
||||
}
|
||||
|
||||
QVariantList
|
||||
ChoicePageQml::getEraseSwapChoices() const
|
||||
{
|
||||
auto choices = m_config->swapChoices();
|
||||
QVariantList qvChoices;
|
||||
QVariantMap qvChoice;
|
||||
|
||||
// Check which choices are supported by the current device
|
||||
for ( auto c : choices )
|
||||
{
|
||||
if ( c == SwapChoice::NoSwap )
|
||||
{
|
||||
qvChoice["label"] = tr( "No swap" );
|
||||
qvChoice["value"] = c;
|
||||
qvChoices.append( qvChoice );
|
||||
}
|
||||
if ( c == SwapChoice::ReuseSwap )
|
||||
{
|
||||
qvChoice["label"] = tr( "Reuse swap" );
|
||||
qvChoice["value"] = c;
|
||||
qvChoices.append( qvChoice );
|
||||
}
|
||||
if ( c == SwapChoice::SmallSwap )
|
||||
{
|
||||
qvChoice["label"] = tr( "Swap (no Hibernate)" );
|
||||
qvChoice["value"] = c;
|
||||
qvChoices.append( qvChoice );
|
||||
}
|
||||
if ( c == SwapChoice::FullSwap )
|
||||
{
|
||||
qvChoice["label"] = tr( "Swap (with Hibernate)" );
|
||||
qvChoice["value"] = c;
|
||||
qvChoices.append( qvChoice );
|
||||
}
|
||||
if ( c == SwapChoice::SwapFile )
|
||||
{
|
||||
qvChoice["label"] = tr( "Swap to file" );
|
||||
qvChoice["value"] = c;
|
||||
qvChoices.append( qvChoice );
|
||||
}
|
||||
}
|
||||
|
||||
// If no choices are supported, only offer the NoSwap and full swap choices
|
||||
// As done in the partition config
|
||||
if ( qvChoices.isEmpty() )
|
||||
{
|
||||
qvChoice["label"] = tr( "No swap" );
|
||||
qvChoice["value"] = SwapChoice::NoSwap;
|
||||
qvChoices.append( qvChoice );
|
||||
qvChoice["label"] = tr( "Swap (with Hibernate)" );
|
||||
qvChoice["value"] = SwapChoice::FullSwap;
|
||||
qvChoices.append( qvChoice );
|
||||
}
|
||||
|
||||
return qvChoices;
|
||||
}
|
||||
|
||||
int
|
||||
ChoicePageQml::getInitialSwapChoice() const
|
||||
{
|
||||
return m_config->initialSwapChoice();
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setSwapChoice(int selectedSwapChoice)
|
||||
{
|
||||
if ( selectedSwapChoice == SwapChoice::NoSwap ) {
|
||||
m_config->setSwapChoice( SwapChoice::NoSwap );
|
||||
} else if ( selectedSwapChoice == SwapChoice::ReuseSwap ) {
|
||||
m_config->setSwapChoice( SwapChoice::ReuseSwap );
|
||||
} else if ( selectedSwapChoice == SwapChoice::SmallSwap ) {
|
||||
m_config->setSwapChoice( SwapChoice::SmallSwap );
|
||||
} else if ( selectedSwapChoice == SwapChoice::FullSwap ) {
|
||||
m_config->setSwapChoice( SwapChoice::FullSwap );
|
||||
} else if ( selectedSwapChoice == SwapChoice::SwapFile ) {
|
||||
m_config->setSwapChoice( SwapChoice::SwapFile );
|
||||
}
|
||||
onActionChanged();
|
||||
}
|
||||
|
||||
bool
|
||||
ChoicePageQml::encryptWidgetEnabled() const
|
||||
{
|
||||
return m_enableEncryptionWidget;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setEncryptionSelected(bool enabled)
|
||||
{
|
||||
m_encryptionSelected = enabled;
|
||||
|
||||
if ( m_config->installChoice() == InstallChoice::Erase )
|
||||
{
|
||||
if (m_encryptionSelected)
|
||||
{
|
||||
applyActionChoice( m_config->installChoice() );
|
||||
}
|
||||
}
|
||||
updateNextEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setEncryptionPhrase(const QString& phrase)
|
||||
{
|
||||
m_encryptPassphrase = phrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
ChoicePageQml::applyDeviceChoice()
|
||||
{
|
||||
if ( !selectedDevice() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_core->isDirty() )
|
||||
{
|
||||
emit scanningDialogShow();
|
||||
QFuture<void> future =
|
||||
QtConcurrent::run(
|
||||
[ = ]
|
||||
{
|
||||
QMutexLocker locker( &m_coreMutex );
|
||||
m_core->revertAllDevices();
|
||||
} );
|
||||
// wait for the future to finish
|
||||
future.waitForFinished();
|
||||
emit scanningDialogHide();
|
||||
continueApplyDeviceChoice();
|
||||
}
|
||||
else
|
||||
{
|
||||
continueApplyDeviceChoice();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ChoicePageQml::continueApplyDeviceChoice()
|
||||
{
|
||||
Device* currd = selectedDevice();
|
||||
|
||||
// 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 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Preview setup done. Now we show/hide choices as needed.
|
||||
setupActions();
|
||||
|
||||
cDebug() << "Previous device" << m_lastSelectedDeviceIndex << "new device" << m_deviceIndex;
|
||||
if ( m_lastSelectedDeviceIndex != m_deviceIndex )
|
||||
{
|
||||
m_lastSelectedDeviceIndex = m_deviceIndex;
|
||||
m_lastSelectedActionIndex = -1;
|
||||
m_config->setInstallChoice( m_config->initialInstallChoice() );
|
||||
}
|
||||
|
||||
Q_EMIT actionChosen();
|
||||
Q_EMIT deviceChosen();
|
||||
}
|
||||
|
||||
void ChoicePageQml::setSelectedPartitionForAction(QModelIndex index)
|
||||
{
|
||||
// map the index from partition list to partition model
|
||||
QModelIndex mappedIndex = m_partitionListModel->mapToSource(index);
|
||||
Partition* partition = m_partitionModel->partitionForIndex(mappedIndex);
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::onActionChanged()
|
||||
{
|
||||
Device* currd = selectedDevice();
|
||||
if ( currd )
|
||||
{
|
||||
applyActionChoice( m_config->installChoice() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::applyActionChoice( InstallChoice choice )
|
||||
{
|
||||
cDebug() << "Prev" << m_lastSelectedActionIndex << "InstallChoice" << choice
|
||||
<< Config::installChoiceNames().find( choice );
|
||||
|
||||
switch ( choice )
|
||||
{
|
||||
case InstallChoice::Erase:
|
||||
{
|
||||
auto gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
PartitionActions::Choices::AutoPartitionOptions options { gs->value( "defaultPartitionTableType" ).toString(),
|
||||
m_config->eraseFsType(),
|
||||
m_encryptPassphrase,
|
||||
gs->value( "efiSystemPartition" ).toString(),
|
||||
CalamaresUtils::GiBtoBytes(
|
||||
gs->value( "requiredStorageGiB" ).toDouble() ),
|
||||
m_config->swapChoice() };
|
||||
|
||||
if ( m_core->isDirty() )
|
||||
{
|
||||
emit scanningDialogShow();
|
||||
QFuture<void> future = QtConcurrent::run(
|
||||
[ = ]
|
||||
{
|
||||
QMutexLocker locker( &m_coreMutex );
|
||||
m_core->revertDevice( selectedDevice() );
|
||||
} );
|
||||
// wait for the future to finish
|
||||
future.waitForFinished();
|
||||
updateNextEnabled();
|
||||
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
||||
Q_EMIT deviceChosen();
|
||||
emit scanningDialogHide();
|
||||
}
|
||||
else
|
||||
{
|
||||
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
||||
Q_EMIT deviceChosen();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InstallChoice::Replace:
|
||||
if ( m_core->isDirty() )
|
||||
{
|
||||
emit scanningDialogShow();
|
||||
QFuture<void> future =
|
||||
QtConcurrent::run(
|
||||
[ = ]
|
||||
{
|
||||
QMutexLocker locker( &m_coreMutex );
|
||||
m_core->revertDevice( selectedDevice() );
|
||||
} );
|
||||
// wait for the future to finish
|
||||
future.waitForFinished();
|
||||
emit scanningDialogHide();
|
||||
}
|
||||
break;
|
||||
|
||||
case InstallChoice::Alongside:
|
||||
if ( m_core->isDirty() )
|
||||
{
|
||||
emit scanningDialogShow();
|
||||
QFuture<void> future = QtConcurrent::run(
|
||||
[ = ]
|
||||
{
|
||||
QMutexLocker locker( &m_coreMutex );
|
||||
m_core->revertDevice( selectedDevice() );
|
||||
} );
|
||||
// wait for the future to finish
|
||||
future.waitForFinished();
|
||||
updateNextEnabled();
|
||||
emit scanningDialogHide();
|
||||
}
|
||||
break;
|
||||
case InstallChoice::NoChoice:
|
||||
case InstallChoice::Manual:
|
||||
break;
|
||||
}
|
||||
updateNextEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::onLeave()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ChoicePageQml::eraseButtonEnabled()
|
||||
{
|
||||
return m_eraseButtonEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setEraseButtonEnabled( bool enabled )
|
||||
{
|
||||
m_eraseButtonEnabled = enabled;
|
||||
emit eraseButtonEnabledChanged();
|
||||
}
|
||||
|
||||
bool
|
||||
ChoicePageQml::alongSideButtonEnabled()
|
||||
{
|
||||
return m_alongSideButtonEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setAlongSideButtonEnabled( bool enabled )
|
||||
{
|
||||
m_alongSideButtonEnabled = enabled;
|
||||
emit alongSideButtonEnabledChanged();
|
||||
}
|
||||
|
||||
bool
|
||||
ChoicePageQml::replaceButtonEnabled()
|
||||
{
|
||||
return m_replaceButtonEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setReplaceButtonEnabled( bool enabled )
|
||||
{
|
||||
m_replaceButtonEnabled = enabled;
|
||||
emit replaceButtonEnabledChanged();
|
||||
}
|
||||
|
||||
bool
|
||||
ChoicePageQml::manualButtonEnabled()
|
||||
{
|
||||
return m_somethingElseButtonEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setManualButtonEnabled( bool enabled )
|
||||
{
|
||||
m_somethingElseButtonEnabled = enabled;
|
||||
emit manualButtonEnabledChanged();
|
||||
}
|
||||
|
||||
QString
|
||||
ChoicePageQml::messageLabel() const
|
||||
{
|
||||
return m_messageLabel;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setMessageLabel( QString messageLabel )
|
||||
{
|
||||
m_messageLabel = messageLabel;
|
||||
emit messageLabelChanged();
|
||||
}
|
||||
|
||||
QString
|
||||
ChoicePageQml::eraseButtonLabel() const
|
||||
{
|
||||
return m_eraseButtonLabel;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setEraseButtonLabel( QString eraseButtonLabel )
|
||||
{
|
||||
m_eraseButtonLabel = eraseButtonLabel;
|
||||
emit eraseButtonLabelChanged();
|
||||
}
|
||||
|
||||
QString
|
||||
ChoicePageQml::alongSideButtonLabel() const
|
||||
{
|
||||
return m_alongSideButtonLabel;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setAlongSideButtonLabel( QString alongSideButtonLabel )
|
||||
{
|
||||
m_alongSideButtonLabel = alongSideButtonLabel;
|
||||
emit alongSideButtonLabelChanged();
|
||||
}
|
||||
|
||||
QString
|
||||
ChoicePageQml::replaceButtonLabel() const
|
||||
{
|
||||
return m_replaceButtonLabel;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setReplaceButtonLabel( QString replaceButtonLabel )
|
||||
{
|
||||
m_replaceButtonLabel = replaceButtonLabel;
|
||||
emit replaceButtonLabelChanged();
|
||||
}
|
||||
|
||||
QString
|
||||
ChoicePageQml::somethingElseButtonLabel() const
|
||||
{
|
||||
return m_somethingElseButtonLabel;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setSomethingElseButtonLabel( QString somethingElseButtonLabel )
|
||||
{
|
||||
m_somethingElseButtonLabel = somethingElseButtonLabel;
|
||||
emit somethingElseButtonLabelChanged();
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setupEfiSystemPartitionSelector()
|
||||
{
|
||||
Q_ASSERT( m_isEfi );
|
||||
|
||||
// Only the already existing ones:
|
||||
QList< Partition* > efiSystemPartitions = m_core->efiSystemPartitions();
|
||||
|
||||
if ( efiSystemPartitions.count() == 0 ) //should never happen
|
||||
{
|
||||
emit setEFIMessageLabel( 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() ) );
|
||||
updateNextEnabled();
|
||||
}
|
||||
else if ( efiSystemPartitions.count() == 1 ) //probably most usual situation
|
||||
{
|
||||
emit setEFIMessageLabel( tr( "The EFI system partition at %1 will be used for "
|
||||
"starting %2." )
|
||||
.arg( efiSystemPartitions.first()->partitionPath() )
|
||||
.arg( Calamares::Branding::instance()->shortProductName() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
//m_efiComboBox->show();
|
||||
emit setEFIMessageLabel( 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
|
||||
if ( efiPartition->devicePath() == selectedDevice()->deviceNode() && efiPartition->number() == 1 )
|
||||
{
|
||||
qDebug() << "ToDo: set it in qml";
|
||||
//m_efiComboBox->setCurrentIndex( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline QDebug&
|
||||
operator<<( QDebug& s, PartitionIterator& it )
|
||||
{
|
||||
s << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
|
||||
return s;
|
||||
}
|
||||
|
||||
QString
|
||||
describePartitionTypes( const QStringList& types )
|
||||
{
|
||||
if ( types.empty() )
|
||||
{
|
||||
return QCoreApplication::translate(
|
||||
ChoicePageQml::staticMetaObject.className(), "any", "any partition-table type" );
|
||||
}
|
||||
if ( types.size() == 1 )
|
||||
{
|
||||
return types.first();
|
||||
}
|
||||
if ( types.size() == 2 )
|
||||
{
|
||||
return QCoreApplication::translate(
|
||||
ChoicePageQml::staticMetaObject.className(), "%1 or %2", "partition-table types" )
|
||||
.arg( types.at( 0 ), types.at( 1 ) );
|
||||
}
|
||||
// More than two, rather unlikely
|
||||
return types.join( ", " );
|
||||
}
|
||||
|
||||
QString
|
||||
ChoicePageQml::getCurrentDevicePartitionType() const
|
||||
{
|
||||
return m_currentDevicePartitionTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
void
|
||||
ChoicePageQml::setupActions()
|
||||
{
|
||||
Logger::Once o;
|
||||
|
||||
m_partitionListModel = new PartitionListModel(m_partitionModel, this);
|
||||
emit partitionListModelInitialized();
|
||||
|
||||
Device* currentDevice = selectedDevice();
|
||||
OsproberEntryList osproberEntriesForCurrentDevice = getOsproberEntriesForDevice( currentDevice );
|
||||
|
||||
cDebug() << o << "Setting up actions for" << currentDevice->deviceNode() << "with"
|
||||
<< osproberEntriesForCurrentDevice.count() << "entries.";
|
||||
|
||||
if ( currentDevice->partitionTable() )
|
||||
{
|
||||
m_currentDevicePartitionType = currentDevice->partitionTable()->type();
|
||||
m_currentDevicePartitionTypeName = currentDevice->partitionTable()->typeName();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentDevicePartitionType = PartitionTable::unknownTableType;
|
||||
m_currentDevicePartitionTypeName = currentDevice->partitionTable()->typeName();
|
||||
}
|
||||
|
||||
if ( m_config->allowManualPartitioning() )
|
||||
{
|
||||
setManualButtonEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
setManualButtonEnabled(false);
|
||||
}
|
||||
|
||||
bool atLeastOneCanBeResized = false;
|
||||
bool atLeastOneCanBeReplaced = false;
|
||||
bool atLeastOneIsMounted = false; // Suppress 'erase' if so
|
||||
bool isInactiveRAID = false;
|
||||
bool matchTableType = false;
|
||||
|
||||
#ifdef WITH_KPMCORE4API
|
||||
if ( currentDevice->type() == Device::Type::SoftwareRAID_Device
|
||||
&& static_cast< SoftwareRAID* >( currentDevice )->status() == SoftwareRAID::Status::Inactive )
|
||||
{
|
||||
cDebug() << Logger::SubEntry << "part of an inactive RAID device";
|
||||
isInactiveRAID = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
PartitionTable::TableType tableType = PartitionTable::unknownTableType;
|
||||
if ( currentDevice->partitionTable() )
|
||||
{
|
||||
tableType = currentDevice->partitionTable()->type();
|
||||
matchTableType = m_config->acceptPartitionTableType( tableType );
|
||||
}
|
||||
|
||||
for ( auto it = PartitionIterator::begin( currentDevice ); it != PartitionIterator::end( currentDevice ); ++it )
|
||||
{
|
||||
if ( PartUtils::canBeResized( *it, o ) )
|
||||
{
|
||||
cDebug() << Logger::SubEntry << "contains resizable" << it;
|
||||
atLeastOneCanBeResized = true;
|
||||
}
|
||||
if ( PartUtils::canBeReplaced( *it, o ) )
|
||||
{
|
||||
cDebug() << Logger::SubEntry << "contains replaceable" << it;
|
||||
atLeastOneCanBeReplaced = true;
|
||||
}
|
||||
if ( ( *it )->isMounted() )
|
||||
{
|
||||
atLeastOneIsMounted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( osproberEntriesForCurrentDevice.count() == 0 )
|
||||
{
|
||||
CALAMARES_RETRANSLATE(
|
||||
cDebug() << "Setting texts for 0 osprober entries";
|
||||
setMessageLabel(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 "
|
||||
"before any change is made to the storage device." ));
|
||||
|
||||
setEraseButtonLabel(tr( "<strong>Erase disk</strong><br/>"
|
||||
"This will <font color=\"red\">delete</font> all data "
|
||||
"currently present on the selected storage device." ));
|
||||
|
||||
setAlongSideButtonLabel(tr( "<strong>Install alongside</strong><br/>"
|
||||
"The installer will shrink a partition to make room for %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
|
||||
setReplaceButtonLabel(tr( "<strong>Replace a partition</strong><br/>"
|
||||
"Replaces a partition with %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
);
|
||||
emit labelsUpdated();
|
||||
setReplaceButtonEnabled(false);
|
||||
setAlongSideButtonEnabled(false);
|
||||
}
|
||||
else if ( osproberEntriesForCurrentDevice.count() == 1 )
|
||||
{
|
||||
QString osName = osproberEntriesForCurrentDevice.first().prettyName;
|
||||
|
||||
if ( !osName.isEmpty() )
|
||||
{
|
||||
CALAMARES_RETRANSLATE (
|
||||
cDebug() << "Setting texts for 1 non-empty osprober entry";
|
||||
setMessageLabel(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 "
|
||||
"before any change is made to the storage device." )
|
||||
.arg( osName ));
|
||||
|
||||
setAlongSideButtonLabel(tr( "<strong>Install alongside</strong><br/>"
|
||||
"The installer will shrink a partition to make room for %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
|
||||
setEraseButtonLabel(tr( "<strong>Erase disk</strong><br/>"
|
||||
"This will <font color=\"red\">delete</font> all data "
|
||||
"currently present on the selected storage device." ));
|
||||
|
||||
|
||||
setReplaceButtonLabel(tr( "<strong>Replace a partition</strong><br/>"
|
||||
"Replaces a partition with %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
);
|
||||
emit labelsUpdated();
|
||||
}
|
||||
else
|
||||
{
|
||||
CALAMARES_RETRANSLATE(
|
||||
cDebug() << "Setting texts for 1 empty osprober entry";
|
||||
setMessageLabel(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 "
|
||||
"before any change is made to the storage device." ));
|
||||
|
||||
setAlongSideButtonLabel(tr( "<strong>Install alongside</strong><br/>"
|
||||
"The installer will shrink a partition to make room for %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
|
||||
setEraseButtonLabel(tr( "<strong>Erase disk</strong><br/>"
|
||||
"This will <font color=\"red\">delete</font> all data "
|
||||
"currently present on the selected storage device." ));
|
||||
|
||||
setReplaceButtonLabel(tr( "<strong>Replace a partition</strong><br/>"
|
||||
"Replaces a partition with %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
);
|
||||
emit labelsUpdated();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// osproberEntriesForCurrentDevice has at least 2 items.
|
||||
|
||||
CALAMARES_RETRANSLATE(
|
||||
cDebug() << "Setting texts for >= 2 osprober entries";
|
||||
|
||||
setMessageLabel(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 "
|
||||
"before any change is made to the storage device." ));
|
||||
|
||||
setAlongSideButtonLabel(tr( "<strong>Install alongside</strong><br/>"
|
||||
"The installer will shrink a partition to make room for %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
|
||||
setEraseButtonLabel(tr( "<strong>Erase disk</strong><br/>"
|
||||
"This will <font color=\"red\">delete</font> all data "
|
||||
"currently present on the selected storage device." ));
|
||||
|
||||
setReplaceButtonLabel(tr( "<strong>Replace a partition</strong><br/>"
|
||||
"Replaces a partition with %1." )
|
||||
.arg( Calamares::Branding::instance()->shortVersionedName() ));
|
||||
);
|
||||
emit labelsUpdated();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PARTITION_UNSAFE
|
||||
#ifdef DEBUG_PARTITION_BAIL_OUT
|
||||
// If things can't be broken, allow all the buttons
|
||||
atLeastOneCanBeReplaced = true;
|
||||
atLeastOneCanBeResized = true;
|
||||
atLeastOneIsMounted = false;
|
||||
isInactiveRAID = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ( atLeastOneCanBeReplaced )
|
||||
{
|
||||
setReplaceButtonEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "No partitions available for replace-action.";
|
||||
setReplaceButtonEnabled(false);
|
||||
}
|
||||
|
||||
if ( atLeastOneCanBeResized )
|
||||
{
|
||||
setAlongSideButtonEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "No partitions available for resize-action.";
|
||||
setAlongSideButtonEnabled(false);
|
||||
}
|
||||
|
||||
if ( !atLeastOneIsMounted && !isInactiveRAID )
|
||||
{
|
||||
setEraseButtonEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "No partitions ("
|
||||
<< "any-mounted?" << atLeastOneIsMounted << "is-raid?" << isInactiveRAID << ") for erase-action.";
|
||||
setEraseButtonEnabled(false);
|
||||
}
|
||||
|
||||
bool isEfi = PartUtils::isEfiSystem();
|
||||
bool efiSystemPartitionFound = !m_core->efiSystemPartitions().isEmpty();
|
||||
|
||||
if ( isEfi && !efiSystemPartitionFound )
|
||||
{
|
||||
cWarning() << "System is EFI but there's no EFI system partition, "
|
||||
"DISABLING alongside and replace features.";
|
||||
setAlongSideButtonEnabled(false);
|
||||
setReplaceButtonEnabled(false);
|
||||
}
|
||||
|
||||
if ( tableType != PartitionTable::unknownTableType && !matchTableType )
|
||||
{
|
||||
setMessageLabel(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/>" )
|
||||
.arg( PartitionTable::tableTypeToName( tableType ) )
|
||||
.arg( describePartitionTypes( m_config->partitionTableTypes() ) ) );
|
||||
|
||||
cWarning() << "Partition table" << PartitionTable::tableTypeToName( tableType )
|
||||
<< "does not match the requirement " << m_config->partitionTableTypes().join( ',' )
|
||||
<< ", ENABLING erase feature and DISABLING alongside, replace and manual features.";
|
||||
setEraseButtonEnabled(true);
|
||||
setAlongSideButtonEnabled(false);
|
||||
setReplaceButtonEnabled(false);
|
||||
setManualButtonEnabled(false);
|
||||
cDebug() << "Replace button suppressed because partition table type mismatch.";
|
||||
}
|
||||
|
||||
if ( !m_somethingElseButtonEnabled && !m_alongSideButtonEnabled && !m_replaceButtonEnabled
|
||||
&& !m_eraseButtonEnabled)
|
||||
{
|
||||
if ( atLeastOneIsMounted )
|
||||
{
|
||||
setMessageLabel( tr( "This storage device has one of its partitions <strong>mounted</strong>." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
setMessageLabel(
|
||||
tr( "This storage device is a part of an <strong>inactive RAID</strong> device." ) );
|
||||
}
|
||||
|
||||
cWarning() << "No buttons available"
|
||||
<< "replaced?" << atLeastOneCanBeReplaced << "resized?" << atLeastOneCanBeResized
|
||||
<< "erased? (not-mounted and not-raid)" << !atLeastOneIsMounted << "and" << !isInactiveRAID;
|
||||
}
|
||||
|
||||
if ( m_somethingElseButtonEnabled )
|
||||
{
|
||||
setSomethingElseButtonLabel(tr( "<strong>Manual partitioning</strong><br/>"
|
||||
"You can create or resize partitions yourself." ));
|
||||
}
|
||||
emit labelsUpdated();
|
||||
|
||||
// Set Partition Model Here
|
||||
ChoicePageQml::setPartitionModelForDevice();
|
||||
}
|
||||
|
||||
|
||||
OsproberEntryList
|
||||
ChoicePageQml::getOsproberEntriesForDevice( Device* device ) const
|
||||
{
|
||||
OsproberEntryList eList;
|
||||
for ( const OsproberEntry& entry : m_core->osproberEntries() )
|
||||
{
|
||||
if ( entry.path.startsWith( device->deviceNode() ) )
|
||||
{
|
||||
eList.append( entry );
|
||||
}
|
||||
}
|
||||
return eList;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ChoicePageQml::isNextEnabled() const
|
||||
{
|
||||
return m_nextEnabled;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ChoicePageQml::calculateNextEnabled() const
|
||||
{
|
||||
bool enabled = false;
|
||||
switch ( m_config->installChoice() )
|
||||
{
|
||||
case InstallChoice::NoChoice:
|
||||
cDebug() << "No partitioning choice";
|
||||
return false;
|
||||
case InstallChoice::Replace:
|
||||
case InstallChoice::Alongside:
|
||||
enabled = true;
|
||||
break;
|
||||
case InstallChoice::Erase:
|
||||
case InstallChoice::Manual:
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
if ( !enabled )
|
||||
{
|
||||
cDebug() << "No valid choice made";
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_isEfi
|
||||
&& ( m_config->installChoice() == InstallChoice::Alongside
|
||||
|| m_config->installChoice() == InstallChoice::Replace ) )
|
||||
{
|
||||
if ( m_core->efiSystemPartitions().count() == 0 )
|
||||
{
|
||||
cDebug() << "No EFI partition for alongside or replace";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_config->installChoice() == InstallChoice::Manual)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ChoicePageQml::updateNextEnabled()
|
||||
{
|
||||
bool enabled = calculateNextEnabled();
|
||||
|
||||
if ( enabled != m_nextEnabled )
|
||||
{
|
||||
m_nextEnabled = enabled;
|
||||
Q_EMIT nextStatusChanged( enabled );
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ChoicePageQml::lastSelectedDeviceIndex()
|
||||
{
|
||||
return m_lastSelectedDeviceIndex;
|
||||
}
|
||||
|
||||
void
|
||||
ChoicePageQml::setLastSelectedDeviceIndex( int index )
|
||||
{
|
||||
m_lastSelectedDeviceIndex = index;
|
||||
}
|
214
src/modules/partitionq/ChoicePageQml.h
Normal file
214
src/modules/partitionq/ChoicePageQml.h
Normal file
@@ -0,0 +1,214 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
* SPDX-FileCopyrightText: 2014-2016 Teo Mrnjavac <teo@kde.org>
|
||||
* SPDX-FileCopyrightText: 2014-2016 Teo Mrnjavac <teo@kde.org>
|
||||
* SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-FileCopyrightText: 2019 Collabora Ltd
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHOICEPAGEQML_H
|
||||
#define CHOICEPAGEQML_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include "Config.h"
|
||||
#include "core/OsproberEntry.h"
|
||||
#include "FlatPartitionModel.h"
|
||||
|
||||
namespace Calamares
|
||||
{
|
||||
}
|
||||
|
||||
class Config;
|
||||
class PartitionCoreModule;
|
||||
class PartitionSplitterWidget;
|
||||
class PartitionModel;
|
||||
class Device;
|
||||
|
||||
using SwapChoiceSet = Config::SwapChoiceSet;
|
||||
|
||||
/**
|
||||
* @brief The ChoicePage class is the first page of the partitioning interface.
|
||||
* It offers a choice between partitioning operations and initiates all automated
|
||||
* partitioning modes. For manual partitioning, see PartitionPage.
|
||||
*/
|
||||
class ChoicePageQml : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(InstallChoiceType)
|
||||
|
||||
Q_PROPERTY( bool eraseButtonEnabled READ eraseButtonEnabled WRITE setEraseButtonEnabled NOTIFY eraseButtonEnabledChanged )
|
||||
Q_PROPERTY( bool alongSideButtonEnabled READ alongSideButtonEnabled WRITE setAlongSideButtonEnabled NOTIFY alongSideButtonEnabledChanged )
|
||||
Q_PROPERTY( bool replaceButtonEnabled READ replaceButtonEnabled WRITE setReplaceButtonEnabled NOTIFY replaceButtonEnabledChanged )
|
||||
Q_PROPERTY( bool manualButtonEnabled READ manualButtonEnabled WRITE setManualButtonEnabled NOTIFY manualButtonEnabledChanged )
|
||||
|
||||
Q_PROPERTY( QString messageLabel READ messageLabel WRITE setMessageLabel NOTIFY messageLabelChanged )
|
||||
Q_PROPERTY( QString eraseButtonLabel READ eraseButtonLabel WRITE setEraseButtonLabel NOTIFY eraseButtonLabelChanged )
|
||||
Q_PROPERTY( QString alongSideButtonLabel READ alongSideButtonLabel WRITE setAlongSideButtonLabel NOTIFY alongSideButtonLabelChanged )
|
||||
Q_PROPERTY( QString replaceButtonLabel READ replaceButtonLabel WRITE setReplaceButtonLabel NOTIFY replaceButtonLabelChanged )
|
||||
Q_PROPERTY( QString somethingElseButtonLabel READ somethingElseButtonLabel WRITE setSomethingElseButtonLabel NOTIFY somethingElseButtonLabelChanged )
|
||||
|
||||
Q_PROPERTY( QAbstractItemModel* partitionModel READ partitionModel CONSTANT FINAL )
|
||||
Q_PROPERTY( QAbstractListModel* partitionListModel READ partitionListModel CONSTANT FINAL )
|
||||
|
||||
public:
|
||||
explicit ChoicePageQml( Config* config, QObject* parent = nullptr );
|
||||
|
||||
enum InstallChoiceType
|
||||
{
|
||||
EraseChoice,
|
||||
AlongSideChoice,
|
||||
ReplaceChoice,
|
||||
ManualChoice
|
||||
};
|
||||
Q_ENUMS(InstallChoiceType)
|
||||
|
||||
/**
|
||||
* @brief init runs when the PartitionViewStep and the PartitionCoreModule are
|
||||
* ready. Sets up the rest of the UI based on os-prober output.
|
||||
* @param core the PartitionCoreModule pointer.
|
||||
*/
|
||||
void init( PartitionCoreModule* core );
|
||||
|
||||
/**
|
||||
* @brief isNextEnabled answers whether the current state of the page is such
|
||||
* that progressing to the next page should be allowed.
|
||||
* @return true if next is allowed, otherwise false.
|
||||
*/
|
||||
bool isNextEnabled() const;
|
||||
|
||||
/**
|
||||
* @brief onLeave runs when control passes from this page to another one.
|
||||
*/
|
||||
void onLeave();
|
||||
|
||||
/**
|
||||
* @brief applyActionChoice reacts to a choice of partitioning mode.
|
||||
* @param choice the partitioning action choice.
|
||||
*/
|
||||
void applyActionChoice( Config::InstallChoice choice );
|
||||
|
||||
int lastSelectedDeviceIndex();
|
||||
void setLastSelectedDeviceIndex( int index );
|
||||
|
||||
void onActionChanged();
|
||||
|
||||
bool eraseButtonEnabled();
|
||||
bool alongSideButtonEnabled();
|
||||
bool replaceButtonEnabled();
|
||||
bool manualButtonEnabled();
|
||||
|
||||
void setEraseButtonEnabled( bool eraseButtonEnabled );
|
||||
void setAlongSideButtonEnabled( bool alongSideButtonEnabled );
|
||||
void setReplaceButtonEnabled( bool replaceButtonEnabled );
|
||||
void setManualButtonEnabled( bool manualButtonEnabled );
|
||||
|
||||
QString messageLabel() const;
|
||||
QString eraseButtonLabel() const;
|
||||
QString alongSideButtonLabel() const;
|
||||
QString replaceButtonLabel() const;
|
||||
QString somethingElseButtonLabel() const;
|
||||
|
||||
void setMessageLabel( QString messageLabel );
|
||||
void setEraseButtonLabel( QString eraseButtonLabel );
|
||||
void setAlongSideButtonLabel( QString alongSideButtonLabel );
|
||||
void setReplaceButtonLabel( QString replaceButtonLabel );
|
||||
void setSomethingElseButtonLabel( QString somethingElseButtonLabel );
|
||||
|
||||
PartitionModel* partitionModel() const;
|
||||
PartitionListModel* partitionListModel() const;
|
||||
void setPartitionModelForDevice();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setDeviceIndex(int index);
|
||||
void setupActions();
|
||||
QString getCurrentDevicePartitionType() const;
|
||||
void setInstallChoice(int installChoice);
|
||||
QVariantList getEraseSwapChoices() const;
|
||||
int getInitialSwapChoice() const;
|
||||
void setSwapChoice(int selectedSwapChoice);
|
||||
bool encryptWidgetEnabled() const;
|
||||
void setEncryptionSelected(bool enabled);
|
||||
void setEncryptionPhrase(const QString& phrase);
|
||||
void setSelectedPartitionForAction(QModelIndex index);
|
||||
|
||||
Q_SIGNALS:
|
||||
void partitionListModelInitialized();
|
||||
void labelsUpdated();
|
||||
void setEFIMessageLabel( const QString& message );
|
||||
void scanningDialogShow();
|
||||
void scanningDialogHide();
|
||||
|
||||
void eraseButtonEnabledChanged();
|
||||
void alongSideButtonEnabledChanged();
|
||||
void replaceButtonEnabledChanged();
|
||||
void manualButtonEnabledChanged();
|
||||
|
||||
void messageLabelChanged();
|
||||
void eraseButtonLabelChanged();
|
||||
void alongSideButtonLabelChanged();
|
||||
void replaceButtonLabelChanged();
|
||||
void somethingElseButtonLabelChanged();
|
||||
|
||||
signals:
|
||||
void nextStatusChanged( bool );
|
||||
void actionChosen();
|
||||
void deviceChosen();
|
||||
|
||||
private:
|
||||
bool calculateNextEnabled() const;
|
||||
void updateNextEnabled();
|
||||
Device* selectedDevice();
|
||||
|
||||
void applyDeviceChoice(); // Start scanning new device
|
||||
void continueApplyDeviceChoice(); // .. called after scan
|
||||
|
||||
OsproberEntryList getOsproberEntriesForDevice( Device* device ) const;
|
||||
void setupEfiSystemPartitionSelector();
|
||||
|
||||
Config* m_config;
|
||||
bool m_nextEnabled;
|
||||
PartitionCoreModule* m_core;
|
||||
PartitionModel* m_partitionModel;
|
||||
PartitionListModel* m_partitionListModel;
|
||||
|
||||
QMutex m_previewsMutex;
|
||||
|
||||
bool m_isEfi;
|
||||
|
||||
int m_lastSelectedDeviceIndex = -1;
|
||||
int m_lastSelectedActionIndex = -1;
|
||||
|
||||
bool m_enableEncryptionWidget;
|
||||
bool m_encryptionSelected;
|
||||
|
||||
bool m_alongSideButtonEnabled;
|
||||
bool m_eraseButtonEnabled;
|
||||
bool m_replaceButtonEnabled;
|
||||
bool m_somethingElseButtonEnabled;
|
||||
|
||||
int m_selectedDeviceIndex = -1;
|
||||
int m_deviceIndex = -1;
|
||||
|
||||
QString m_messageLabel;
|
||||
QString m_eraseButtonLabel;
|
||||
QString m_alongSideButtonLabel;
|
||||
QString m_replaceButtonLabel;
|
||||
QString m_somethingElseButtonLabel;
|
||||
|
||||
QPointer< PartitionSplitterWidget > m_afterPartitionSplitterWidget;
|
||||
|
||||
QString m_currentDevicePartitionType;
|
||||
QString m_currentDevicePartitionTypeName;
|
||||
|
||||
QString m_encryptPassphrase;
|
||||
|
||||
QMutex m_coreMutex;
|
||||
};
|
||||
|
||||
#endif // CHOICEPAGEQML_H
|
310
src/modules/partitionq/ChoosePage.qml
Normal file
310
src/modules/partitionq/ChoosePage.qml
Normal file
@@ -0,0 +1,310 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
import io.calamares.core 1.0
|
||||
import io.calamares.ui 1.0
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls 1.4 as QQC1
|
||||
import QtQuick.Window 2.14
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import org.kde.kirigami 2.7 as Kirigami
|
||||
|
||||
Item {
|
||||
width: partitionPage.width
|
||||
height: partitionPage.height
|
||||
|
||||
function listProperty(item)
|
||||
{
|
||||
for (var p in item)
|
||||
console.log(p + ": " + item[p]);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: choicePage
|
||||
onPartitionListModelInitialized: {
|
||||
// Need to wait for partition model to initialize
|
||||
// followed by partitionListModel
|
||||
// Requires further refactor to have partitionListModel ready
|
||||
// when choicePage is loaded instead of waiting for choicePage
|
||||
// to load partitionModel first.
|
||||
partitionView.model = choicePage.partitionListModel
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: headerRowLayout
|
||||
anchors.top: parent.top
|
||||
width: parent.width
|
||||
height: Kirigami.Units.gridUnits * 2
|
||||
|
||||
Item {
|
||||
id: partitionTypeBox
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 5
|
||||
Layout.fillHeight: true
|
||||
|
||||
Item {
|
||||
id: partitionTypeIcon
|
||||
anchors.left: parent.left
|
||||
width: parent.width * 0.35
|
||||
height: parent.height
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: Kirigami.Units.iconSizes.large
|
||||
height: width
|
||||
source: "images/partition-table.svg"
|
||||
}
|
||||
}
|
||||
Label {
|
||||
id: partitionTypeLabel
|
||||
anchors.left: partitionTypeIcon.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 1
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Select Storage Device:"
|
||||
font.bold: true
|
||||
Layout.fillHeight: true
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
horizontalAlignment: Qt.AlignLeft
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: deviceComboBox
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: core.deviceModel
|
||||
textRole: "display"
|
||||
currentIndex: core.currentDeviceIndex
|
||||
onCurrentIndexChanged: {
|
||||
core.currentDeviceIndex = currentIndex
|
||||
choicePage.setDeviceIndex(currentIndex)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
choicePage.setupActions()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 5
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
id: headerBoxLine
|
||||
anchors.top: headerRowLayout.bottom
|
||||
width: parent.width
|
||||
height: 1
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.top: headerBoxLine.bottom
|
||||
anchors.bottom: bottomSelectionBoxLine.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
id: eraseBtn
|
||||
objectName: "eraseBtn"
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: choicePage.eraseButtonEnabled
|
||||
enabled: choicePage.eraseButtonEnabled
|
||||
ButtonGroup.group: buttonGroup
|
||||
text: choicePage.eraseButtonLabel;
|
||||
onClicked: {
|
||||
choicePage.setInstallChoice(0)
|
||||
}
|
||||
}
|
||||
RadioButton {
|
||||
id: alongSideBtn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: choicePage.alongSideButtonEnabled
|
||||
enabled: choicePage.alongSideButtonEnabled
|
||||
ButtonGroup.group: buttonGroup
|
||||
text: choicePage.alongSideButtonLabel;
|
||||
onClicked: {
|
||||
choicePage.setInstallChoice(1)
|
||||
}
|
||||
}
|
||||
RadioButton {
|
||||
id: replaceBtn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: choicePage.replaceButtonEnabled
|
||||
enabled: choicePage.replaceButtonEnabled
|
||||
ButtonGroup.group: buttonGroup
|
||||
text: choicePage.replaceButtonLabel;
|
||||
onClicked: {
|
||||
choicePage.setInstallChoice(2)
|
||||
}
|
||||
}
|
||||
RadioButton {
|
||||
id: manualBtn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: choicePage.manualButtonEnabled
|
||||
enabled: choicePage.manualButtonEnabled
|
||||
ButtonGroup.group: buttonGroup
|
||||
text: choicePage.somethingElseButtonLabel;
|
||||
onClicked: {
|
||||
choicePage.setInstallChoice(3)
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: partitionViewLayout
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnits * 3
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Repeater {
|
||||
id: partitionView
|
||||
|
||||
delegate: Item {
|
||||
id: partitionItem
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 4
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 1.5
|
||||
|
||||
color: model.decoration
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: model.display
|
||||
fontSizeMode: Text.Fit
|
||||
font.pixelSize: parent.height * 0.25
|
||||
minimumPixelSize: 8
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
listProperty(model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
fontSizeMode: Text.Fit
|
||||
font.pixelSize: parent.height * 0.25
|
||||
minimumPixelSize: 8
|
||||
color: Kirigami.Theme.textColor
|
||||
text: model.toolTip.replace(" ", "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onCountChanged: {
|
||||
partitionView.forceLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToDo: Partitioning Tree View Before and After View
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
id: bottomSelectionBoxLine
|
||||
anchors.bottom: selectionBoxes.top
|
||||
width: parent.width
|
||||
height: 1
|
||||
visible: selectionBoxes.visible
|
||||
}
|
||||
|
||||
Item {
|
||||
id: selectionBoxes
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.height * 0.2
|
||||
visible: eraseBtn.checked || replaceBtn.checked || alongSideBtn.checked
|
||||
|
||||
ColumnLayout {
|
||||
id: selectionBoxesLayout
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
ComboBox {
|
||||
id: eraseSwapComboBox
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
model: choicePage.getEraseSwapChoices()
|
||||
textRole: "label"
|
||||
currentIndex: choicePage.getInitialSwapChoice()
|
||||
onCurrentIndexChanged: {
|
||||
choicePage.setSwapChoice(currentIndex)
|
||||
}
|
||||
visible: eraseBtn.checked
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
id: encryptPartitionButton
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: "Encrypt Partition"
|
||||
onClicked: {
|
||||
if (encryptPartitionButton.checked) {
|
||||
choicePage.setEncryptionSelected(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: encryptionPasswordField
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: encryptPartitionButton.checked
|
||||
onTextChanged: {
|
||||
choicePage.setEncryptionPhrase(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
72
src/modules/partitionq/FlatPartitionModel.cpp
Normal file
72
src/modules/partitionq/FlatPartitionModel.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "FlatPartitionModel.h"
|
||||
#include "core/PartitionModel.h"
|
||||
|
||||
PartitionListModel::PartitionListModel( PartitionModel* model, QObject* parent )
|
||||
: QAbstractListModel( parent )
|
||||
, m_model( model )
|
||||
{
|
||||
connect( m_model, &PartitionModel::rowsInserted, this, &PartitionListModel::rowsInserted );
|
||||
connect( m_model, &PartitionModel::rowsRemoved, this, &PartitionListModel::rowsRemoved );
|
||||
connect( m_model, &PartitionModel::dataChanged, this, &PartitionListModel::dataChanged );
|
||||
}
|
||||
|
||||
int PartitionListModel::rowCount( const QModelIndex& parent ) const
|
||||
{
|
||||
return m_model->rowCount( parent );
|
||||
}
|
||||
|
||||
QHash< int, QByteArray > PartitionListModel::roleNames() const
|
||||
{
|
||||
QHash< int, QByteArray > roles = m_model->roleNames();
|
||||
roles.insert( Qt::UserRole + 1, "size" );
|
||||
roles.insert( Qt::UserRole + 2, "partitionData" );
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
QVariant PartitionListModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
// Convert the treeview index to a flat index
|
||||
QModelIndex flatIndex = m_model->index( index.row(), 0, index.parent() );
|
||||
QVariant data = m_model->data( flatIndex, role );
|
||||
if ( role == PartitionModel::SizeRole )
|
||||
{
|
||||
data = m_model->data( flatIndex, PartitionModel::SizeRole );
|
||||
}
|
||||
if ( role == Qt::UserRole + 2 )
|
||||
{
|
||||
QVariantMap partitionData;
|
||||
partitionData.insert( "IsFreeSpaceRole", m_model->data( flatIndex, PartitionModel::IsFreeSpaceRole ) );
|
||||
partitionData.insert( "IsPartitionNewRole", m_model->data( flatIndex, PartitionModel::IsPartitionNewRole ) );
|
||||
partitionData.insert( "FileSystemLabelRole", m_model->data( flatIndex, PartitionModel::FileSystemLabelRole ) );
|
||||
partitionData.insert( "FileSystemTypeRole", m_model->data( flatIndex, PartitionModel::FileSystemTypeRole ) );
|
||||
partitionData.insert( "PartitionPathRole", m_model->data( flatIndex, PartitionModel::PartitionPathRole ) );
|
||||
partitionData.insert( "PartitionPtrRole", m_model->data( flatIndex, PartitionModel::PartitionPtrRole ) );
|
||||
partitionData.insert( "OsproberNameRole", m_model->data( flatIndex, PartitionModel::OsproberNameRole ) );
|
||||
partitionData.insert( "OsproberPathRole", m_model->data( flatIndex, PartitionModel::OsproberPathRole ) );
|
||||
partitionData.insert( "OsproberCanBeResizedRole", m_model->data( flatIndex, PartitionModel::OsproberCanBeResizedRole ) );
|
||||
partitionData.insert( "OsproberRawLineRole", m_model->data( flatIndex, PartitionModel::OsproberRawLineRole ) );
|
||||
partitionData.insert( "OsproberHomePartitionPathRole", m_model->data( flatIndex, PartitionModel::OsproberHomePartitionPathRole ) );
|
||||
data.setValue( partitionData );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
QVariantMap PartitionListModel::get( int row ) const
|
||||
{
|
||||
return data( index( row, 0 ), Qt::DisplayRole ).toList().first().toMap();
|
||||
}
|
||||
|
||||
QModelIndex PartitionListModel::mapToSource( const QModelIndex& index ) const
|
||||
{
|
||||
return m_model->index( index.row(), 0, index.parent() );
|
||||
}
|
39
src/modules/partitionq/FlatPartitionModel.h
Normal file
39
src/modules/partitionq/FlatPartitionModel.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FLATPARTITIONMODEL_H
|
||||
#define FLATPARTITIONMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
class PartitionModel;
|
||||
|
||||
// Flatten the PartionModel.
|
||||
// This is used by the QML frontend to display the partition table.
|
||||
class PartitionListModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PartitionListModel( PartitionModel* model, QObject* parent = nullptr );
|
||||
|
||||
int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
|
||||
QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
|
||||
QHash< int, QByteArray > roleNames() const override;
|
||||
|
||||
Q_INVOKABLE QVariantMap get( int row ) const;
|
||||
|
||||
QModelIndex mapToSource( const QModelIndex& index ) const;
|
||||
|
||||
private:
|
||||
PartitionModel* m_model;
|
||||
};
|
||||
|
||||
#endif // FLATPARTITIONMODEL_H
|
120
src/modules/partitionq/PartitionQmlViewStep.cpp
Normal file
120
src/modules/partitionq/PartitionQmlViewStep.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <Aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PartitionQmlViewStep.h"
|
||||
#include "Config.h"
|
||||
#include "ChoicePageQml.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "core/PartUtils.h"
|
||||
#include "core/PartitionCoreModule.h"
|
||||
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( PartitionQmlViewStepFactory, registerPlugin< PartitionQmlViewStep >(); )
|
||||
|
||||
PartitionQmlViewStep::PartitionQmlViewStep( QObject* parent )
|
||||
: Calamares::QmlViewStep( parent )
|
||||
, m_config( new Config( this ) )
|
||||
, m_core( nullptr )
|
||||
, m_choicePage( nullptr )
|
||||
{
|
||||
m_choicePage = new ChoicePageQml(m_config, this);
|
||||
m_core = new PartitionCoreModule( this ); // Unusable before init is complete!
|
||||
Calamares::QmlViewStep::setContextProperty( "core", m_core );
|
||||
Calamares::QmlViewStep::setContextProperty( "choicePage", m_choicePage );
|
||||
|
||||
emit nextStatusChanged( true );
|
||||
}
|
||||
|
||||
QString
|
||||
PartitionQmlViewStep::prettyName() const
|
||||
{
|
||||
return tr( "Partition" );
|
||||
}
|
||||
|
||||
bool
|
||||
PartitionQmlViewStep::isNextEnabled() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PartitionQmlViewStep::isBackEnabled() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PartitionQmlViewStep::isAtBeginning() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PartitionQmlViewStep::isAtEnd() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Calamares::JobList
|
||||
PartitionQmlViewStep::jobs() const
|
||||
{
|
||||
return m_core->jobs( m_config );
|
||||
}
|
||||
|
||||
void
|
||||
PartitionQmlViewStep::onActivate()
|
||||
{
|
||||
m_choicePage->init( m_core );
|
||||
}
|
||||
|
||||
void
|
||||
PartitionQmlViewStep::onLeave()
|
||||
{
|
||||
}
|
||||
|
||||
QObject*
|
||||
PartitionQmlViewStep::getConfig()
|
||||
{
|
||||
return m_config;
|
||||
}
|
||||
|
||||
QObject* PartitionQmlViewStep::getCore()
|
||||
{
|
||||
return m_core;
|
||||
}
|
||||
|
||||
void
|
||||
PartitionQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_config->setConfigurationMap( configurationMap );
|
||||
Calamares::QmlViewStep::setConfigurationMap( configurationMap );
|
||||
|
||||
m_future = new QFutureWatcher< void >();
|
||||
connect( m_future,
|
||||
&QFutureWatcher< void >::finished,
|
||||
this,
|
||||
[ this ]
|
||||
{
|
||||
this->m_future->deleteLater();
|
||||
this->m_future = nullptr;
|
||||
} );
|
||||
|
||||
QFuture< void > future = QtConcurrent::run( this, &PartitionQmlViewStep::initPartitionCoreModule );
|
||||
m_future->setFuture( future );
|
||||
}
|
||||
|
||||
void
|
||||
PartitionQmlViewStep::initPartitionCoreModule()
|
||||
{
|
||||
Q_ASSERT( m_core );
|
||||
m_core->init();
|
||||
}
|
60
src/modules/partitionq/PartitionQmlViewStep.h
Normal file
60
src/modules/partitionq/PartitionQmlViewStep.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <Aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PARTITIONQMLVIEWSTEP_H
|
||||
#define PARTITIONQMLVIEWSTEP_H
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "DllMacro.h"
|
||||
#include "utils/PluginFactory.h"
|
||||
#include "viewpages/QmlViewStep.h"
|
||||
|
||||
#include "core/PartitionCoreModule.h"
|
||||
#include "ChoicePageQml.h"
|
||||
|
||||
#include <QObject>
|
||||
template < typename T >
|
||||
class QFutureWatcher;
|
||||
|
||||
class PLUGINDLLEXPORT PartitionQmlViewStep : public Calamares::QmlViewStep
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PartitionQmlViewStep( QObject* parent = nullptr );
|
||||
|
||||
QString prettyName() const override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
bool isAtBeginning() const override;
|
||||
bool isAtEnd() const override;
|
||||
|
||||
Calamares::JobList jobs() const override;
|
||||
|
||||
void onActivate() override;
|
||||
void onLeave() override;
|
||||
|
||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||
QObject* getConfig() override;
|
||||
QObject* getCore();
|
||||
|
||||
private:
|
||||
void initPartitionCoreModule();
|
||||
Config* m_config;
|
||||
PartitionCoreModule* m_core;
|
||||
QFutureWatcher< void >* m_future;
|
||||
ChoicePageQml* m_choicePage;
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( PartitionQmlViewStepFactory )
|
||||
|
||||
#endif // PARTITIONQMLVIEWSTEP_H
|
112
src/modules/partitionq/images/partition-table.svg
Normal file
112
src/modules/partitionq/images/partition-table.svg
Normal file
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="22"
|
||||
height="22"
|
||||
id="svg3813"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="kr_diskusage.svg">
|
||||
<defs
|
||||
id="defs3815" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="14.427263"
|
||||
inkscape:cy="11.039521"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1021"
|
||||
inkscape:window-x="-4"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:showpageshadow="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4109" />
|
||||
<sodipodi:guide
|
||||
position="2.0000072,19.999993"
|
||||
orientation="18,0"
|
||||
id="guide4115" />
|
||||
<sodipodi:guide
|
||||
position="2.0000072,1.9999929"
|
||||
orientation="0,18"
|
||||
id="guide4117" />
|
||||
<sodipodi:guide
|
||||
position="20.000007,1.9999929"
|
||||
orientation="-18,0"
|
||||
id="guide4119" />
|
||||
<sodipodi:guide
|
||||
position="20.000007,19.999993"
|
||||
orientation="0,-18"
|
||||
id="guide4121" />
|
||||
<sodipodi:guide
|
||||
position="3.0000072,18.999993"
|
||||
orientation="16,0"
|
||||
id="guide4123" />
|
||||
<sodipodi:guide
|
||||
position="3.0000072,2.9999929"
|
||||
orientation="0,16"
|
||||
id="guide4125" />
|
||||
<sodipodi:guide
|
||||
position="19.000007,2.9999929"
|
||||
orientation="-16,0"
|
||||
id="guide4127" />
|
||||
<sodipodi:guide
|
||||
position="19.000007,18.999993"
|
||||
orientation="0,-16"
|
||||
id="guide4129" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3818">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Capa 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-378.85714,-540.07647)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 389.85714,543.07647 c -4.432,0 -8,3.568 -8,8 0,4.432 3.568,8 8,8 4.432,0 8,-3.568 8,-8 0,-4.432 -3.568,-8 -8,-8 z m 0,1 c 3.878,0 7,3.122 7,7 0,3.878 -3.122,7 -7,7 -3.878,0 -7,-3.122 -7,-7 0,-3.878 3.122,-7 7,-7 z"
|
||||
id="rect4185" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 389.85714,547.07647 c -2.216,0 -4,1.784 -4,4 0,2.216 1.784,4 4,4 2.216,0 4,-1.784 4,-4 0,-2.216 -1.784,-4 -4,-4 z m 0,1 c 0.46399,0 0.89764,0.11233 1.28906,0.29883 0.18113,-0.1837 0.43139,-0.29883 0.71094,-0.29883 0.554,0 1,0.446 1,1 0,0.27955 -0.11513,0.52981 -0.29883,0.71094 0.18651,0.39142 0.29883,0.82507 0.29883,1.28906 0,1.662 -1.338,3 -3,3 -1.662,0 -3,-1.338 -3,-3 0,-1.662 1.338,-3 3,-3 z"
|
||||
id="rect4225" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 391.85714,547.07647 c -1.108,0 -2,0.892 -2,2 0,1.108 0.892,2 2,2 1.108,0 2,-0.892 2,-2 0,-1.108 -0.892,-2 -2,-2 z m 0,1 c 0.554,0 1,0.446 1,1 0,0.554 -0.446,1 -1,1 -0.554,0 -1,-0.446 -1,-1 0,-0.554 0.446,-1 1,-1 z"
|
||||
id="rect4230" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
4
src/modules/partitionq/partitionq.conf
Normal file
4
src/modules/partitionq/partitionq.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
# ToDo: use for qml module specific settings
|
46
src/modules/partitionq/partitionq.qml
Normal file
46
src/modules/partitionq/partitionq.qml
Normal file
@@ -0,0 +1,46 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Aditya Mehra <aix.m@outlook.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
import io.calamares.core 1.0
|
||||
import io.calamares.ui 1.0
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Window 2.14
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import org.kde.kirigami 2.7 as Kirigami
|
||||
|
||||
Page {
|
||||
id: partitionPage
|
||||
|
||||
Connections {
|
||||
target: core
|
||||
onInitCompleted: {
|
||||
console.log("Partition Core Module Init Completed")
|
||||
busyIndicator.running = false
|
||||
busyIndicator.visible = false
|
||||
partitionViewLoader.source = "qrc:/ChoosePage.qml"
|
||||
}
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
id: busyIndicator
|
||||
anchors.centerIn: parent
|
||||
running: true
|
||||
visible: true
|
||||
width: parent.width / 2
|
||||
height: parent.height / 2
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: partitionViewLoader
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
7
src/modules/partitionq/partitionq.qrc
Normal file
7
src/modules/partitionq/partitionq.qrc
Normal file
@@ -0,0 +1,7 @@
|
||||
<RCC>
|
||||
<qresource>
|
||||
<file>partitionq.qml</file>
|
||||
<file>ChoosePage.qml</file>
|
||||
<file>images/partition-table.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
Reference in New Issue
Block a user