2017-12-20 14:39:09 +01:00
/* === This file is part of Calamares - <https://github.com/calamares> ===
2014-06-11 13:37:10 +02:00
*
2019-04-16 18:20:39 +02:00
* Copyright 2019 , Dominic Hayes < ferenosdev @ outlook . com >
2019-04-16 19:27:51 +02:00
* Copyright 2019 , Gabriel Craciunescu < crazy @ frugalware . org >
2015-01-28 15:24:32 +01:00
* Copyright 2014 - 2015 , Teo Mrnjavac < teo @ kde . org >
2018-01-02 13:59:38 +01:00
* Copyright 2017 - 2018 , Adriaan de Groot < groot @ kde . org >
2014-06-11 13:37:10 +02:00
*
* 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 "ViewManager.h"
2014-08-01 17:00:21 +02:00
# include "utils/Logger.h"
2018-06-13 11:11:31 +02:00
# include "viewpages/BlankViewStep.h"
2014-07-01 11:49:09 +02:00
# include "viewpages/ViewStep.h"
2015-09-09 19:05:20 +02:00
# include "ExecutionViewStep.h"
2014-07-08 17:04:39 +02:00
# include "JobQueue.h"
2015-04-08 18:40:43 +02:00
# include "utils/Retranslator.h"
2015-04-10 12:41:10 +02:00
# include "Branding.h"
# include "Settings.h"
2014-07-01 11:49:09 +02:00
2014-06-24 15:31:11 +02:00
# include <QApplication>
2014-06-11 13:37:10 +02:00
# include <QBoxLayout>
2014-07-10 14:46:08 +02:00
# include <QMessageBox>
2015-09-09 19:05:20 +02:00
# include <QMetaObject>
2014-06-11 13:37:10 +02:00
namespace Calamares
{
2014-06-27 15:21:16 +02:00
ViewManager * ViewManager : : s_instance = nullptr ;
2014-06-11 13:37:10 +02:00
ViewManager *
ViewManager : : instance ( )
{
return s_instance ;
}
2017-06-27 12:46:59 +02:00
ViewManager *
ViewManager : : instance ( QObject * parent )
{
Q_ASSERT ( ! s_instance ) ;
s_instance = new ViewManager ( parent ) ;
return s_instance ;
}
2014-06-11 13:37:10 +02:00
ViewManager : : ViewManager ( QObject * parent )
: QObject ( parent )
2014-06-27 18:00:27 +02:00
, m_currentStep ( 0 )
2017-06-28 13:48:51 +02:00
, m_widget ( new QWidget ( ) )
2014-06-11 13:37:10 +02:00
{
2015-09-09 19:05:20 +02:00
Q_ASSERT ( ! s_instance ) ;
2014-06-11 13:37:10 +02:00
QBoxLayout * mainLayout = new QVBoxLayout ;
m_widget - > setLayout ( mainLayout ) ;
m_stack = new QStackedWidget ( m_widget ) ;
2014-06-12 10:56:13 +02:00
m_stack - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2014-06-11 13:37:10 +02:00
mainLayout - > addWidget ( m_stack ) ;
2015-04-08 18:40:43 +02:00
m_back = new QPushButton ( m_widget ) ;
m_next = new QPushButton ( m_widget ) ;
m_quit = new QPushButton ( m_widget ) ;
CALAMARES_RETRANSLATE (
m_back - > setText ( tr ( " &Back " ) ) ;
m_next - > setText ( tr ( " &Next " ) ) ;
m_quit - > setText ( tr ( " &Cancel " ) ) ;
2019-04-01 12:16:13 +02:00
QString tooltip = Calamares : : Settings : : instance ( ) - > isSetupMode ( )
? tr ( " Cancel setup without changing the system. " )
: tr ( " Cancel installation without changing the system. " ) ;
m_quit - > setToolTip ( tooltip ) ;
2015-04-08 18:40:43 +02:00
)
2014-06-11 13:37:10 +02:00
QBoxLayout * bottomLayout = new QHBoxLayout ;
mainLayout - > addLayout ( bottomLayout ) ;
bottomLayout - > addStretch ( ) ;
bottomLayout - > addWidget ( m_back ) ;
bottomLayout - > addWidget ( m_next ) ;
2014-06-24 15:31:11 +02:00
bottomLayout - > addSpacing ( 12 ) ;
bottomLayout - > addWidget ( m_quit ) ;
2014-06-27 18:00:27 +02:00
2015-06-29 10:48:50 +02:00
connect ( m_next , & QPushButton : : clicked , this , & ViewManager : : next ) ;
connect ( m_back , & QPushButton : : clicked , this , & ViewManager : : back ) ;
m_back - > setEnabled ( false ) ;
2018-01-02 13:59:38 +01:00
connect ( m_quit , & QPushButton : : clicked , this ,
[ this ] ( ) { if ( this - > confirmCancelInstallation ( ) ) qApp - > quit ( ) ; } ) ;
2015-09-09 19:05:20 +02:00
connect ( JobQueue : : instance ( ) , & JobQueue : : failed ,
this , & ViewManager : : onInstallationFailed ) ;
connect ( JobQueue : : instance ( ) , & JobQueue : : finished ,
this , & ViewManager : : next ) ;
2019-01-23 15:56:07 +01:00
if ( Calamares : : Settings : : instance ( ) - > disableCancel ( ) )
m_quit - > setVisible ( false ) ;
2014-06-11 13:37:10 +02:00
}
ViewManager : : ~ ViewManager ( )
{
m_widget - > deleteLater ( ) ;
2018-01-17 15:16:47 +01:00
s_instance = nullptr ;
2014-06-11 13:37:10 +02:00
}
QWidget *
2014-06-27 18:00:27 +02:00
ViewManager : : centralWidget ( )
2014-06-11 13:37:10 +02:00
{
return m_widget ;
}
2014-06-12 10:56:13 +02:00
void
2014-06-27 18:00:27 +02:00
ViewManager : : addViewStep ( ViewStep * step )
2014-06-12 10:56:13 +02:00
{
2015-01-29 20:36:45 +01:00
insertViewStep ( m_steps . size ( ) , step ) ;
2015-09-09 19:05:20 +02:00
// If this is the first inserted view step, update status of "Next" button
if ( m_steps . count ( ) = = 1 )
m_next - > setEnabled ( step - > isNextEnabled ( ) ) ;
2014-07-08 15:23:30 +02:00
}
void
2017-09-05 14:18:23 +02:00
ViewManager : : insertViewStep ( int before , ViewStep * step )
2014-07-08 15:23:30 +02:00
{
m_steps . insert ( before , step ) ;
2014-07-02 16:38:57 +02:00
QLayout * layout = step - > widget ( ) - > layout ( ) ;
if ( layout )
layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2014-07-08 15:23:30 +02:00
m_stack - > insertWidget ( before , step - > widget ( ) ) ;
2014-06-12 10:56:13 +02:00
2017-09-05 14:18:23 +02:00
connect ( step , & ViewStep : : enlarge , this , & ViewManager : : enlarge ) ;
2014-06-27 18:00:27 +02:00
connect ( step , & ViewStep : : nextStatusChanged ,
2014-09-01 12:44:36 +02:00
this , [ this ] ( bool status )
{
ViewStep * vs = qobject_cast < ViewStep * > ( sender ( ) ) ;
if ( vs )
{
if ( vs = = m_steps . at ( m_currentStep ) )
m_next - > setEnabled ( status ) ;
}
} ) ;
2014-07-01 17:45:28 +02:00
2014-07-08 15:23:30 +02:00
m_stack - > setCurrentIndex ( 0 ) ;
2014-11-10 12:24:44 +01:00
step - > widget ( ) - > setFocus ( ) ;
2014-07-01 17:45:28 +02:00
}
2014-07-12 14:38:33 +02:00
void
ViewManager : : onInstallationFailed ( const QString & message , const QString & details )
{
2018-03-28 15:31:45 +02:00
cError ( ) < < " Installation failed: " ;
cDebug ( ) < < " - message: " < < message ;
cDebug ( ) < < " - details: " < < details ;
2014-08-01 17:00:21 +02:00
2019-04-01 12:16:13 +02:00
QString heading = Calamares : : Settings : : instance ( ) - > isSetupMode ( )
? tr ( " Setup Failed " )
: tr ( " Installation Failed " ) ;
2017-07-04 14:14:30 +02:00
QMessageBox * msgBox = new QMessageBox ( ) ;
msgBox - > setIcon ( QMessageBox : : Critical ) ;
2017-09-05 14:18:23 +02:00
msgBox - > setWindowTitle ( tr ( " Error " ) ) ;
2019-04-01 12:16:13 +02:00
msgBox - > setText ( " <strong> " + heading + " </strong> " ) ;
2017-07-04 14:14:30 +02:00
msgBox - > setStandardButtons ( QMessageBox : : Close ) ;
msgBox - > button ( QMessageBox : : Close ) - > setText ( tr ( " &Close " ) ) ;
2014-07-12 14:38:33 +02:00
2014-08-01 09:56:40 +02:00
QString text = " <p> " + message + " </p> " ;
2014-07-12 14:38:33 +02:00
if ( ! details . isEmpty ( ) )
2014-08-01 09:56:40 +02:00
text + = " <p> " + details + " </p> " ;
2017-07-04 14:14:30 +02:00
msgBox - > setInformativeText ( text ) ;
2014-07-12 14:38:33 +02:00
2017-09-05 14:18:23 +02:00
connect ( msgBox , & QMessageBox : : buttonClicked , qApp , & QApplication : : quit ) ;
2018-03-28 15:31:45 +02:00
cDebug ( ) < < " Calamares will quit when the dialog closes. " ;
2017-07-04 14:14:30 +02:00
msgBox - > show ( ) ;
2014-07-08 15:23:30 +02:00
}
2018-06-13 11:11:31 +02:00
void
ViewManager : : onInitFailed ( const QStringList & modules )
{
2019-04-01 12:16:13 +02:00
// Because this means the installer / setup program is broken by the distributor,
// don't bother being precise about installer / setup wording.
2018-06-13 11:11:31 +02:00
QString title ( tr ( " Calamares Initialization Failed " ) ) ;
2018-06-14 08:48:52 +02:00
QString description ( tr ( " %1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution. " ) ) ;
QString detailString ;
if ( modules . count ( ) > 0 )
{
description . append ( tr ( " <br/>The following modules could not be loaded: " ) ) ;
QStringList details ;
details < < QLatin1Literal ( " <ul> " ) ;
for ( const auto & m : modules )
details < < QLatin1Literal ( " <li> " ) < < m < < QLatin1Literal ( " </li> " ) ;
details < < QLatin1Literal ( " </ul> " ) ;
detailString = details . join ( QString ( ) ) ;
}
2018-09-24 17:58:22 +02:00
insertViewStep ( 0 , new BlankViewStep ( title , description . arg ( * Calamares : : Branding : : ProductName ) , detailString ) ) ;
2018-06-13 11:11:31 +02:00
}
2015-09-09 19:05:20 +02:00
ViewStepList
ViewManager : : viewSteps ( ) const
2014-07-08 15:23:30 +02:00
{
2015-09-09 19:05:20 +02:00
return m_steps ;
2014-07-01 17:45:28 +02:00
}
ViewStep *
ViewManager : : currentStep ( ) const
{
return m_steps . value ( m_currentStep ) ;
}
int
ViewManager : : currentStepIndex ( ) const
{
return m_currentStep ;
2014-06-12 10:56:13 +02:00
}
2018-02-13 14:11:11 +01:00
static inline bool
stepNextWillExecute ( const ViewStepList & steps , int index )
{
return ( index + 1 < steps . count ( ) ) & & qobject_cast < ExecutionViewStep * > ( steps . at ( index + 1 ) ) ;
}
2014-06-12 10:56:13 +02:00
2014-06-11 13:37:10 +02:00
void
ViewManager : : next ( )
{
2014-06-27 18:00:27 +02:00
ViewStep * step = m_steps . at ( m_currentStep ) ;
2015-09-09 19:05:20 +02:00
bool executing = false ;
2014-07-08 15:23:30 +02:00
if ( step - > isAtEnd ( ) )
2014-06-27 18:00:27 +02:00
{
2019-04-22 00:18:28 +02:00
const auto * const settings = Calamares : : Settings : : instance ( ) ;
2019-04-21 17:32:05 +02:00
2015-09-09 19:05:20 +02:00
// Special case when the user clicks next on the very last page in a view phase
// and right before switching to an execution phase.
2015-04-10 12:41:10 +02:00
// Depending on Calamares::Settings, we show an "are you sure" prompt or not.
2019-04-21 17:32:05 +02:00
if ( settings - > showPromptBeforeExecution ( ) & & stepNextWillExecute ( m_steps , m_currentStep ) )
2015-04-10 12:41:10 +02:00
{
2019-04-21 17:32:05 +02:00
QString title = settings - > isSetupMode ( )
2019-04-01 12:16:13 +02:00
? tr ( " Continue with setup? " )
: tr ( " Continue with installation? " ) ;
2019-04-21 17:32:05 +02:00
QString question = settings - > isSetupMode ( )
2019-04-01 12:16:13 +02:00
? tr ( " The %1 setup program is about to make changes to your "
" disk in order to set up %2.<br/><strong>You will not be able "
" to undo these changes.</strong> " )
: tr ( " The %1 installer is about to make changes to your "
" disk in order to install %2.<br/><strong>You will not be able "
" to undo these changes.</strong> " ) ;
2019-04-21 17:32:05 +02:00
QString confirm = settings - > isSetupMode ( )
2019-04-01 12:16:13 +02:00
? tr ( " &Set up now " )
: tr ( " &Install now " ) ;
2015-04-10 12:41:10 +02:00
int reply =
QMessageBox : : question ( m_widget ,
2019-04-01 12:16:13 +02:00
title ,
question . arg ( * Calamares : : Branding : : ShortProductName , * Calamares : : Branding : : ShortVersionedName ) ,
confirm ,
2015-04-10 12:41:10 +02:00
tr ( " Go &back " ) ,
QString ( ) ,
0 ,
1 ) ;
if ( reply = = 1 )
return ;
}
2014-06-27 18:00:27 +02:00
m_currentStep + + ;
m_stack - > setCurrentIndex ( m_currentStep ) ;
2014-07-08 18:24:39 +02:00
step - > onLeave ( ) ;
m_steps . at ( m_currentStep ) - > onActivate ( ) ;
2015-09-09 19:05:20 +02:00
executing = qobject_cast < ExecutionViewStep * > ( m_steps . at ( m_currentStep ) ) ! = nullptr ;
2014-07-01 17:45:28 +02:00
emit currentStepChanged ( ) ;
2015-09-09 19:05:20 +02:00
if ( executing )
2014-07-08 17:04:39 +02:00
{
2015-01-29 20:36:45 +01:00
m_back - > setEnabled ( false ) ;
m_next - > setEnabled ( false ) ;
2019-04-21 17:32:05 +02:00
// Enabled if there's nothing blocking it during exec
m_quit - > setEnabled ( ! ( settings - > dontCancel ( ) | | settings - > disableCancel ( ) ) ) ;
2014-07-08 17:04:39 +02:00
}
2019-04-21 17:32:05 +02:00
else
// Enabled unless it's also hidden
m_quit - > setEnabled ( ! settings - > disableCancel ( ) ) ;
2014-06-27 18:00:27 +02:00
}
2014-07-08 15:23:30 +02:00
else
2014-06-27 18:00:27 +02:00
step - > next ( ) ;
2015-09-09 19:05:20 +02:00
m_next - > setEnabled ( ! executing & & m_steps . at ( m_currentStep ) - > isNextEnabled ( ) ) ;
m_back - > setEnabled ( ! executing & & m_steps . at ( m_currentStep ) - > isBackEnabled ( ) ) ;
2015-01-28 15:24:32 +01:00
2018-02-13 14:11:11 +01:00
updateButtonLabels ( ) ;
}
void
ViewManager : : updateButtonLabels ( )
{
2019-04-01 12:16:13 +02:00
QString next = Calamares : : Settings : : instance ( ) - > isSetupMode ( )
? tr ( " &Set up " )
: tr ( " &Install " ) ;
QString complete = Calamares : : Settings : : instance ( ) - > isSetupMode ( )
? tr ( " Setup is complete. Close the setup program. " )
: tr ( " The installation is complete. Close the installer. " ) ;
QString quit = Calamares : : Settings : : instance ( ) - > isSetupMode ( )
? tr ( " Cancel setup without changing the system. " )
: tr ( " Cancel installation without changing the system. " ) ;
2018-02-13 14:11:11 +01:00
if ( stepNextWillExecute ( m_steps , m_currentStep ) )
2019-04-01 12:16:13 +02:00
m_next - > setText ( next ) ;
2018-02-13 14:11:11 +01:00
else
m_next - > setText ( tr ( " &Next " ) ) ;
if ( m_currentStep = = m_steps . count ( ) - 1 & & m_steps . last ( ) - > isAtEnd ( ) )
2015-11-20 17:39:08 +01:00
{
2017-06-28 13:48:51 +02:00
m_quit - > setText ( tr ( " &Done " ) ) ;
2019-04-01 12:16:13 +02:00
m_quit - > setToolTip ( complete ) ;
2019-04-21 17:32:05 +02:00
m_quit - > setVisible ( true ) ; // At end, always visible and enabled.
m_quit - > setEnabled ( true ) ;
2015-11-20 17:39:08 +01:00
}
2018-02-13 14:11:11 +01:00
else
{
2019-04-21 17:32:05 +02:00
if ( Calamares : : Settings : : instance ( ) - > disableCancel ( ) )
{
2019-01-23 15:56:07 +01:00
m_quit - > setVisible ( false ) ;
2019-04-21 17:32:05 +02:00
m_quit - > setEnabled ( false ) ; // Can't be triggered through DBUS
}
2018-02-13 14:11:11 +01:00
m_quit - > setText ( tr ( " &Cancel " ) ) ;
2019-04-01 12:16:13 +02:00
m_quit - > setToolTip ( quit ) ;
2018-02-13 14:11:11 +01:00
}
2014-06-11 13:37:10 +02:00
}
void
ViewManager : : back ( )
{
2014-06-27 18:00:27 +02:00
ViewStep * step = m_steps . at ( m_currentStep ) ;
if ( step - > isAtBeginning ( ) & & m_currentStep > 0 )
{
m_currentStep - - ;
m_stack - > setCurrentIndex ( m_currentStep ) ;
2014-07-08 18:24:39 +02:00
step - > onLeave ( ) ;
m_steps . at ( m_currentStep ) - > onActivate ( ) ;
2014-07-01 17:45:28 +02:00
emit currentStepChanged ( ) ;
2014-06-27 18:00:27 +02:00
}
else if ( ! step - > isAtBeginning ( ) )
step - > back ( ) ;
else return ;
2014-06-27 18:18:36 +02:00
m_next - > setEnabled ( m_steps . at ( m_currentStep ) - > isNextEnabled ( ) ) ;
2015-01-29 20:36:45 +01:00
m_back - > setEnabled ( m_steps . at ( m_currentStep ) - > isBackEnabled ( ) ) ;
2014-06-27 18:00:27 +02:00
if ( m_currentStep = = 0 & & m_steps . first ( ) - > isAtBeginning ( ) )
m_back - > setEnabled ( false ) ;
2015-01-28 15:24:32 +01:00
2018-02-13 14:11:11 +01:00
updateButtonLabels ( ) ;
2014-06-11 13:37:10 +02:00
}
2018-01-02 13:59:38 +01:00
bool ViewManager : : confirmCancelInstallation ( )
{
// If it's NOT the last page of the last step, we ask for confirmation
if ( ! ( m_currentStep = = m_steps . count ( ) - 1 & &
m_steps . last ( ) - > isAtEnd ( ) ) )
{
2019-04-01 12:16:13 +02:00
QString title = Calamares : : Settings : : instance ( ) - > isSetupMode ( )
? tr ( " Cancel setup? " )
: tr ( " Cancel installation? " ) ;
QString question = Calamares : : Settings : : instance ( ) - > isSetupMode ( )
? tr ( " Do you really want to cancel the current setup process? \n "
" The setup program will quit and all changes will be lost. " )
: tr ( " Do you really want to cancel the current install process? \n "
" The installer will quit and all changes will be lost. " ) ;
2018-01-02 13:59:38 +01:00
QMessageBox mb ( QMessageBox : : Question ,
2019-04-01 12:16:13 +02:00
title ,
question ,
2018-01-02 13:59:38 +01:00
QMessageBox : : Yes | QMessageBox : : No ,
m_widget ) ;
mb . setDefaultButton ( QMessageBox : : No ) ;
mb . button ( QMessageBox : : Yes ) - > setText ( tr ( " &Yes " ) ) ;
mb . button ( QMessageBox : : No ) - > setText ( tr ( " &No " ) ) ;
int response = mb . exec ( ) ;
return response = = QMessageBox : : Yes ;
}
else // Means we're at the end, no need to confirm.
return true ;
2014-06-11 13:37:10 +02:00
}
2018-01-02 13:59:38 +01:00
} // namespace