New UI and logic for Alongside autopartitioning+install.
This commit is contained in:
parent
08a2ab94e7
commit
961eadada4
@ -38,6 +38,7 @@ calamares_add_plugin( partition
|
|||||||
gui/PartitionPage.cpp
|
gui/PartitionPage.cpp
|
||||||
gui/PartitionPreview.cpp
|
gui/PartitionPreview.cpp
|
||||||
gui/PartitionSizeController.cpp
|
gui/PartitionSizeController.cpp
|
||||||
|
gui/PartitionSplitterWidget.cpp
|
||||||
gui/PartitionViewStep.cpp
|
gui/PartitionViewStep.cpp
|
||||||
gui/PrettyRadioButton.cpp
|
gui/PrettyRadioButton.cpp
|
||||||
jobs/CheckFileSystemJob.cpp
|
jobs/CheckFileSystemJob.cpp
|
||||||
|
@ -18,9 +18,26 @@
|
|||||||
|
|
||||||
#include "AlongsidePage.h"
|
#include "AlongsidePage.h"
|
||||||
|
|
||||||
|
#include "core/ColorUtils.h"
|
||||||
|
#include "core/PartitionCoreModule.h"
|
||||||
|
#include "core/DeviceModel.h"
|
||||||
|
#include "core/PMUtils.h"
|
||||||
|
#include "core/device.h"
|
||||||
|
#include "core/partition.h"
|
||||||
|
#include "core/PartitionInfo.h"
|
||||||
|
#include "core/PartitionIterator.h"
|
||||||
|
#include "gui/PartitionSplitterWidget.h"
|
||||||
|
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/CalamaresUtilsGui.h"
|
||||||
|
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
|
|
||||||
AlongsidePage::AlongsidePage( QWidget* parent )
|
AlongsidePage::AlongsidePage( QWidget* parent )
|
||||||
: QWidget( parent )
|
: QWidget( parent )
|
||||||
, m_nextEnabled( false )
|
, m_nextEnabled( false )
|
||||||
@ -28,14 +45,133 @@ AlongsidePage::AlongsidePage( QWidget* parent )
|
|||||||
{
|
{
|
||||||
QVBoxLayout* mainLayout = new QVBoxLayout;
|
QVBoxLayout* mainLayout = new QVBoxLayout;
|
||||||
setLayout( mainLayout );
|
setLayout( mainLayout );
|
||||||
|
|
||||||
|
QHBoxLayout* partitionsComboLayout = new QHBoxLayout;
|
||||||
|
mainLayout->addLayout( partitionsComboLayout );
|
||||||
|
|
||||||
|
QLabel* partitionsLabel = new QLabel;
|
||||||
|
partitionsLabel->setText( tr( "Choose partition to shrink:" ) );
|
||||||
|
partitionsComboLayout->addWidget( partitionsLabel );
|
||||||
|
|
||||||
|
m_partitionsComboBox = new QComboBox;
|
||||||
|
partitionsComboLayout->addWidget( m_partitionsComboBox );
|
||||||
|
partitionsLabel->setBuddy( m_partitionsComboBox );
|
||||||
|
|
||||||
|
partitionsComboLayout->addStretch();
|
||||||
|
|
||||||
|
mainLayout->addWidget( new QLabel( tr( "Allocate drive space by dragging the divider below:" ) ) );
|
||||||
|
|
||||||
|
m_splitterWidget = new PartitionSplitterWidget;
|
||||||
|
mainLayout->addWidget( m_splitterWidget );
|
||||||
|
|
||||||
|
m_sizeLabel = new QLabel;
|
||||||
|
m_sizeLabel->setWordWrap( true );
|
||||||
|
mainLayout->addWidget( m_sizeLabel );
|
||||||
|
|
||||||
|
mainLayout->addStretch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AlongsidePage::init( PartitionCoreModule* core , const OsproberEntryList& osproberEntries )
|
AlongsidePage::init( PartitionCoreModule* core , const OsproberEntryList& osproberEntries )
|
||||||
{
|
{
|
||||||
QLabel* placeholder = new QLabel( "Alongside partitioning goes here." );
|
if ( m_core != core )
|
||||||
layout()->addWidget( placeholder );
|
m_core = core;
|
||||||
|
|
||||||
|
m_partitionsComboBox->clear();
|
||||||
|
|
||||||
|
connect( m_partitionsComboBox,
|
||||||
|
static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ),
|
||||||
|
this, [ this ]( int index )
|
||||||
|
{
|
||||||
|
QString path = m_partitionsComboBox->itemData( index ).toString();
|
||||||
|
cDebug() << "Current index changed:" << path;
|
||||||
|
|
||||||
|
DeviceModel* dm = m_core->deviceModel();
|
||||||
|
for ( int i = 0; i < dm->rowCount(); ++i )
|
||||||
|
{
|
||||||
|
Device* dev = dm->deviceForIndex( dm->index( i ) );
|
||||||
|
Partition* candidate = PMUtils::findPartitionByPath( { dev }, path );
|
||||||
|
if ( candidate )
|
||||||
|
{
|
||||||
|
// store candidate->partitionPath() here!
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
double requiredStorageGB = Calamares::JobQueue::instance()
|
||||||
|
->globalStorage()
|
||||||
|
->value( "requiredStorageGB" )
|
||||||
|
.toDouble( &ok );
|
||||||
|
|
||||||
|
qint64 usedStorageB = candidate->sectorsUsed() * dev->logicalSectorSize();
|
||||||
|
qint64 requiredStorageB = ( requiredStorageGB + 0.1 + 2.0 ) * 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
// set up splitter widget here, then set up the split position
|
||||||
|
QList< PartitionSplitterItem > allPartitionItems;
|
||||||
|
{
|
||||||
|
PartitionSplitterItem* extendedPartitionItem = nullptr;
|
||||||
|
for ( auto it = PartitionIterator::begin( dev );
|
||||||
|
it != PartitionIterator::end( dev ); ++it )
|
||||||
|
{
|
||||||
|
PartitionSplitterItem newItem = {
|
||||||
|
( *it )->partitionPath(),
|
||||||
|
ColorUtils::colorForPartition( *it ),
|
||||||
|
false,
|
||||||
|
( *it )->capacity(),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( ( *it )->roles().has( PartitionRole::Logical ) && extendedPartitionItem )
|
||||||
|
extendedPartitionItem->children.append( newItem );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allPartitionItems.append( newItem );
|
||||||
|
if ( ( *it )->roles().has( PartitionRole::Extended ) )
|
||||||
|
extendedPartitionItem = &allPartitionItems.last();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_splitterWidget->init( allPartitionItems );
|
||||||
|
|
||||||
|
m_splitterWidget->setSplitPartition( candidate->partitionPath(),
|
||||||
|
candidate->used() * 1.1,
|
||||||
|
candidate->capacity() - requiredStorageB,
|
||||||
|
candidate->capacity() / 2,
|
||||||
|
tr( "$RELEASE" ) );
|
||||||
|
|
||||||
|
m_splitterWidget->setFixedHeight( qMax< int >( CalamaresUtils::defaultFontHeight() * 1.5, 30 ) );
|
||||||
|
if ( ok )
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setNextEnabled( true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
connect( m_splitterWidget, &PartitionSplitterWidget::partitionResized,
|
||||||
|
this, [ this ]( const QString& path, qint64 size, qint64 sizeNext )
|
||||||
|
{
|
||||||
|
m_sizeLabel->setText( tr( "With this operation, the partition <b>%1</b> which contains "
|
||||||
|
"%4 will be shrunk "
|
||||||
|
"to %2MB and a new %3MB partition will be created for "
|
||||||
|
"$RELEASE." )
|
||||||
|
.arg( path )
|
||||||
|
.arg( size / ( 1024 * 1024 ) )
|
||||||
|
.arg( sizeNext / ( 1024 * 1024 ) )
|
||||||
|
.arg( m_partitionsComboBox->currentText() ) );
|
||||||
|
} );
|
||||||
|
|
||||||
|
foreach ( const OsproberEntry& e, osproberEntries )
|
||||||
|
{
|
||||||
|
if ( e.canBeResized )
|
||||||
|
m_partitionsComboBox->addItem( e.prettyName + " (" + e.path + ")", e.path );
|
||||||
|
}
|
||||||
|
setNextEnabled( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -46,6 +182,51 @@ AlongsidePage::isNextEnabled() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AlongsidePage::applyChanges()
|
||||||
|
{
|
||||||
|
m_core->revert();
|
||||||
|
|
||||||
|
Q_ASSERT( m_splitterWidget->splitPartitionSize() >= 0 );
|
||||||
|
Q_ASSERT( m_splitterWidget->newPartitionSize() >= 0 );
|
||||||
|
|
||||||
|
|
||||||
|
QString path = m_partitionsComboBox->currentData().toString();
|
||||||
|
|
||||||
|
DeviceModel* dm = m_core->deviceModel();
|
||||||
|
for ( int i = 0; i < dm->rowCount(); ++i )
|
||||||
|
{
|
||||||
|
Device* dev = dm->deviceForIndex( dm->index( i ) );
|
||||||
|
Partition* candidate = PMUtils::findPartitionByPath( { dev }, path );
|
||||||
|
if ( candidate )
|
||||||
|
{
|
||||||
|
qint64 firstSector = candidate->firstSector();
|
||||||
|
qint64 oldLastSector = candidate->lastSector();
|
||||||
|
qint64 newLastSector = m_splitterWidget->splitPartitionSize() /
|
||||||
|
dev->logicalSectorSize();
|
||||||
|
|
||||||
|
m_core->resizePartition( dev, candidate, firstSector, newLastSector );
|
||||||
|
Partition* newPartition = PMUtils::createNewPartition(
|
||||||
|
candidate->parent(),
|
||||||
|
*dev,
|
||||||
|
candidate->roles(),
|
||||||
|
FileSystem::Ext4,
|
||||||
|
newLastSector + 1,
|
||||||
|
oldLastSector );
|
||||||
|
PartitionInfo::setMountPoint( newPartition, "/" );
|
||||||
|
PartitionInfo::setFormat( newPartition, true );
|
||||||
|
|
||||||
|
m_core->createPartition( dev, newPartition );
|
||||||
|
m_core->setBootLoaderInstallPath( dev->deviceNode() );
|
||||||
|
|
||||||
|
m_core->dumpQueue();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AlongsidePage::setNextEnabled( bool enabled )
|
AlongsidePage::setNextEnabled( bool enabled )
|
||||||
{
|
{
|
||||||
@ -55,3 +236,4 @@ AlongsidePage::setNextEnabled( bool enabled )
|
|||||||
m_nextEnabled = enabled;
|
m_nextEnabled = enabled;
|
||||||
emit nextStatusChanged( enabled );
|
emit nextStatusChanged( enabled );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,12 @@
|
|||||||
|
|
||||||
#include "OsproberEntry.h"
|
#include "OsproberEntry.h"
|
||||||
|
|
||||||
|
class QComboBox;
|
||||||
|
class QLabel;
|
||||||
class PartitionCoreModule;
|
class PartitionCoreModule;
|
||||||
|
class PartitionSplitterWidget;
|
||||||
|
class Partition;
|
||||||
|
class Device;
|
||||||
|
|
||||||
class AlongsidePage : public QWidget
|
class AlongsidePage : public QWidget
|
||||||
{
|
{
|
||||||
@ -35,12 +40,18 @@ public:
|
|||||||
|
|
||||||
bool isNextEnabled() const;
|
bool isNextEnabled() const;
|
||||||
|
|
||||||
|
void applyChanges();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nextStatusChanged( bool );
|
void nextStatusChanged( bool );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setNextEnabled( bool enabled );
|
void setNextEnabled( bool enabled );
|
||||||
|
|
||||||
|
QComboBox* m_partitionsComboBox;
|
||||||
|
PartitionSplitterWidget* m_splitterWidget;
|
||||||
|
QLabel* m_sizeLabel;
|
||||||
|
|
||||||
PartitionCoreModule* m_core;
|
PartitionCoreModule* m_core;
|
||||||
|
|
||||||
bool m_nextEnabled;
|
bool m_nextEnabled;
|
||||||
|
417
src/modules/partition/gui/PartitionSplitterWidget.cpp
Normal file
417
src/modules/partition/gui/PartitionSplitterWidget.cpp
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
/* === This file is part of Calamares - <http://github.com/calamares> ===
|
||||||
|
*
|
||||||
|
* Copyright 2014, Teo Mrnjavac <teo@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 "PartitionSplitterWidget.h"
|
||||||
|
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QStyleOption>
|
||||||
|
|
||||||
|
static const int VIEW_HEIGHT = 30;
|
||||||
|
static const int CORNER_RADIUS = 3;
|
||||||
|
static const int EXTENDED_PARTITION_MARGIN = 4;
|
||||||
|
|
||||||
|
|
||||||
|
PartitionSplitterWidget::PartitionSplitterWidget( QWidget* parent )
|
||||||
|
: QWidget( parent )
|
||||||
|
, m_resizing( false )
|
||||||
|
, m_itemToResize( nullptr )
|
||||||
|
, m_itemToResizeNext( nullptr )
|
||||||
|
, HANDLE_SNAP( QApplication::startDragDistance() )
|
||||||
|
{
|
||||||
|
setMouseTracking( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::init( const QList<PartitionSplitterItem>& items )
|
||||||
|
{
|
||||||
|
m_itemToResize = nullptr;
|
||||||
|
m_itemToResizeNext = nullptr;
|
||||||
|
m_itemToResizePath.clear();
|
||||||
|
|
||||||
|
m_items = items;
|
||||||
|
repaint();
|
||||||
|
foreach ( const PartitionSplitterItem& item, items )
|
||||||
|
cDebug() << "PSI added item" << item.itemPath << "size" << item.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::setSplitPartition( const QString& path,
|
||||||
|
qint64 minSize,
|
||||||
|
qint64 maxSize,
|
||||||
|
qint64 preferredSize,
|
||||||
|
const QString& newLabel )
|
||||||
|
{
|
||||||
|
cDebug() << Q_FUNC_INFO << "path:" << path
|
||||||
|
<< "\nminSize:" << minSize
|
||||||
|
<< "\nmaxSize:" << maxSize
|
||||||
|
<< "\nprfSize:" << preferredSize;
|
||||||
|
|
||||||
|
if ( m_itemToResize || m_itemToResizeNext || !m_itemToResizePath.isEmpty() )
|
||||||
|
{
|
||||||
|
cDebug() << "ERROR: trying to split partition but partition to split is already set.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartitionSplitterItem* itemToResize = _findItem( m_items,
|
||||||
|
[ path ]( PartitionSplitterItem& item ) -> bool
|
||||||
|
{
|
||||||
|
return path == item.itemPath;
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( !itemToResize )
|
||||||
|
return;
|
||||||
|
cDebug() << "itemToResize:" << itemToResize->itemPath;
|
||||||
|
|
||||||
|
m_itemToResize = itemToResize;
|
||||||
|
m_itemToResizePath = path;
|
||||||
|
|
||||||
|
if ( preferredSize > maxSize )
|
||||||
|
preferredSize = maxSize;
|
||||||
|
|
||||||
|
qint64 newSize = m_itemToResize->size - preferredSize;
|
||||||
|
m_itemToResize->size = preferredSize;
|
||||||
|
m_itemMinSize = minSize;
|
||||||
|
m_itemMaxSize = maxSize;
|
||||||
|
m_itemPrefSize = preferredSize;
|
||||||
|
|
||||||
|
for ( int i = 0; i < m_items.count(); ++i )
|
||||||
|
{
|
||||||
|
if ( m_items[ i ].itemPath == itemToResize->itemPath )
|
||||||
|
{
|
||||||
|
m_items.insert( i+1,
|
||||||
|
{ "", QColor( "#d667b7" ), false, newSize, {} } );
|
||||||
|
m_itemToResizeNext = &( m_items[ i+1 ] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ( !m_items[ i ].children.isEmpty() )
|
||||||
|
{
|
||||||
|
for ( int j = 0; j < m_items[ i ].children.count(); ++j )
|
||||||
|
{
|
||||||
|
if ( m_items[ i ].children[ j ].itemPath == itemToResize->itemPath )
|
||||||
|
{
|
||||||
|
m_items[ i ].children.insert( j+1,
|
||||||
|
{ "", QColor( "#d667b7" ), false, newSize, {} } );
|
||||||
|
m_itemToResizeNext = &( m_items[ i ].children[ j+1 ] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( m_itemToResizeNext )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repaint();
|
||||||
|
|
||||||
|
emit partitionResized( m_itemToResize->itemPath,
|
||||||
|
m_itemToResize->size,
|
||||||
|
m_itemToResizeNext->size );
|
||||||
|
|
||||||
|
cDebug() << "Items updated. Status:";
|
||||||
|
foreach ( const PartitionSplitterItem& item, m_items )
|
||||||
|
cDebug() << "item" << item.itemPath << "size" << item.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qint64
|
||||||
|
PartitionSplitterWidget::splitPartitionSize() const
|
||||||
|
{
|
||||||
|
if ( !m_itemToResize )
|
||||||
|
return -1;
|
||||||
|
return m_itemToResize->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qint64
|
||||||
|
PartitionSplitterWidget::newPartitionSize() const
|
||||||
|
{
|
||||||
|
if ( !m_itemToResizeNext )
|
||||||
|
return -1;
|
||||||
|
return m_itemToResizeNext->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QSize
|
||||||
|
PartitionSplitterWidget::sizeHint() const
|
||||||
|
{
|
||||||
|
return QSize( -1, VIEW_HEIGHT );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::paintEvent( QPaintEvent* event )
|
||||||
|
{
|
||||||
|
QPainter painter( this );
|
||||||
|
painter.fillRect( rect(), palette().window() );
|
||||||
|
painter.setRenderHint( QPainter::Antialiasing );
|
||||||
|
drawPartitions( &painter, rect(), m_items );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::mousePressEvent( QMouseEvent* event )
|
||||||
|
{
|
||||||
|
if ( event->button() == Qt::LeftButton )
|
||||||
|
{
|
||||||
|
if ( qAbs( event->x() - m_resizeHandleX ) < HANDLE_SNAP )
|
||||||
|
m_resizing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::mouseMoveEvent( QMouseEvent* event )
|
||||||
|
{
|
||||||
|
if ( m_resizing )
|
||||||
|
{
|
||||||
|
qint64 start = 0;
|
||||||
|
foreach ( const PartitionSplitterItem& item, m_items )
|
||||||
|
{
|
||||||
|
if ( item.itemPath == m_itemToResize->itemPath )
|
||||||
|
break;
|
||||||
|
else if ( !item.children.isEmpty() )
|
||||||
|
{
|
||||||
|
bool done = false;
|
||||||
|
foreach ( const PartitionSplitterItem& child, item.children )
|
||||||
|
{
|
||||||
|
if ( child.itemPath == m_itemToResize->itemPath )
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start += child.size;
|
||||||
|
}
|
||||||
|
if ( done )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
start += item.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 total = 0;
|
||||||
|
for ( int row = 0; row < m_items.count(); ++row )
|
||||||
|
{
|
||||||
|
total += m_items[ row ].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ew = rect().width(); //effective width
|
||||||
|
qreal bpp = total / static_cast< qreal >( ew ); //bytes per pixel
|
||||||
|
|
||||||
|
qreal mx = event->x() * bpp - start;
|
||||||
|
|
||||||
|
// make sure we are within resize range
|
||||||
|
mx = qBound( static_cast< qreal >( m_itemMinSize ),
|
||||||
|
mx,
|
||||||
|
static_cast< qreal >( m_itemMaxSize ) );
|
||||||
|
|
||||||
|
qint64 span = m_itemPrefSize;
|
||||||
|
qreal percent = mx / span;
|
||||||
|
qint64 oldsize = m_itemToResize->size;
|
||||||
|
|
||||||
|
m_itemToResize->size = qRound64( span * percent );
|
||||||
|
m_itemToResizeNext->size -= m_itemToResize->size - oldsize;
|
||||||
|
|
||||||
|
qint64 t = 0;
|
||||||
|
for ( int row = 0; row < m_items.count(); ++row )
|
||||||
|
{
|
||||||
|
t += m_items[ row ].size;
|
||||||
|
}
|
||||||
|
Q_ASSERT( t == total );
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
|
||||||
|
emit partitionResized( m_itemToResize->itemPath,
|
||||||
|
m_itemToResize->size,
|
||||||
|
m_itemToResizeNext->size );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( m_itemToResize )
|
||||||
|
{
|
||||||
|
if ( qAbs( event->x() - m_resizeHandleX ) < HANDLE_SNAP )
|
||||||
|
setCursor( Qt::SplitHCursor );
|
||||||
|
else if ( cursor().shape() != Qt::ArrowCursor )
|
||||||
|
setCursor( Qt::ArrowCursor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::mouseReleaseEvent( QMouseEvent* event )
|
||||||
|
{
|
||||||
|
m_resizing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::drawSection( QPainter* painter, const QRect& rect_, int x, int width,
|
||||||
|
const PartitionSplitterItem& item )
|
||||||
|
{
|
||||||
|
QColor color = item.color;
|
||||||
|
bool isFreeSpace = item.isFreeSpace;
|
||||||
|
|
||||||
|
QRect rect = rect_;
|
||||||
|
const int y = rect.y();
|
||||||
|
const int rectHeight = rect.height();
|
||||||
|
const int radius = qMax( 1, CORNER_RADIUS - ( height() - rectHeight ) / 2 );
|
||||||
|
painter->setClipRect( x, y, width, rectHeight );
|
||||||
|
painter->translate( 0.5, 0.5 );
|
||||||
|
|
||||||
|
rect.adjust( 0, 0, -1, -1 );
|
||||||
|
const QColor borderColor = color.darker();
|
||||||
|
painter->setPen( borderColor );
|
||||||
|
painter->setBrush( color );
|
||||||
|
painter->drawRoundedRect( rect, radius, radius );
|
||||||
|
|
||||||
|
// Draw shade
|
||||||
|
if ( !isFreeSpace )
|
||||||
|
rect.adjust( 2, 2, -2, -2 );
|
||||||
|
|
||||||
|
QLinearGradient gradient( 0, 0, 0, rectHeight / 2 );
|
||||||
|
|
||||||
|
qreal c = isFreeSpace ? 0 : 1;
|
||||||
|
gradient.setColorAt( 0, QColor::fromRgbF( c, c, c, 0.3 ) );
|
||||||
|
gradient.setColorAt( 1, QColor::fromRgbF( c, c, c, 0 ) );
|
||||||
|
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( gradient );
|
||||||
|
painter->drawRoundedRect( rect, radius, radius );
|
||||||
|
|
||||||
|
painter->translate( -0.5, -0.5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::drawResizeHandle( QPainter* painter,
|
||||||
|
const QRect& rect_,
|
||||||
|
int x )
|
||||||
|
{
|
||||||
|
if ( !m_itemToResize )
|
||||||
|
return;
|
||||||
|
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( Qt::black );
|
||||||
|
painter->setClipRect( rect_ );
|
||||||
|
|
||||||
|
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||||
|
|
||||||
|
qreal h = rect_.height();
|
||||||
|
int scaleFactor = qRound( height() / static_cast< qreal >( VIEW_HEIGHT ) );
|
||||||
|
QList< QPair< qreal, qreal > > arrow_offsets = {
|
||||||
|
qMakePair( 0, h / 2 - 1 ),
|
||||||
|
qMakePair( 4, h / 2 - 1 ),
|
||||||
|
qMakePair( 4, h / 2 - 3 ),
|
||||||
|
qMakePair( 8, h / 2 ),
|
||||||
|
qMakePair( 4, h / 2 + 3 ),
|
||||||
|
qMakePair( 4, h / 2 + 1 ),
|
||||||
|
qMakePair( 0, h / 2 + 1 )
|
||||||
|
};
|
||||||
|
for ( int i = 0; i < arrow_offsets.count(); ++i )
|
||||||
|
{
|
||||||
|
arrow_offsets[ i ] = qMakePair( arrow_offsets[ i ].first * scaleFactor,
|
||||||
|
( arrow_offsets[ i ].second - h/2 ) * scaleFactor + h/2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p1 = arrow_offsets[ 0 ];
|
||||||
|
if ( m_itemToResize->size > m_itemMinSize )
|
||||||
|
{
|
||||||
|
auto arrow = QPainterPath( QPointF( x + -1 * p1.first, p1.second ) );
|
||||||
|
for ( auto p : arrow_offsets )
|
||||||
|
arrow.lineTo( x + -1 * p.first + 1, p.second );
|
||||||
|
painter->drawPath( arrow );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_itemToResize->size < m_itemMaxSize )
|
||||||
|
{
|
||||||
|
auto arrow = QPainterPath( QPointF( x + p1.first, p1.second ) );
|
||||||
|
for ( auto p : arrow_offsets )
|
||||||
|
arrow.lineTo( x + p.first, p.second );
|
||||||
|
painter->drawPath( arrow );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->setRenderHint( QPainter::Antialiasing, false );
|
||||||
|
painter->setPen( Qt::black );
|
||||||
|
painter->drawLine( x, 0, x, h - 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionSplitterWidget::drawPartitions( QPainter* painter,
|
||||||
|
const QRect& rect,
|
||||||
|
const QList< PartitionSplitterItem >& items )
|
||||||
|
{
|
||||||
|
const int count = items.count();
|
||||||
|
const int totalWidth = rect.width();
|
||||||
|
|
||||||
|
qint64 total = 0;
|
||||||
|
for ( int row = 0; row < count; ++row )
|
||||||
|
{
|
||||||
|
total += items[ row ].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = rect.x();
|
||||||
|
for ( int row = 0; row < count; ++row )
|
||||||
|
{
|
||||||
|
const PartitionSplitterItem& item = items[ row ];
|
||||||
|
int width;
|
||||||
|
if ( row < count - 1 )
|
||||||
|
width = totalWidth * ( item.size / static_cast< qreal >( total ) );
|
||||||
|
else
|
||||||
|
// Make sure we fill the last pixel column
|
||||||
|
width = rect.right() - x + 1;
|
||||||
|
|
||||||
|
drawSection( painter, rect, x, width, item );
|
||||||
|
if ( !item.children.isEmpty() )
|
||||||
|
{
|
||||||
|
QRect subRect(
|
||||||
|
x + EXTENDED_PARTITION_MARGIN,
|
||||||
|
rect.y() + EXTENDED_PARTITION_MARGIN,
|
||||||
|
width - 2 * EXTENDED_PARTITION_MARGIN,
|
||||||
|
rect.height() - 2 * EXTENDED_PARTITION_MARGIN
|
||||||
|
);
|
||||||
|
drawPartitions( painter, subRect, item.children );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( item.itemPath == m_itemToResize->itemPath )
|
||||||
|
m_resizeHandleX = x + width;
|
||||||
|
|
||||||
|
x += width;
|
||||||
|
}
|
||||||
|
drawResizeHandle( painter, rect, m_resizeHandleX );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PartitionSplitterItem*
|
||||||
|
PartitionSplitterWidget::_findItem( QList< PartitionSplitterItem >& items,
|
||||||
|
auto condition )
|
||||||
|
{
|
||||||
|
for ( auto it = items.begin(); it != items.end(); ++it)
|
||||||
|
{
|
||||||
|
if ( condition( *it ) )
|
||||||
|
return &*it;
|
||||||
|
|
||||||
|
PartitionSplitterItem* candidate = _findItem( it->children, condition );
|
||||||
|
if ( candidate )
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
88
src/modules/partition/gui/PartitionSplitterWidget.h
Normal file
88
src/modules/partition/gui/PartitionSplitterWidget.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/* === This file is part of Calamares - <http://github.com/calamares> ===
|
||||||
|
*
|
||||||
|
* Copyright 2014, Teo Mrnjavac <teo@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 PARTITIONSPLITTERWIDGET_H
|
||||||
|
#define PARTITIONSPLITTERWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
struct PartitionSplitterItem
|
||||||
|
{
|
||||||
|
QString itemPath;
|
||||||
|
QColor color;
|
||||||
|
bool isFreeSpace;
|
||||||
|
qint64 size;
|
||||||
|
|
||||||
|
QList< PartitionSplitterItem > children;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PartitionSplitterWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PartitionSplitterWidget( QWidget* parent = nullptr );
|
||||||
|
|
||||||
|
void init( const QList< PartitionSplitterItem >& items );
|
||||||
|
|
||||||
|
void setSplitPartition( const QString& path,
|
||||||
|
qint64 minSize,
|
||||||
|
qint64 maxSize,
|
||||||
|
qint64 preferredSize,
|
||||||
|
const QString& newLabel );
|
||||||
|
|
||||||
|
qint64 splitPartitionSize() const;
|
||||||
|
qint64 newPartitionSize() const;
|
||||||
|
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void partitionResized( const QString&, qint64, qint64 );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent( QPaintEvent* event ) override;
|
||||||
|
void mousePressEvent( QMouseEvent* event ) override;
|
||||||
|
void mouseMoveEvent( QMouseEvent* event ) override;
|
||||||
|
void mouseReleaseEvent( QMouseEvent* event ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawPartitions( QPainter* painter,
|
||||||
|
const QRect& rect,
|
||||||
|
const QList< PartitionSplitterItem >& items );
|
||||||
|
void drawSection( QPainter* painter, const QRect& rect_, int x, int width,
|
||||||
|
const PartitionSplitterItem& item );
|
||||||
|
void drawResizeHandle( QPainter* painter,
|
||||||
|
const QRect& rect_,
|
||||||
|
int x );
|
||||||
|
|
||||||
|
PartitionSplitterItem* _findItem( QList< PartitionSplitterItem >& items, auto condition );
|
||||||
|
|
||||||
|
QList< PartitionSplitterItem > m_items;
|
||||||
|
QString m_itemToResizePath;
|
||||||
|
PartitionSplitterItem* m_itemToResize;
|
||||||
|
PartitionSplitterItem* m_itemToResizeNext;
|
||||||
|
|
||||||
|
qint64 m_itemMinSize;
|
||||||
|
qint64 m_itemMaxSize;
|
||||||
|
qint64 m_itemPrefSize;
|
||||||
|
bool m_resizing;
|
||||||
|
int m_resizeHandleX;
|
||||||
|
|
||||||
|
const int HANDLE_SNAP;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PARTITIONSPLITTERWIDGET_H
|
@ -205,9 +205,9 @@ PartitionViewStep::next()
|
|||||||
m_widget->setCurrentWidget( m_alongsidePage );
|
m_widget->setCurrentWidget( m_alongsidePage );
|
||||||
}
|
}
|
||||||
cDebug() << "Choice applied: " << m_choicePage->currentChoice();
|
cDebug() << "Choice applied: " << m_choicePage->currentChoice();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
emit done();
|
||||||
emit done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -231,6 +231,9 @@ PartitionViewStep::isNextEnabled() const
|
|||||||
m_core->hasRootMountPoint();
|
m_core->hasRootMountPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( m_alongsidePage && m_alongsidePage == m_widget->currentWidget() )
|
||||||
|
return m_alongsidePage->isNextEnabled();
|
||||||
|
|
||||||
if ( m_manualPartitionPage && m_manualPartitionPage == m_widget->currentWidget() )
|
if ( m_manualPartitionPage && m_manualPartitionPage == m_widget->currentWidget() )
|
||||||
return m_core->hasRootMountPoint();
|
return m_core->hasRootMountPoint();
|
||||||
|
|
||||||
@ -258,6 +261,16 @@ PartitionViewStep::isAtEnd() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PartitionViewStep::onLeave()
|
||||||
|
{
|
||||||
|
if ( m_widget->currentWidget() == m_alongsidePage )
|
||||||
|
{
|
||||||
|
m_alongsidePage->applyChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QList< Calamares::job_ptr >
|
QList< Calamares::job_ptr >
|
||||||
PartitionViewStep::jobs() const
|
PartitionViewStep::jobs() const
|
||||||
{
|
{
|
||||||
@ -268,6 +281,7 @@ PartitionViewStep::jobs() const
|
|||||||
bool
|
bool
|
||||||
PartitionViewStep::canBeResized( const QString& partitionPath )
|
PartitionViewStep::canBeResized( const QString& partitionPath )
|
||||||
{
|
{
|
||||||
|
//FIXME: check for max partitions count on DOS MBR
|
||||||
cDebug() << "checking if" << partitionPath << "can be resized.";
|
cDebug() << "checking if" << partitionPath << "can be resized.";
|
||||||
QString partitionWithOs = partitionPath;
|
QString partitionWithOs = partitionPath;
|
||||||
if ( partitionWithOs.startsWith( "/dev/" ) )
|
if ( partitionWithOs.startsWith( "/dev/" ) )
|
||||||
|
@ -58,6 +58,8 @@ public:
|
|||||||
bool isAtBeginning() const override;
|
bool isAtBeginning() const override;
|
||||||
bool isAtEnd() const override;
|
bool isAtEnd() const override;
|
||||||
|
|
||||||
|
void onLeave() override;
|
||||||
|
|
||||||
QList< Calamares::job_ptr > jobs() const override;
|
QList< Calamares::job_ptr > jobs() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user