Turn PartitionModel into a tree model

Fixes #12
This commit is contained in:
Aurélien Gâteau 2014-07-29 10:57:10 +02:00
parent e3a52745fc
commit 5c1336f2d5
8 changed files with 138 additions and 61 deletions

View File

@ -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 );
}

View File

@ -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();

View File

@ -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
*/

View File

@ -30,49 +30,93 @@
// KF5
#include <KFormat>
//- 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() );
}

View File

@ -19,22 +19,40 @@
#define PARTITIONMODEL_H
// Qt
#include <QAbstractListModel>
#include <QAbstractItemModel>
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 */

View File

@ -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();
}

View File

@ -50,6 +50,7 @@ private:
void onEditClicked();
void onDeleteClicked();
void onPartitionViewActivated();
void onPartitionModelReset();
void updatePartitionToCreate( Device*, Partition* );
void editExistingPartition( Device*, Partition* );

View File

@ -72,6 +72,9 @@
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>