EditExistingPartitionDialog: Visual resizing of partitions

This commit is contained in:
Aurélien Gâteau 2014-08-06 18:31:46 +02:00
parent c3efa65668
commit 55f4231c92
6 changed files with 300 additions and 32 deletions

View file

@ -40,6 +40,7 @@ calamares_add_plugin( partition
PartitionModel.cpp PartitionModel.cpp
PartitionPage.cpp PartitionPage.cpp
PartitionPreview.cpp PartitionPreview.cpp
PartitionSizeController.cpp
PartitionSizeWidget.cpp PartitionSizeWidget.cpp
PartitionViewStep.cpp PartitionViewStep.cpp
PMUtils.cpp PMUtils.cpp

View file

@ -20,6 +20,7 @@
#include <PartitionCoreModule.h> #include <PartitionCoreModule.h>
#include <PartitionInfo.h> #include <PartitionInfo.h>
#include <PartitionSizeController.h>
#include <PMUtils.h> #include <PMUtils.h>
#include <ui_EditExistingPartitionDialog.h> #include <ui_EditExistingPartitionDialog.h>
#include <utils/Logger.h> #include <utils/Logger.h>
@ -27,6 +28,7 @@
// CalaPM // CalaPM
#include <core/device.h> #include <core/device.h>
#include <core/partition.h> #include <core/partition.h>
#include <fs/filesystemfactory.h>
// Qt // Qt
#include <QComboBox> #include <QComboBox>
@ -36,10 +38,37 @@ EditExistingPartitionDialog::EditExistingPartitionDialog( Device* device, Partit
, m_ui( new Ui_EditExistingPartitionDialog ) , m_ui( new Ui_EditExistingPartitionDialog )
, m_device( device ) , m_device( device )
, m_partition( partition ) , m_partition( partition )
, m_partitionSizeController( new PartitionSizeController( this ) )
{ {
m_ui->setupUi( 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 ) ); m_ui->mountPointComboBox->setCurrentText( PartitionInfo::mountPoint( partition ) );
replacePartResizerWidget();
connect( m_ui->formatRadioButton, &QAbstractButton::toggled, [ this ]( bool )
{
replacePartResizerWidget();
} );
} }
EditExistingPartitionDialog::~EditExistingPartitionDialog() EditExistingPartitionDialog::~EditExistingPartitionDialog()
@ -50,9 +79,12 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
{ {
PartitionInfo::setMountPoint( m_partition, m_ui->mountPointComboBox->currentText() ); 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() ) if ( m_ui->formatRadioButton->isChecked() )
{ {
Partition* newPartition = PMUtils::createNewPartition( Partition* newPartition = PMUtils::createNewPartition(
@ -60,8 +92,8 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
*m_device, *m_device,
m_partition->roles(), m_partition->roles(),
m_partition->fileSystem().type(), m_partition->fileSystem().type(),
range.first, newFirstSector,
range.second ); newLastSector );
PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) ); PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) );
PartitionInfo::setFormat( newPartition, true ); PartitionInfo::setFormat( newPartition, true );
@ -69,7 +101,7 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
core->createPartition( m_device, newPartition ); core->createPartition( m_device, newPartition );
} }
else else
core->resizePartition( m_device, m_partition, range.first, range.second ); core->resizePartition( m_device, m_partition, newFirstSector, newLastSector );
} }
else else
{ {
@ -80,3 +112,39 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
core->refreshPartition( m_device, m_partition ); 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 );
}

View file

@ -25,6 +25,7 @@
class PartitionCoreModule; class PartitionCoreModule;
class Device; class Device;
class Partition; class Partition;
class PartitionSizeController;
class Ui_EditExistingPartitionDialog; class Ui_EditExistingPartitionDialog;
class EditExistingPartitionDialog : public QDialog class EditExistingPartitionDialog : public QDialog
@ -40,6 +41,10 @@ private:
QScopedPointer< Ui_EditExistingPartitionDialog > m_ui; QScopedPointer< Ui_EditExistingPartitionDialog > m_ui;
Device* m_device; Device* m_device;
Partition* m_partition; Partition* m_partition;
QScopedPointer< Partition > m_partResizerWidgetPartition;
PartitionSizeController* m_partitionSizeController;
void replacePartResizerWidget();
}; };
#endif /* EDITEXISTINGPARTITIONDIALOG_H */ #endif /* EDITEXISTINGPARTITIONDIALOG_H */

View file

@ -7,11 +7,11 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>350</width> <width>350</width>
<height>203</height> <height>236</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum"> <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -20,29 +20,31 @@
<string>Edit Existing Partition</string> <string>Edit Existing Partition</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="PartResizerWidget" name="partResizerWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>59</height>
</size>
</property>
</widget>
</item>
<item> <item>
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy"> <property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum> <enum>QFormLayout::ExpandingFieldsGrow</enum>
</property> </property>
<item row="0" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Si&amp;ze:</string>
</property>
<property name="buddy">
<cstring>sizeSpinBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="PartitionSizeWidget" name="sizeSpinBox">
<property name="suffix">
<string> MB</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Content:</string> <string>Content:</string>
@ -52,7 +54,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="2" column="1">
<widget class="QRadioButton" name="keepRadioButton"> <widget class="QRadioButton" name="keepRadioButton">
<property name="text"> <property name="text">
<string>Keep</string> <string>Keep</string>
@ -62,15 +64,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="3" column="1">
<widget class="QRadioButton" name="formatRadioButton"> <widget class="QRadioButton" name="formatRadioButton">
<property name="text"> <property name="text">
<string>Format</string> <string>Format</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>Warning: Formatting the partition will erase all existing data.</string> <string>Warning: Formatting the partition will erase all existing data.</string>
</property> </property>
@ -129,6 +137,19 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Size:</string>
</property>
<property name="buddy">
<cstring>sizeSpinBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="sizeSpinBox"/>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -145,9 +166,10 @@
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
<class>PartitionSizeWidget</class> <class>PartResizerWidget</class>
<extends>QSpinBox</extends> <extends>QWidget</extends>
<header location="global">PartitionSizeWidget.h</header> <header location="global">gui/partresizerwidget.h</header>
<container>1</container>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>

View file

@ -0,0 +1,115 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <PartitionSizeController.h>
// Qt
#include <QSpinBox>
// CalaPM
#include <core/device.h>
#include <core/partition.h>
#include <gui/partresizerwidget.h>
// stdc++
#include <limits>
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 );
}

View file

@ -0,0 +1,57 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PARTITIONSIZECONTROLLER_H
#define PARTITIONSIZECONTROLLER_H
#include <QObject>
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 */