diff --git a/src/modules/partition/EditExistingPartitionDialog.cpp b/src/modules/partition/EditExistingPartitionDialog.cpp index fdee1322b..492f41088 100644 --- a/src/modules/partition/EditExistingPartitionDialog.cpp +++ b/src/modules/partition/EditExistingPartitionDialog.cpp @@ -65,5 +65,5 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) if ( m_ui->formatRadioButton->isChecked() ) core->formatPartition( m_device, m_partition ); else - core->refresh( m_device ); + core->refreshPartition( m_device, m_partition ); } diff --git a/src/modules/partition/PartitionCoreModule.cpp b/src/modules/partition/PartitionCoreModule.cpp index 0e408cb0e..aa34a2e01 100644 --- a/src/modules/partition/PartitionCoreModule.cpp +++ b/src/modules/partition/PartitionCoreModule.cpp @@ -137,11 +137,12 @@ PartitionCoreModule::createPartitionTable( Device* device, PartitionTable::Table // keep previous changes info->forgetChanges(); + PartitionModel::ResetHelper helper( partitionModelForDevice( device ) ); CreatePartitionTableJob* job = new CreatePartitionTableJob( device, type ); job->updatePreview(); info->jobs << Calamares::job_ptr( job ); - refresh( device ); + refresh(); } void @@ -150,12 +151,13 @@ PartitionCoreModule::createPartition( Device* device, Partition* partition ) auto deviceInfo = infoForDevice( device ); Q_ASSERT( deviceInfo ); + PartitionModel::ResetHelper helper( partitionModelForDevice( device ) ); CreatePartitionJob* job = new CreatePartitionJob( device, partition ); job->updatePreview(); deviceInfo->jobs << Calamares::job_ptr( job ); - refresh( device ); + refresh(); } void @@ -164,6 +166,8 @@ PartitionCoreModule::deletePartition( Device* device, Partition* partition ) auto deviceInfo = infoForDevice( device ); Q_ASSERT( deviceInfo ); + PartitionModel::ResetHelper helper( partitionModelForDevice( device ) ); + if ( partition->roles().has( PartitionRole::Extended ) ) { // Delete all logical partitions first @@ -220,7 +224,7 @@ PartitionCoreModule::deletePartition( Device* device, Partition* partition ) jobs << Calamares::job_ptr( job ); } - refresh( device ); + refresh(); } void @@ -228,11 +232,12 @@ PartitionCoreModule::formatPartition( Device* device, Partition* partition ) { auto deviceInfo = infoForDevice( device ); Q_ASSERT( deviceInfo ); + PartitionModel::ResetHelper helper( partitionModelForDevice( device ) ); FormatPartitionJob* job = new FormatPartitionJob( device, partition ); deviceInfo->jobs << Calamares::job_ptr( job ); - refresh( device ); + refresh(); } QList< Calamares::job_ptr > @@ -262,11 +267,21 @@ PartitionCoreModule::dumpQueue() const } void -PartitionCoreModule::refresh( Device* device ) +PartitionCoreModule::refreshPartition( Device* device, Partition* partition ) { + // Keep it simple for now: reset the model. This can be improved to cause + // the model to emit dataChanged() for the affected row instead, avoiding + // the loss of the current selection. auto model = partitionModelForDevice( device ); Q_ASSERT( model ); - model->reload(); + PartitionModel::ResetHelper helper( model ); + + refresh(); +} + +void +PartitionCoreModule::refresh() +{ updateHasRootMountPoint(); updateIsDirty(); m_bootLoaderModel->update(); diff --git a/src/modules/partition/PartitionCoreModule.h b/src/modules/partition/PartitionCoreModule.h index 860ac144e..79d54e5cc 100644 --- a/src/modules/partition/PartitionCoreModule.h +++ b/src/modules/partition/PartitionCoreModule.h @@ -71,15 +71,22 @@ public: return m_hasRootMountPoint; } - void refresh( Device* device ); - void revert(); + /** + * To be called when a partition has been altered, but only for changes + * which do not affect its size, because changes which affect the partition size + * affect the size of other partitions as well. + */ + void refreshPartition( Device* device, Partition* partition ); + Q_SIGNALS: void hasRootMountPointChanged( bool value ); void isDirtyChanged( bool value ); private: + void refresh(); + /** * Owns the Device, PartitionModel and the jobs */ diff --git a/src/modules/partition/PartitionModel.cpp b/src/modules/partition/PartitionModel.cpp index 69e31e809..07c6356ed 100644 --- a/src/modules/partition/PartitionModel.cpp +++ b/src/modules/partition/PartitionModel.cpp @@ -30,49 +30,93 @@ // KF5 #include +//- ResetHelper -------------------------------------------- +PartitionModel::ResetHelper::ResetHelper( PartitionModel* model ) +: m_model( model ) +{ + m_model->beginResetModel(); +} + +PartitionModel::ResetHelper::~ResetHelper() +{ + m_model->endResetModel(); +} + +//- PartitionModel ----------------------------------------- PartitionModel::PartitionModel( QObject* parent ) - : QAbstractListModel( parent ) + : QAbstractItemModel( parent ) { } void PartitionModel::init( Device* device ) -{ - m_device = device; - reload(); -} - -void -PartitionModel::reload() { beginResetModel(); - m_partitionList.clear(); - if ( m_device ) - fillPartitionList( m_device->partitionTable() ); + m_device = device; endResetModel(); } int PartitionModel::columnCount( const QModelIndex& parent ) const { - return LastColumn; + return ColumnCount; } int PartitionModel::rowCount( const QModelIndex& parent ) const { - return parent.isValid() ? 0 : m_partitionList.count(); + Partition* parentPartition = partitionForIndex( parent ); + if ( parentPartition ) + return parentPartition->children().count(); + PartitionTable* table = m_device->partitionTable(); + return table ? table->children().count() : 0; +} + +QModelIndex +PartitionModel::index( int row, int column, const QModelIndex& parent ) const +{ + PartitionNode* parentPartition = parent.isValid() + ? static_cast< PartitionNode* >( partitionForIndex( parent )) + : static_cast< PartitionNode* >( m_device->partitionTable() ); + if ( !parentPartition ) + return QModelIndex(); + auto lst = parentPartition->children(); + if ( row < 0 || row >= lst.count() ) + return QModelIndex(); + if ( column < 0 || column >= ColumnCount ) + return QModelIndex(); + Partition* partition = parentPartition->children().at( row ); + return createIndex( row, column, partition ); +} + +QModelIndex +PartitionModel::parent( const QModelIndex& child ) const +{ + if ( !child.isValid() ) + return QModelIndex(); + Partition* partition = partitionForIndex( child ); + PartitionNode* parentNode = partition->parent(); + if ( parentNode == m_device->partitionTable() ) + return QModelIndex(); + + int row = 0; + for ( auto p : m_device->partitionTable()->children() ) + { + if ( parentNode == p ) + return createIndex( row, 0, parentNode ); + ++row; + } + cLog() << "No parent found!"; + return QModelIndex(); } QVariant PartitionModel::data( const QModelIndex& index, int role ) const { - int row = index.row(); - if ( row < 0 || row >= m_partitionList.count() ) + Partition* partition = partitionForIndex( index ); + if ( !partition ) return QVariant(); - Partition* partition = m_partitionList.at( row ); - switch ( role ) { case Qt::DisplayRole: @@ -80,17 +124,13 @@ PartitionModel::data( const QModelIndex& index, int role ) const int col = index.column(); if ( col == NameColumn ) { - // FIXME: Turn model into a tree model, will make implementing the - // preview easier - QString prefix = partition->roles().has( PartitionRole::Logical ) - ? QStringLiteral( " " ) : QStringLiteral(); if ( PMUtils::isPartitionFreeSpace( partition ) ) - return prefix + tr( "Free Space" ); + return tr( "Free Space" ); else { - return prefix + ( PMUtils::isPartitionNew( partition ) - ? tr( "New partition" ) - : partition->partitionPath() ); + return PMUtils::isPartitionNew( partition ) + ? tr( "New partition" ) + : partition->partitionPath(); } } if ( col == FileSystemColumn ) @@ -132,23 +172,10 @@ PartitionModel::headerData( int section, Qt::Orientation orientation, int role ) } } -void -PartitionModel::fillPartitionList( PartitionNode* parent ) -{ - if ( !parent ) - return; - for ( auto partition : parent->children() ) - { - m_partitionList << partition; - fillPartitionList( partition ); - } -} - Partition* PartitionModel::partitionForIndex( const QModelIndex& index ) const { - int row = index.row(); - if ( row < 0 || row >= m_partitionList.count() ) + if ( !index.isValid() ) return nullptr; - return m_partitionList.at( row ); + return reinterpret_cast< Partition* >( index.internalPointer() ); } diff --git a/src/modules/partition/PartitionModel.h b/src/modules/partition/PartitionModel.h index acb19e17a..50981ae2c 100644 --- a/src/modules/partition/PartitionModel.h +++ b/src/modules/partition/PartitionModel.h @@ -19,22 +19,40 @@ #define PARTITIONMODEL_H // Qt -#include +#include class Device; class Partition; class PartitionNode; -class PartitionModel : public QAbstractListModel +class PartitionModel : public QAbstractItemModel { public: + /** + * This helper class must be instantiated on the stack *before* making + * changes to the device represented by this model. It will cause the model + * to emit modelAboutToBeReset() when instantiated and modelReset() when + * destructed. + */ + class ResetHelper + { + public: + ResetHelper( PartitionModel* model ); + ~ResetHelper(); + + ResetHelper( const ResetHelper& ) = delete; + ResetHelper& operator=( const ResetHelper& ) = delete; + private: + PartitionModel* m_model; + }; + enum Column { NameColumn, FileSystemColumn, MountPointColumn, SizeColumn, - LastColumn = SizeColumn + 1 + ColumnCount = SizeColumn + 1 }; PartitionModel( QObject* parent = 0 ); @@ -43,6 +61,8 @@ public: */ void init( Device* device ); + QModelIndex index( int row, int column, const QModelIndex& parent = QModelIndex() ) const override; + QModelIndex parent( const QModelIndex& child ) const override; int columnCount( const QModelIndex& parent = QModelIndex() ) const override; int rowCount( const QModelIndex& parent = QModelIndex() ) const override; QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override; @@ -55,16 +75,8 @@ public: return m_device; } - /** - * Reload model from m_device new content - */ - void reload(); - private: Device* m_device; - QList< Partition* > m_partitionList; - - void fillPartitionList( PartitionNode* parent ); }; #endif /* PARTITIONMODEL_H */ diff --git a/src/modules/partition/PartitionPage.cpp b/src/modules/partition/PartitionPage.cpp index 05fa6243d..393cb7561 100644 --- a/src/modules/partition/PartitionPage.cpp +++ b/src/modules/partition/PartitionPage.cpp @@ -249,8 +249,13 @@ PartitionPage::updateFromCurrentDevice() Device* device = m_core->deviceModel()->deviceForIndex( index ); + QAbstractItemModel* oldModel = m_ui->partitionTreeView->model(); + if ( oldModel ) + disconnect( oldModel, 0, this, 0 ); + PartitionModel* model = m_core->partitionModelForDevice( device ); m_ui->partitionTreeView->setModel( model ); + m_ui->partitionTreeView->expandAll(); // Must be done here because we need to have a model set to define // individual column resize mode @@ -266,5 +271,12 @@ PartitionPage::updateFromCurrentDevice() { updateButtons(); } ); - connect( model, &QAbstractItemModel::modelReset, this, &PartitionPage::updateButtons ); + connect( model, &QAbstractItemModel::modelReset, this, &PartitionPage::onPartitionModelReset ); +} + +void +PartitionPage::onPartitionModelReset() +{ + m_ui->partitionTreeView->expandAll(); + updateButtons(); } diff --git a/src/modules/partition/PartitionPage.h b/src/modules/partition/PartitionPage.h index aacb7d220..4a4323f62 100644 --- a/src/modules/partition/PartitionPage.h +++ b/src/modules/partition/PartitionPage.h @@ -50,6 +50,7 @@ private: void onEditClicked(); void onDeleteClicked(); void onPartitionViewActivated(); + void onPartitionModelReset(); void updatePartitionToCreate( Device*, Partition* ); void editExistingPartition( Device*, Partition* ); diff --git a/src/modules/partition/PartitionPage.ui b/src/modules/partition/PartitionPage.ui index ae4c592ac..40ca567b4 100644 --- a/src/modules/partition/PartitionPage.ui +++ b/src/modules/partition/PartitionPage.ui @@ -72,6 +72,9 @@ true + + false + false