diff --git a/src/modules/partition/CMakeLists.txt b/src/modules/partition/CMakeLists.txt index 753e8eae6..0b99a9dff 100644 --- a/src/modules/partition/CMakeLists.txt +++ b/src/modules/partition/CMakeLists.txt @@ -40,6 +40,7 @@ calamares_add_plugin( partition PartitionModel.cpp PartitionPage.cpp PartitionPreview.cpp + PartitionSizeController.cpp PartitionSizeWidget.cpp PartitionViewStep.cpp PMUtils.cpp diff --git a/src/modules/partition/EditExistingPartitionDialog.cpp b/src/modules/partition/EditExistingPartitionDialog.cpp index e946fec91..6a991143f 100644 --- a/src/modules/partition/EditExistingPartitionDialog.cpp +++ b/src/modules/partition/EditExistingPartitionDialog.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ // CalaPM #include #include +#include // Qt #include @@ -36,10 +38,37 @@ EditExistingPartitionDialog::EditExistingPartitionDialog( Device* device, Partit , m_ui( new Ui_EditExistingPartitionDialog ) , m_device( device ) , m_partition( partition ) + , m_partitionSizeController( new PartitionSizeController( this ) ) { m_ui->setupUi( this ); - m_ui->sizeSpinBox->init( device, partition ); + + // Create a partition for partResizerWidget because it alters the first and + // last sectors when used + FileSystem* fs = FileSystemFactory::create( + m_partition->fileSystem().type(), + m_partition->firstSector(), + m_partition->lastSector() + ); + m_partResizerWidgetPartition.reset( new Partition( + m_partition->parent(), + *m_device, + m_partition->roles(), + fs, fs->firstSector(), fs->lastSector(), + m_partition->partitionPath() + ) + ); + + m_partitionSizeController->init( m_device, m_partResizerWidgetPartition.data() ); + m_partitionSizeController->setSpinBox( m_ui->sizeSpinBox ); + m_ui->mountPointComboBox->setCurrentText( PartitionInfo::mountPoint( partition ) ); + + replacePartResizerWidget(); + + connect( m_ui->formatRadioButton, &QAbstractButton::toggled, [ this ]( bool ) + { + replacePartResizerWidget(); + } ); } EditExistingPartitionDialog::~EditExistingPartitionDialog() @@ -50,9 +79,12 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) { PartitionInfo::setMountPoint( m_partition, m_ui->mountPointComboBox->currentText() ); - if ( m_ui->sizeSpinBox->isDirty() ) + qint64 newFirstSector = m_partResizerWidgetPartition->firstSector(); + qint64 newLastSector = m_partResizerWidgetPartition->lastSector(); + bool partitionChanged = newFirstSector != m_partition->firstSector() || newLastSector != m_partition->lastSector(); + + if ( partitionChanged ) { - PartitionSizeWidget::SectorRange range = m_ui->sizeSpinBox->sectorRange(); if ( m_ui->formatRadioButton->isChecked() ) { Partition* newPartition = PMUtils::createNewPartition( @@ -60,8 +92,8 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) *m_device, m_partition->roles(), m_partition->fileSystem().type(), - range.first, - range.second ); + newFirstSector, + newLastSector ); PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) ); PartitionInfo::setFormat( newPartition, true ); @@ -69,7 +101,7 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) core->createPartition( m_device, newPartition ); } else - core->resizePartition( m_device, m_partition, range.first, range.second ); + core->resizePartition( m_device, m_partition, newFirstSector, newLastSector ); } else { @@ -80,3 +112,39 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) core->refreshPartition( m_device, m_partition ); } } + +void +EditExistingPartitionDialog::replacePartResizerWidget() +{ + /* + * There is no way to reliably update the partition used by + * PartResizerWidget, which is necessary when we switch between "format" and + * "keep". This is a hack which replaces the existing PartResizerWidget + * with a new one. + */ + + bool format = m_ui->formatRadioButton->isChecked(); + + qint64 used = format ? 0 : m_partition->fileSystem().sectorsUsed(); + m_partResizerWidgetPartition->fileSystem().setSectorsUsed( used ); + + qint64 minFirstSector = m_partition->firstSector() - m_device->partitionTable()->freeSectorsBefore( *m_partition ); + qint64 maxLastSector = m_partition->lastSector() + m_device->partitionTable()->freeSectorsAfter( *m_partition ); + + PartResizerWidget* widget = new PartResizerWidget( this ); + widget->init( *m_device, *m_partResizerWidgetPartition, minFirstSector, maxLastSector ); + + if ( !format ) + { + // If we are not formatting, make sure the space between the first and + // last sectors is big enough to fit the existing content. + widget->updateLastSector( m_partResizerWidgetPartition->lastSector() ); + widget->updateFirstSector( m_partResizerWidgetPartition->firstSector() ); + } + + layout()->replaceWidget( m_ui->partResizerWidget, widget ); + delete m_ui->partResizerWidget; + m_ui->partResizerWidget = widget; + + m_partitionSizeController->setPartResizerWidget( widget ); +} diff --git a/src/modules/partition/EditExistingPartitionDialog.h b/src/modules/partition/EditExistingPartitionDialog.h index 270bbb0e5..779e318d0 100644 --- a/src/modules/partition/EditExistingPartitionDialog.h +++ b/src/modules/partition/EditExistingPartitionDialog.h @@ -25,6 +25,7 @@ class PartitionCoreModule; class Device; class Partition; +class PartitionSizeController; class Ui_EditExistingPartitionDialog; class EditExistingPartitionDialog : public QDialog @@ -40,6 +41,10 @@ private: QScopedPointer< Ui_EditExistingPartitionDialog > m_ui; Device* m_device; Partition* m_partition; + QScopedPointer< Partition > m_partResizerWidgetPartition; + PartitionSizeController* m_partitionSizeController; + + void replacePartResizerWidget(); }; #endif /* EDITEXISTINGPARTITIONDIALOG_H */ diff --git a/src/modules/partition/EditExistingPartitionDialog.ui b/src/modules/partition/EditExistingPartitionDialog.ui index 3cbfeebd7..3618302b3 100644 --- a/src/modules/partition/EditExistingPartitionDialog.ui +++ b/src/modules/partition/EditExistingPartitionDialog.ui @@ -7,11 +7,11 @@ 0 0 350 - 203 + 236 - + 0 0 @@ -20,29 +20,31 @@ Edit Existing Partition + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + + 0 + 59 + + + + QFormLayout::ExpandingFieldsGrow - - - - Si&ze: - - - sizeSpinBox - - - - - - - MB - - - - + Content: @@ -52,7 +54,7 @@ - + Keep @@ -62,15 +64,21 @@ - + Format - + + + + 0 + 0 + + Warning: Formatting the partition will erase all existing data. @@ -129,6 +137,19 @@ + + + + Size: + + + sizeSpinBox + + + + + + @@ -145,9 +166,10 @@ - PartitionSizeWidget - QSpinBox -
PartitionSizeWidget.h
+ PartResizerWidget + QWidget +
gui/partresizerwidget.h
+ 1
diff --git a/src/modules/partition/PartitionSizeController.cpp b/src/modules/partition/PartitionSizeController.cpp new file mode 100644 index 000000000..25f25151f --- /dev/null +++ b/src/modules/partition/PartitionSizeController.cpp @@ -0,0 +1,115 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include + +// Qt +#include + +// CalaPM +#include +#include +#include + +// stdc++ +#include + +PartitionSizeController::PartitionSizeController( QObject* parent ) + : QObject( parent ) +{} + +void +PartitionSizeController::setPartResizerWidget( PartResizerWidget* widget ) +{ + if ( m_partResizerWidget ) + disconnect( m_partResizerWidget, 0, this, 0 ); + m_partResizerWidget = widget; + // FIXME: Should be set by PartResizerWidget itself + m_partResizerWidget->setFixedHeight( PartResizerWidget::handleHeight() ); + updateConnections(); +} + +void +PartitionSizeController::setSpinBox( QSpinBox* spinBox ) +{ + if ( m_spinBox ) + disconnect( m_spinBox, 0, this, 0 ); + m_spinBox = spinBox; + m_spinBox->setMaximum( std::numeric_limits< int >::max() ); + updateConnections(); +} + +void +PartitionSizeController::init( Device* device, Partition* partition ) +{ + m_device = device; + m_partition = partition; +} + +void +PartitionSizeController::updateConnections() +{ + if ( !m_spinBox || !m_partResizerWidget ) + return; + + connect( m_spinBox, SIGNAL( editingFinished() ), SLOT( updatePartResizerWidget() ) ); + connect( m_partResizerWidget, SIGNAL( firstSectorChanged( qint64 ) ), SLOT( updateSpinBox() ) ); + connect( m_partResizerWidget, SIGNAL( lastSectorChanged( qint64 ) ), SLOT( updateSpinBox() ) ); + updateSpinBox(); +} + +void +PartitionSizeController::updatePartResizerWidget() +{ + if ( m_updating ) + return; + m_updating = true; + qint64 sectorSize = qint64( m_spinBox->value() ) * 1024 * 1024 / m_device->logicalSectorSize(); + + qint64 firstSector = m_partition->firstSector(); + qint64 lastSector = firstSector + sectorSize - 1; + if ( lastSector > m_partResizerWidget->maximumLastSector() ) + { + qint64 delta = lastSector - m_partResizerWidget->maximumLastSector(); + firstSector -= delta; + lastSector -= delta; + } + m_partResizerWidget->updateLastSector( lastSector ); + m_partResizerWidget->updateFirstSector( firstSector ); + + // Update spinbox value in case it was an impossible value + doUpdateSpinBox(); + m_updating = false; +} + +void +PartitionSizeController::updateSpinBox() +{ + if ( m_updating ) + return; + m_updating = true; + doUpdateSpinBox(); + m_updating = false; +} + +void +PartitionSizeController::doUpdateSpinBox() +{ + qint64 mbSize = ( m_partition->lastSector() - m_partition->firstSector() + 1 ) * m_device->logicalSectorSize() / 1024 / 1024; + m_spinBox->setValue( mbSize ); +} diff --git a/src/modules/partition/PartitionSizeController.h b/src/modules/partition/PartitionSizeController.h new file mode 100644 index 000000000..6b1e0e204 --- /dev/null +++ b/src/modules/partition/PartitionSizeController.h @@ -0,0 +1,57 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef PARTITIONSIZECONTROLLER_H +#define PARTITIONSIZECONTROLLER_H + +#include + +class QSpinBox; + +class Device; +class Partition; +class PartResizerWidget; + +/** + * Synchronize a PartResizerWidget and a QSpinBox + */ +class PartitionSizeController : public QObject +{ + Q_OBJECT +public: + explicit PartitionSizeController( QObject* parent = nullptr ); + void setPartResizerWidget( PartResizerWidget* widget ); + void setSpinBox( QSpinBox* spinBox ); + void init( Device* device, Partition* partition ); + +private: + PartResizerWidget* m_partResizerWidget = nullptr; + QSpinBox* m_spinBox = nullptr; + Device* m_device = nullptr; + Partition* m_partition = nullptr; + bool m_updating = false; + + void updateConnections(); + void doUpdateSpinBox(); + +private Q_SLOTS: + void updatePartResizerWidget(); + void updateSpinBox(); +}; + +#endif /* PARTITIONSIZECONTROLLER_H */