source: calamares/trunk/fuentes/src/libcalamaresui/ViewManager.cpp @ 7538

Last change on this file since 7538 was 7538, checked in by kbut, 17 months ago

sync with github

File size: 10.4 KB
Line 
1/* === This file is part of Calamares - <https://github.com/calamares> ===
2 *
3 *   Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
4 *   Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
5 *
6 *   Calamares is free software: you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation, either version 3 of the License, or
9 *   (at your option) any later version.
10 *
11 *   Calamares is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *   GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with Calamares. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "ViewManager.h"
21
22#include "utils/Logger.h"
23#include "viewpages/BlankViewStep.h"
24#include "viewpages/ViewStep.h"
25#include "ExecutionViewStep.h"
26#include "JobQueue.h"
27#include "utils/Retranslator.h"
28#include "Branding.h"
29#include "Settings.h"
30
31#include <QApplication>
32#include <QBoxLayout>
33#include <QMessageBox>
34#include <QMetaObject>
35
36namespace Calamares
37{
38
39ViewManager* ViewManager::s_instance = nullptr;
40
41ViewManager*
42ViewManager::instance()
43{
44    return s_instance;
45}
46
47ViewManager*
48ViewManager::instance( QObject* parent )
49{
50    Q_ASSERT( !s_instance );
51    s_instance = new ViewManager( parent );
52    return s_instance;
53}
54
55ViewManager::ViewManager( QObject* parent )
56    : QObject( parent )
57    , m_currentStep( 0 )
58    , m_widget( new QWidget() )
59{
60    Q_ASSERT( !s_instance );
61
62    QBoxLayout* mainLayout = new QVBoxLayout;
63    m_widget->setLayout( mainLayout );
64
65    m_stack = new QStackedWidget( m_widget );
66    m_stack->setContentsMargins( 0, 0, 0, 0 );
67    mainLayout->addWidget( m_stack );
68
69    m_back = new QPushButton( m_widget );
70    m_next = new QPushButton( m_widget );
71    m_quit = new QPushButton( m_widget );
72
73    CALAMARES_RETRANSLATE(
74        m_back->setText( tr( "&Back" ) );
75        m_next->setText( tr( "&Next" ) );
76        m_quit->setText( tr( "&Cancel" ) );
77        m_quit->setToolTip( tr( "Cancel installation without changing the system." ) );
78    )
79
80    QBoxLayout* bottomLayout = new QHBoxLayout;
81    mainLayout->addLayout( bottomLayout );
82    bottomLayout->addStretch();
83    bottomLayout->addWidget( m_back );
84    bottomLayout->addWidget( m_next );
85    bottomLayout->addSpacing( 12 );
86    bottomLayout->addWidget( m_quit );
87
88    connect( m_next, &QPushButton::clicked, this, &ViewManager::next );
89    connect( m_back, &QPushButton::clicked, this, &ViewManager::back );
90    m_back->setEnabled( false );
91
92    connect( m_quit, &QPushButton::clicked, this,
93             [this]() { if ( this->confirmCancelInstallation() ) qApp->quit(); } );
94    connect( JobQueue::instance(), &JobQueue::failed,
95             this, &ViewManager::onInstallationFailed );
96    connect( JobQueue::instance(), &JobQueue::finished,
97             this, &ViewManager::next );
98}
99
100
101ViewManager::~ViewManager()
102{
103    m_widget->deleteLater();
104    s_instance = nullptr;
105}
106
107
108QWidget*
109ViewManager::centralWidget()
110{
111    return m_widget;
112}
113
114
115void
116ViewManager::addViewStep( ViewStep* step )
117{
118    insertViewStep( m_steps.size(), step );
119    // If this is the first inserted view step, update status of "Next" button
120    if ( m_steps.count() == 1 )
121        m_next->setEnabled( step->isNextEnabled() );
122}
123
124
125void
126ViewManager::insertViewStep( int before, ViewStep* step )
127{
128    m_steps.insert( before, step );
129    QLayout* layout = step->widget()->layout();
130    if ( layout )
131        layout->setContentsMargins( 0, 0, 0, 0 );
132    m_stack->insertWidget( before, step->widget() );
133
134    connect( step, &ViewStep::enlarge, this, &ViewManager::enlarge );
135    connect( step, &ViewStep::nextStatusChanged,
136             this, [this]( bool status )
137    {
138        ViewStep* vs = qobject_cast< ViewStep* >( sender() );
139        if ( vs )
140        {
141            if ( vs == m_steps.at( m_currentStep ) )
142                m_next->setEnabled( status );
143        }
144    } );
145
146    m_stack->setCurrentIndex( 0 );
147    step->widget()->setFocus();
148}
149
150
151void
152ViewManager::onInstallationFailed( const QString& message, const QString& details )
153{
154    cError() << "Installation failed:";
155    cDebug() << "- message:" << message;
156    cDebug() << "- details:" << details;
157
158    QMessageBox* msgBox = new QMessageBox();
159    msgBox->setIcon( QMessageBox::Critical );
160    msgBox->setWindowTitle( tr( "Error" ) );
161    msgBox->setText( "<strong>" + tr( "Installation Failed" ) + "</strong>" );
162    msgBox->setStandardButtons( QMessageBox::Close );
163    msgBox->button( QMessageBox::Close )->setText( tr( "&Close" ) );
164
165    QString text = "<p>" + message + "</p>";
166    if ( !details.isEmpty() )
167        text += "<p>" + details + "</p>";
168    msgBox->setInformativeText( text );
169
170    connect( msgBox, &QMessageBox::buttonClicked, qApp, &QApplication::quit );
171    cDebug() << "Calamares will quit when the dialog closes.";
172    msgBox->show();
173}
174
175
176void
177ViewManager::onInitFailed( const QStringList& modules)
178{
179    QString title( tr( "Calamares Initialization Failed" ) );
180    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." ) );
181    QString detailString;
182
183    if ( modules.count() > 0 )
184    {
185        description.append( tr( "<br/>The following modules could not be loaded:" ) );
186        QStringList details;
187        details << QLatin1Literal("<ul>");
188        for( const auto& m : modules )
189            details << QLatin1Literal("<li>") << m << QLatin1Literal("</li>");
190        details << QLatin1Literal("</ul>");
191        detailString = details.join( QString() );
192    }
193
194    insertViewStep( 0, new BlankViewStep( title, description.arg( *Calamares::Branding::ShortProductName ), detailString ) );
195}
196
197ViewStepList
198ViewManager::viewSteps() const
199{
200    return m_steps;
201}
202
203
204ViewStep*
205ViewManager::currentStep() const
206{
207    return m_steps.value( m_currentStep );
208}
209
210
211int
212ViewManager::currentStepIndex() const
213{
214    return m_currentStep;
215}
216
217static inline bool
218stepNextWillExecute(const ViewStepList& steps, int index)
219{
220    return ( index + 1 < steps.count() ) && qobject_cast< ExecutionViewStep* >( steps.at( index + 1 ) );
221}
222
223void
224ViewManager::next()
225{
226    ViewStep* step = m_steps.at( m_currentStep );
227    bool executing = false;
228    if ( step->isAtEnd() )
229    {
230        // Special case when the user clicks next on the very last page in a view phase
231        // and right before switching to an execution phase.
232        // Depending on Calamares::Settings, we show an "are you sure" prompt or not.
233        if ( Calamares::Settings::instance()->showPromptBeforeExecution() && stepNextWillExecute( m_steps, m_currentStep ) )
234        {
235            int reply =
236                QMessageBox::question( m_widget,
237                                       tr( "Continue with setup?" ),
238                                       tr( "The %1 installer is about to make changes to your "
239                                           "disk in order to install %2.<br/><strong>You will not be able "
240                                           "to undo these changes.</strong>" )
241                                       .arg( *Calamares::Branding::ShortProductName )
242                                       .arg( *Calamares::Branding::ShortVersionedName ),
243                                       tr( "&Install now" ),
244                                       tr( "Go &back" ),
245                                       QString(),
246                                       0,
247                                       1 );
248            if ( reply == 1 )
249                return;
250        }
251
252        m_currentStep++;
253        m_stack->setCurrentIndex( m_currentStep );
254        step->onLeave();
255        m_steps.at( m_currentStep )->onActivate();
256        executing = qobject_cast< ExecutionViewStep* >( m_steps.at( m_currentStep ) ) != nullptr;
257        emit currentStepChanged();
258        if ( executing )
259        {
260            m_back->setEnabled( false );
261            m_next->setEnabled( false );
262        }
263    }
264    else
265        step->next();
266
267    m_next->setEnabled( !executing && m_steps.at( m_currentStep )->isNextEnabled() );
268    m_back->setEnabled( !executing && m_steps.at( m_currentStep )->isBackEnabled() );
269
270    updateButtonLabels();
271}
272
273void
274ViewManager::updateButtonLabels()
275{
276    if ( stepNextWillExecute( m_steps, m_currentStep ) )
277        m_next->setText( tr( "&Install" ) );
278    else
279        m_next->setText( tr( "&Next" ) );
280
281    if ( m_currentStep == m_steps.count() -1 && m_steps.last()->isAtEnd() )
282    {
283        m_quit->setText( tr( "&Done" ) );
284        m_quit->setToolTip( tr( "The installation is complete. Close the installer." ) );
285    }
286    else
287    {
288        m_quit->setText( tr( "&Cancel" ) );
289        m_quit->setToolTip( tr( "Cancel installation without changing the system." ) );
290    }
291}
292
293void
294ViewManager::back()
295{
296    ViewStep* step = m_steps.at( m_currentStep );
297    if ( step->isAtBeginning() && m_currentStep > 0 )
298    {
299        m_currentStep--;
300        m_stack->setCurrentIndex( m_currentStep );
301        step->onLeave();
302        m_steps.at( m_currentStep )->onActivate();
303        emit currentStepChanged();
304    }
305    else if ( !step->isAtBeginning() )
306        step->back();
307    else return;
308
309    m_next->setEnabled( m_steps.at( m_currentStep )->isNextEnabled() );
310    m_back->setEnabled( m_steps.at( m_currentStep )->isBackEnabled() );
311
312    if ( m_currentStep == 0 && m_steps.first()->isAtBeginning() )
313        m_back->setEnabled( false );
314
315    updateButtonLabels();
316}
317
318bool ViewManager::confirmCancelInstallation()
319{
320    // If it's NOT the last page of the last step, we ask for confirmation
321    if ( !( m_currentStep == m_steps.count() -1 &&
322            m_steps.last()->isAtEnd() ) )
323    {
324        QMessageBox mb( QMessageBox::Question,
325                        tr( "Cancel installation?" ),
326                        tr( "Do you really want to cancel the current install process?\n"
327                            "The installer will quit and all changes will be lost." ),
328                        QMessageBox::Yes | QMessageBox::No,
329                        m_widget );
330        mb.setDefaultButton( QMessageBox::No );
331        mb.button( QMessageBox::Yes )->setText( tr( "&Yes" ) );
332        mb.button( QMessageBox::No )->setText( tr( "&No" ) );
333        int response = mb.exec();
334        return response == QMessageBox::Yes;
335    }
336    else // Means we're at the end, no need to confirm.
337        return true;
338}
339
340}  // namespace
Note: See TracBrowser for help on using the repository browser.