diff --git a/src/modules/partition/CMakeLists.txt b/src/modules/partition/CMakeLists.txt index 626fed8e4..70f1b58f7 100644 --- a/src/modules/partition/CMakeLists.txt +++ b/src/modules/partition/CMakeLists.txt @@ -33,6 +33,7 @@ calamares_add_plugin( partition gui/ChoicePage.cpp gui/CreatePartitionDialog.cpp gui/EditExistingPartitionDialog.cpp + gui/AlongsidePage.cpp gui/EraseDiskPage.cpp gui/PartitionPage.cpp gui/PartitionPreview.cpp diff --git a/src/modules/partition/gui/AlongsidePage.cpp b/src/modules/partition/gui/AlongsidePage.cpp new file mode 100644 index 000000000..aab68d2c3 --- /dev/null +++ b/src/modules/partition/gui/AlongsidePage.cpp @@ -0,0 +1,58 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Teo Mrnjavac + * + * 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 "AlongsidePage.h" + +#include +#include + +AlongsidePage::AlongsidePage( QWidget* parent ) + : QWidget( parent ) + , m_nextEnabled( false ) + , m_core( nullptr ) +{ + QVBoxLayout* mainLayout = new QVBoxLayout; + setLayout( mainLayout ); +} + + +void +AlongsidePage::init( PartitionCoreModule* core , const QStringList& osproberLines ) +{ + QLabel* placeholder = new QLabel( "Alongside partitioning goes here.\nOsprober:\n" + + osproberLines.join( '\n' ) ); + layout()->addWidget( placeholder ); +} + + +bool +AlongsidePage::isNextEnabled() const +{ + return m_nextEnabled; +} + + +void +AlongsidePage::setNextEnabled( bool enabled ) +{ + if ( enabled == m_nextEnabled ) + return; + + m_nextEnabled = enabled; + emit nextStatusChanged( enabled ); +} diff --git a/src/modules/partition/gui/AlongsidePage.h b/src/modules/partition/gui/AlongsidePage.h new file mode 100644 index 000000000..e1306f961 --- /dev/null +++ b/src/modules/partition/gui/AlongsidePage.h @@ -0,0 +1,47 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Teo Mrnjavac + * + * 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 ALONGSIDEPAGE_H +#define ALONGSIDEPAGE_H + +#include + +class PartitionCoreModule; + +class AlongsidePage : public QWidget +{ + Q_OBJECT +public: + explicit AlongsidePage( QWidget* parent = nullptr ); + + void init( PartitionCoreModule* core, const QStringList& osproberLines ); + + bool isNextEnabled() const; + +signals: + void nextStatusChanged( bool ); + +private: + void setNextEnabled( bool enabled ); + + PartitionCoreModule* m_core; + + bool m_nextEnabled; +}; + +#endif // ALONGSIDEPAGE_H diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index eca3b17cc..941cbbd36 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -18,9 +18,18 @@ #include "ChoicePage.h" +#include "core/PartitionCoreModule.h" +#include "core/DeviceModel.h" +#include "core/PartitionModel.h" +#include "core/partition.h" +#include "core/device.h" + +#include "JobQueue.h" +#include "GlobalStorage.h" #include "PrettyRadioButton.h" #include "utils/CalamaresUtilsGui.h" +#include "utils/Logger.h" #include #include @@ -55,6 +64,7 @@ void ChoicePage::init( PartitionCoreModule* core, const QStringList& osproberLines ) { m_core = core; + m_osproberLines = osproberLines; // sample os-prober output: // /dev/sda2:Windows 7 (loader):Windows:chain @@ -75,13 +85,6 @@ ChoicePage::init( PartitionCoreModule* core, const QStringList& osproberLines ) CalamaresUtils::defaultIconSize().height() * 3 ); QButtonGroup* grp = new QButtonGroup( this ); - m_cleanOsproberLines.clear(); - foreach ( const QString& line, osproberLines ) - { - if ( !line.simplified().isEmpty() ) - m_cleanOsproberLines.append( line ); - } - PrettyRadioButton* alongsideButton = new PrettyRadioButton; alongsideButton->setIconSize( iconSize ); alongsideButton->setIcon( CalamaresUtils::defaultPixmap( CalamaresUtils::Information, @@ -99,7 +102,9 @@ ChoicePage::init( PartitionCoreModule* core, const QStringList& osproberLines ) m_itemsLayout->addWidget( alongsideButton ); m_itemsLayout->addWidget( eraseButton ); - if ( m_cleanOsproberLines.count() == 0 ) + cDebug() << "Osprober lines, clean:\n" << m_osproberLines.join( '\n' ); + + if ( m_osproberLines.count() == 0 ) { m_messageLabel->setText( tr( "This computer currently does not seem to have an operating system on it. " "What would you like to do?" ) ); @@ -111,51 +116,57 @@ ChoicePage::init( PartitionCoreModule* core, const QStringList& osproberLines ) alongsideButton->hide(); } - else if ( m_cleanOsproberLines.count() == 1 ) + else if ( m_osproberLines.count() == 1 ) { - QStringList osLine = m_cleanOsproberLines.first().split( ':' ); + QStringList osLine = m_osproberLines.first().split( ':' ); QString osName; if ( !osLine.value( 1 ).simplified().isEmpty() ) osName = osLine.value( 1 ).simplified(); else if ( !osLine.value( 2 ).simplified().isEmpty() ) osName = osLine.value( 2 ).simplified(); - if ( !osName.isEmpty() ) + if ( canBeResized( osLine ) ) { - m_messageLabel->setText( tr( "This computer currently has %1 on it. " - "What would you like to do?" ) - .arg( osName ) ); - - alongsideButton->setText( tr( "Install %2 alongside %1
" - "Documents, music and other personal files will be kept. " - "You can choose which operating system you want each time the " - "computer starts up." ) + + if ( !osName.isEmpty() ) + { + m_messageLabel->setText( tr( "This computer currently has %1 on it. " + "What would you like to do?" ) + .arg( osName ) ); + + alongsideButton->setText( tr( "Install %2 alongside %1
" + "Documents, music and other personal files will be kept. " + "You can choose which operating system you want each time the " + "computer starts up." ) + .arg( osName ) + .arg( "$RELEASE" ) ); + + eraseButton->setText( tr( "Replace %1 with %2
" + "Warning: This will erase the whole disk and " + "delete all of your %1 programs, " + "documents, photos, music, and any other files." ) .arg( osName ) .arg( "$RELEASE" ) ); - - eraseButton->setText( tr( "Replace %1 with %2
" - "Warning: This will erase the whole disk and " - "delete all of your %1 programs, " - "documents, photos, music, and any other files." ) - .arg( osName ) - .arg( "$RELEASE" ) ); - } - else - { - m_messageLabel->setText( tr( "This computer already has an operating system on it. " - "What would you like to do?" ) ); - - alongsideButton->setText( tr( "Install %1 alongside your current operating system
" - "Documents, music and other personal files will be kept. " - "You can choose which operating system you want each time the " - "computer starts up." ) + } + else + { + m_messageLabel->setText( tr( "This computer already has an operating system on it. " + "What would you like to do?" ) ); + + alongsideButton->setText( tr( "Install %1 alongside your current operating system
" + "Documents, music and other personal files will be kept. " + "You can choose which operating system you want each time the " + "computer starts up." ) + .arg( "$RELEASE" ) ); + + eraseButton->setText( tr( "Erase disk and install %1
" + "Warning: This will delete all of your Windows 7 programs, " + "documents, photos, music, and any other files." ) .arg( "$RELEASE" ) ); - - eraseButton->setText( tr( "Erase disk and install %1
" - "Warning: This will delete all of your Windows 7 programs, " - "documents, photos, music, and any other files." ) - .arg( "$RELEASE" ) ); + } } + else + alongsideButton->hide(); } else { @@ -172,6 +183,7 @@ ChoicePage::init( PartitionCoreModule* core, const QStringList& osproberLines ) "Warning: This will delete all of your Windows 7 programs, " "documents, photos, music, and any other files." ) .arg( "$RELEASE" ) ); + alongsideButton->hide(); //FIXME: allow this when we can } m_itemsLayout->addStretch(); @@ -244,3 +256,59 @@ ChoicePage::setNextEnabled( bool enabled ) m_nextEnabled = enabled; emit nextStatusChanged( enabled ); } + + +bool +ChoicePage::canBeResized( const QStringList& osproberLine ) +{ + cDebug() << "checking if" << osproberLine << "can be resized."; + QString partitionWithOs = osproberLine.value( 0 ).simplified(); + if ( partitionWithOs.startsWith( "/dev/" ) ) + { + cDebug() << partitionWithOs << "seems like a good path"; + bool canResize = false; + DeviceModel* dm = m_core->deviceModel(); + for ( int i = 0; i < dm->rowCount(); ++i ) + { + Device* dev = dm->deviceForIndex( dm->index( i ) ); + PartitionModel* pm = m_core->partitionModelForDevice( dev ); + for ( int j = 0; j < pm->rowCount(); ++j ) + { + QModelIndex index = pm->index( j, 0 ); + Partition* candidate = pm->partitionForIndex( index ); + if ( candidate->partitionPath() == partitionWithOs ) + { + cDebug() << "found Partition* for" << partitionWithOs; + bool ok = false; + double requiredStorageGB = Calamares::JobQueue::instance() + ->globalStorage() + ->value( "requiredStorageGB" ) + .toDouble( &ok ); + + qint64 availableStorageB = candidate->available() * dev->logicalSectorSize(); + + // We require a little more for partitioning overhead and swap file + // TODO: maybe make this configurable? + qint64 requiredStorageB = ( requiredStorageGB + 0.1 + 2.0 ) * 1024 * 1024 * 1024; + cDebug() << "Required storage B:" << requiredStorageB; + cDebug() << "Available storage B:" << availableStorageB; + if ( ok && + availableStorageB > requiredStorageB ) + { + canResize = true; + } + } + if ( canResize ) + break; + } + if ( canResize ) + break; + } + + cDebug() << "Partition" << osproberLine << "authorized for resize + autopartition install."; + return canResize; + } + + cDebug() << "Partition" << osproberLine << "CANNOT BE RESIZED FOR AUTOINSTALL."; + return false; +} diff --git a/src/modules/partition/gui/ChoicePage.h b/src/modules/partition/gui/ChoicePage.h index 32a0e07e9..19a1d6d2a 100644 --- a/src/modules/partition/gui/ChoicePage.h +++ b/src/modules/partition/gui/ChoicePage.h @@ -53,12 +53,14 @@ signals: private: void setNextEnabled( bool enabled ); + bool canBeResized( const QStringList& osproberLine ); + bool m_nextEnabled; PartitionCoreModule* m_core; QBoxLayout* m_itemsLayout; QLabel* m_messageLabel; - QStringList m_cleanOsproberLines; + QStringList m_osproberLines; Choice m_choice; }; diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 1a4bf8f75..558472a34 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ PartitionViewStep::PartitionViewStep( QObject* parent ) , m_core( new PartitionCoreModule( this ) ) , m_choicePage( new ChoicePage() ) , m_erasePage( new EraseDiskPage() ) + , m_alongsidePage( new AlongsidePage() ) , m_manualPartitionPage( new PartitionPage( m_core ) ) { m_widget->setContentsMargins( 0, 0, 0, 0 ); @@ -77,10 +79,16 @@ PartitionViewStep::PartitionViewStep( QObject* parent ) osprober.readAllStandardOutput() ).trimmed() ); } - QStringList osproberLines = osproberOutput.split( '\n' ); + QStringList osproberLines; + foreach ( const QString& line, osproberOutput.split( '\n' ) ) + { + if ( !line.simplified().isEmpty() ) + osproberLines.append( line ); + } m_choicePage->init( m_core, osproberLines ); m_erasePage->init( m_core ); + m_alongsidePage->init( m_core, osproberLines ); m_widget->addWidget( m_choicePage ); m_widget->addWidget( m_manualPartitionPage ); @@ -92,12 +100,14 @@ PartitionViewStep::PartitionViewStep( QObject* parent ) } ); timer->start( 0 ); - connect( m_core, &PartitionCoreModule::hasRootMountPointChanged, - this, &PartitionViewStep::nextStatusChanged ); - connect( m_choicePage, &ChoicePage::nextStatusChanged, - this, &PartitionViewStep::nextStatusChanged ); - connect( m_erasePage, &EraseDiskPage::nextStatusChanged, - this, &PartitionViewStep::nextStatusChanged ); + connect( m_core, &PartitionCoreModule::hasRootMountPointChanged, + this, &PartitionViewStep::nextStatusChanged ); + connect( m_choicePage, &ChoicePage::nextStatusChanged, + this, &PartitionViewStep::nextStatusChanged ); + connect( m_erasePage, &EraseDiskPage::nextStatusChanged, + this, &PartitionViewStep::nextStatusChanged ); + connect( m_alongsidePage, &AlongsidePage::nextStatusChanged, + this, &PartitionViewStep::nextStatusChanged ); } @@ -165,6 +175,12 @@ PartitionViewStep::next() m_core->revert(); m_widget->setCurrentWidget( m_erasePage ); } + else if ( m_choicePage->currentChoice() == ChoicePage::Alongside ) + { + if ( m_core->isDirty() ) + m_core->revert(); + m_widget->setCurrentWidget( m_alongsidePage ); + } cDebug() << "Choice applied: " << m_choicePage->currentChoice(); } else diff --git a/src/modules/partition/gui/PartitionViewStep.h b/src/modules/partition/gui/PartitionViewStep.h index ee12e2121..2749c758c 100644 --- a/src/modules/partition/gui/PartitionViewStep.h +++ b/src/modules/partition/gui/PartitionViewStep.h @@ -26,6 +26,7 @@ class ChoicePage; class EraseDiskPage; +class AlongsidePage; class PartitionPage; class PartitionCoreModule; class QStackedWidget; @@ -64,6 +65,7 @@ private: QStackedWidget* m_widget; ChoicePage* m_choicePage; EraseDiskPage* m_erasePage; + AlongsidePage* m_alongsidePage; PartitionPage* m_manualPartitionPage; };