diff --git a/src/modules/partition/CMakeLists.txt b/src/modules/partition/CMakeLists.txt index e980fb578..83f360992 100644 --- a/src/modules/partition/CMakeLists.txt +++ b/src/modules/partition/CMakeLists.txt @@ -17,6 +17,7 @@ add_definitions( -DCALAMARES ) add_subdirectory( tests ) include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) + calamares_add_plugin( partition TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO @@ -29,12 +30,14 @@ calamares_add_plugin( partition core/PartitionIterator.cpp core/PartitionModel.cpp core/PMUtils.cpp + gui/ChoicePage.cpp gui/CreatePartitionDialog.cpp gui/EditExistingPartitionDialog.cpp gui/PartitionPage.cpp gui/PartitionPreview.cpp gui/PartitionSizeController.cpp gui/PartitionViewStep.cpp + gui/PrettyRadioButton.cpp jobs/CheckFileSystemJob.cpp jobs/CreatePartitionJob.cpp jobs/CreatePartitionTableJob.cpp diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp new file mode 100644 index 000000000..eca3b17cc --- /dev/null +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -0,0 +1,246 @@ +/* === 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 "ChoicePage.h" + +#include "PrettyRadioButton.h" + +#include "utils/CalamaresUtilsGui.h" + +#include +#include +#include + +ChoicePage::ChoicePage( QWidget* parent ) + : QWidget( parent ) + , m_choice( NoChoice ) + , m_nextEnabled( false ) +{ + QBoxLayout* mainLayout = new QVBoxLayout; + setLayout( mainLayout ); + + m_messageLabel = new QLabel; + m_messageLabel->setWordWrap( true ); + + m_itemsLayout = new QVBoxLayout; + CalamaresUtils::unmarginLayout( m_itemsLayout ); + + mainLayout->addSpacing( CalamaresUtils::defaultFontHeight() ); + mainLayout->addWidget( m_messageLabel ); + mainLayout->addLayout( m_itemsLayout ); + mainLayout->addStretch(); +} + + +ChoicePage::~ChoicePage() +{} + + +void +ChoicePage::init( PartitionCoreModule* core, const QStringList& osproberLines ) +{ + m_core = core; + + // sample os-prober output: + // /dev/sda2:Windows 7 (loader):Windows:chain + // /dev/sda6::Arch:linux + // + // There are three possibilities we have to consider: + // - There are no operating systems present + // - There is one operating system present + // - There are multiple operating systems present + // + // There are three outcomes we have to provide: + // 1) Wipe+autopartition + // 2) Resize+autopartition + // 3) Manual + // TBD: upgrade option? + + QSize iconSize( CalamaresUtils::defaultIconSize().width() * 3, + 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, + CalamaresUtils::Original, + iconSize ) ); + grp->addButton( alongsideButton->buttonWidget() ); + + PrettyRadioButton* eraseButton = new PrettyRadioButton; + eraseButton->setIconSize( iconSize ); + eraseButton->setIcon( CalamaresUtils::defaultPixmap( CalamaresUtils::Magic, + CalamaresUtils::Original, + iconSize ) ); + grp->addButton( eraseButton->buttonWidget() ); + + m_itemsLayout->addWidget( alongsideButton ); + m_itemsLayout->addWidget( eraseButton ); + + if ( m_cleanOsproberLines.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?" ) ); + + eraseButton->setText( tr( "Erase disk and install %1
" + "Warning: This will delete all of your programs, " + "documents, photos, music, and any other files." ) + .arg( "$RELEASE" ) ); + + alongsideButton->hide(); + } + else if ( m_cleanOsproberLines.count() == 1 ) + { + QStringList osLine = m_cleanOsproberLines.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() ) + { + 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" ) ); + } + 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" ) ); + } + } + else + { + m_messageLabel->setText( tr( "This computer currently has multiple operating systems on it. " + "What would you like to do?" ) ); + + alongsideButton->setText( tr( "Install %1 alongside your current operating systems
" + "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" ) ); + } + + m_itemsLayout->addStretch(); + + QFrame* hLine = new QFrame; + hLine->setFrameStyle( QFrame::HLine ); + m_itemsLayout->addWidget( hLine ); + + m_itemsLayout->addStretch(); + + PrettyRadioButton* somethingElseButton = new PrettyRadioButton; + somethingElseButton->setText( tr( "Something else
" + "You can create or resize partitions yourself, or choose " + "multiple partitions for %1." ) + .arg( "$RELEASE" ) ); + somethingElseButton->setIconSize( iconSize ); + somethingElseButton->setIcon( CalamaresUtils::defaultPixmap( CalamaresUtils::Partitions, + CalamaresUtils::Original, + iconSize ) ); + m_itemsLayout->addWidget( somethingElseButton ); + grp->addButton( somethingElseButton->buttonWidget() ); + + + connect( alongsideButton->buttonWidget(), &QRadioButton::toggled, + this, [ this ]( bool checked ) + { + if ( checked ) + m_choice = Alongside; + setNextEnabled( true ); + } ); + + connect( eraseButton->buttonWidget(), &QRadioButton::toggled, + this, [ this ]( bool checked ) + { + if ( checked ) + m_choice = Erase; + setNextEnabled( true ); + } ); + + connect( somethingElseButton->buttonWidget(), &QRadioButton::toggled, + this, [ this ]( bool checked ) + { + if ( checked ) + m_choice = Manual; + setNextEnabled( true ); + } ); +} + + +bool +ChoicePage::isNextEnabled() +{ + return m_nextEnabled; +} + + +ChoicePage::Choice +ChoicePage::currentChoice() +{ + return m_choice; +} + + +void +ChoicePage::setNextEnabled( bool enabled ) +{ + if ( enabled == m_nextEnabled ) + return; + + m_nextEnabled = enabled; + emit nextStatusChanged( enabled ); +} diff --git a/src/modules/partition/gui/ChoicePage.h b/src/modules/partition/gui/ChoicePage.h new file mode 100644 index 000000000..600f0d101 --- /dev/null +++ b/src/modules/partition/gui/ChoicePage.h @@ -0,0 +1,65 @@ +/* === 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 CHOICEPAGE_H +#define CHOICEPAGE_H + +#include + +class QBoxLayout; +class QLabel; + +class PartitionCoreModule; + +class ChoicePage : public QWidget +{ + Q_OBJECT +public: + enum Choice + { + NoChoice, + Alongside, + Erase, + Manual + }; + + explicit ChoicePage( QWidget* parent = nullptr ); + virtual ~ChoicePage(); + + void init( PartitionCoreModule* core, const QStringList& osproberLines ); + + bool isNextEnabled(); + + Choice currentChoice(); + +signals: + void nextStatusChanged( bool enabled ); + +private: + void setNextEnabled( bool enabled ); + + bool m_nextEnabled; + PartitionCoreModule* m_core; + QBoxLayout* m_itemsLayout; + QLabel* m_messageLabel; + + QStringList m_cleanOsproberLines; + Choice m_choice; +}; + +#endif // CHOICEPAGE_H diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 372873516..55cb4adbb 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -21,20 +21,86 @@ #include #include #include +#include #include #include +#include "CalamaresVersion.h" +#include "utils/CalamaresUtilsGui.h" +#include "utils/Logger.h" +#include "widgets/WaitingWidget.h" + // Qt +#include #include #include +#include +#include +#include PartitionViewStep::PartitionViewStep( QObject* parent ) : Calamares::ViewStep( parent ) + , m_widget( new QStackedWidget() ) , m_core( new PartitionCoreModule( this ) ) - , m_page( new PartitionPage( m_core ) ) + , m_choicePage( new ChoicePage() ) + , m_manualPartitionPage( new PartitionPage( m_core ) ) { - connect( m_core, SIGNAL( hasRootMountPointChanged( bool ) ), - SIGNAL( nextStatusChanged( bool ) ) ); + m_widget->setContentsMargins( 0, 0, 0, 0 ); + + QWidget* waitingWidget = new WaitingWidget( tr( "Gathering system information..." ) ); + m_widget->addWidget( waitingWidget ); + + QTimer* timer = new QTimer; + timer->setSingleShot( true ); + connect( timer, &QTimer::timeout, + [=]() + { + QString osproberOutput; + QProcess osprober; + osprober.setProgram( "os-prober" ); + osprober.setProcessChannelMode( QProcess::SeparateChannels ); + osprober.start(); + if ( !osprober.waitForStarted() ) + { + cDebug() << "ERROR: os-prober cannot start."; + } + else if ( !osprober.waitForFinished( 60000 ) ) + { + cDebug() << "ERROR: os-prober timed out."; + } + else + { + osproberOutput.append( + QString::fromLocal8Bit( + osprober.readAllStandardOutput() ).trimmed() ); + } + + QStringList osproberLines = osproberOutput.split( '\n' ); + + m_choicePage->init( m_core, osproberLines ); + + m_widget->addWidget( m_choicePage ); + m_widget->addWidget( m_manualPartitionPage ); + m_widget->removeWidget( waitingWidget ); + waitingWidget->deleteLater(); + + timer->deleteLater(); + } ); + timer->start( 0 ); + + connect( m_core, &PartitionCoreModule::hasRootMountPointChanged, + this, &PartitionViewStep::nextStatusChanged ); + connect( m_choicePage, &ChoicePage::nextStatusChanged, + this, &PartitionViewStep::nextStatusChanged ); +} + + +PartitionViewStep::~PartitionViewStep() +{ + if ( m_choicePage && m_choicePage->parent() == nullptr ) + m_choicePage->deleteLater(); + if ( m_manualPartitionPage && m_manualPartitionPage->parent() == nullptr ) + m_manualPartitionPage->deleteLater(); } @@ -48,7 +114,7 @@ PartitionViewStep::prettyName() const QWidget* PartitionViewStep::widget() { - return m_page; + return m_widget; } @@ -79,21 +145,34 @@ PartitionViewStep::createSummaryWidget() const return widget; } + void PartitionViewStep::next() { - emit done(); + if ( m_choicePage == m_widget->currentWidget() ) + { + m_widget->setCurrentWidget( m_manualPartitionPage ); + cDebug() << "Choice applied: " << m_choicePage->currentChoice(); + } + else + emit done(); } void PartitionViewStep::back() -{} +{ + if ( m_widget->currentWidget() != m_choicePage ) + m_widget->setCurrentWidget( m_choicePage ); +} bool PartitionViewStep::isNextEnabled() const { + if ( m_choicePage && m_choicePage == m_widget->currentWidget() ) + return m_choicePage->isNextEnabled(); + return m_core->hasRootMountPoint(); } @@ -101,6 +180,8 @@ PartitionViewStep::isNextEnabled() const bool PartitionViewStep::isAtBeginning() const { + if ( m_widget->currentWidget() == m_manualPartitionPage ) + return false; return true; } @@ -108,6 +189,8 @@ PartitionViewStep::isAtBeginning() const bool PartitionViewStep::isAtEnd() const { + if ( m_choicePage == m_widget->currentWidget() ) + return false; return true; } diff --git a/src/modules/partition/gui/PartitionViewStep.h b/src/modules/partition/gui/PartitionViewStep.h index 9e1eae808..768b98eab 100644 --- a/src/modules/partition/gui/PartitionViewStep.h +++ b/src/modules/partition/gui/PartitionViewStep.h @@ -24,8 +24,10 @@ #include "viewpages/ViewStep.h" #include "PluginDllMacro.h" +class ChoicePage; class PartitionPage; class PartitionCoreModule; +class QStackedWidget; /** * The starting point of the module. Instantiates PartitionCoreModule and @@ -39,6 +41,7 @@ class PLUGINDLLEXPORT PartitionViewStep : public Calamares::ViewStep public: explicit PartitionViewStep( QObject* parent = 0 ); + virtual ~PartitionViewStep(); QString prettyName() const override; QWidget* createSummaryWidget() const override; @@ -57,7 +60,9 @@ public: private: PartitionCoreModule* m_core; - PartitionPage* m_page; + QStackedWidget* m_widget; + ChoicePage* m_choicePage; + PartitionPage* m_manualPartitionPage; }; #endif // PARTITIONVIEWSTEP_H