Merge branch 'qml-finished' into calamares

main
Adriaan de Groot 4 years ago
commit d3acc39d2d

@ -11,6 +11,7 @@ calamares_add_plugin( finished
TYPE viewmodule
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
Config.cpp
FinishedViewStep.cpp
FinishedPage.cpp
UI

@ -0,0 +1,201 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#include "Config.h"
#include "Branding.h"
#include "Settings.h"
#include "utils/Logger.h"
#include "utils/Variant.h"
#include <QProcess>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
const NamedEnumTable< Config::RestartMode >&
restartModes()
{
using M = Config::RestartMode;
static const NamedEnumTable< M > table { { "never", M::Never },
{ "user-unchecked", M::UserDefaultUnchecked },
{ "unchecked", M::UserDefaultUnchecked },
{ "user-checked", M::UserDefaultChecked },
{ "checked", M::UserDefaultChecked },
{ "always", M::Always }
};
return table;
}
Config::Config( QObject* parent )
: QObject( parent )
{
}
void
Config::setRestartNowMode( Config::RestartMode m )
{
// Can only go "down" in state (Always > UserDefaultChecked > .. > Never)
if ( m > m_restartNowMode )
{
return;
}
// If changing to an unconditional mode, also set other flag
if ( m == RestartMode::Always || m == RestartMode::Never )
{
setRestartNowWanted( m == RestartMode::Always );
}
if ( m != m_restartNowMode )
{
m_restartNowMode = m;
emit restartModeChanged( m );
}
}
void
Config::setRestartNowWanted( bool w )
{
// Follow the mode which may affect @p w
if ( m_restartNowMode == RestartMode::Always )
{
w = true;
}
if ( m_restartNowMode == RestartMode::Never )
{
w = false;
}
if ( w != m_userWantsRestart )
{
m_userWantsRestart = w;
emit restartNowWantedChanged( w );
}
}
void
Config::doRestart()
{
if ( restartNowMode() != RestartMode::Never && restartNowWanted() )
{
cDebug() << "Running restart command" << m_restartNowCommand;
QProcess::execute( "/bin/sh", { "-c", m_restartNowCommand } );
}
}
void
Config::doNotify( bool hasFailed )
{
if ( !notifyOnFinished() )
{
return;
}
QDBusInterface notify(
"org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications" );
if ( notify.isValid() )
{
cDebug() << "Sending notification of completion. Failed?" << hasFailed;
QString title;
QString message;
if ( hasFailed )
{
title = Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Failed" ) : tr( "Installation Failed" );
message = Calamares::Settings::instance()->isSetupMode()
? tr( "The setup of %1 did not complete successfully." )
: tr( "The installation of %1 did not complete successfully." );
}
else
{
title = Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Complete" )
: tr( "Installation Complete" );
message = Calamares::Settings::instance()->isSetupMode() ? tr( "The setup of %1 is complete." )
: tr( "The installation of %1 is complete." );
}
const auto* branding = Calamares::Branding::instance();
QDBusReply< uint > r = notify.call( "Notify",
QString( "Calamares" ),
QVariant( 0U ),
QString( "calamares" ),
title,
message.arg( branding->versionedName() ),
QStringList(),
QVariantMap(),
QVariant( 0 ) );
if ( !r.isValid() )
{
cWarning() << "Could not call org.freedesktop.Notifications.Notify at end of installation." << r.error();
}
}
else
{
cWarning() << "Could not get dbus interface for notifications at end of installation." << notify.lastError();
}
}
void
Config::setConfigurationMap( const QVariantMap& configurationMap )
{
RestartMode mode = RestartMode::Never;
//TODO:3.3 remove deprecated restart settings
QString restartMode = CalamaresUtils::getString( configurationMap, "restartNowMode" );
if ( restartMode.isEmpty() )
{
if ( configurationMap.contains( "restartNowEnabled" ) )
{
cWarning() << "Configuring the finished module with deprecated restartNowEnabled settings";
}
bool restartNowEnabled = CalamaresUtils::getBool( configurationMap, "restartNowEnabled", false );
bool restartNowChecked = CalamaresUtils::getBool( configurationMap, "restartNowChecked", false );
if ( !restartNowEnabled )
{
mode = RestartMode::Never;
}
else
{
mode = restartNowChecked ? RestartMode::UserDefaultChecked : RestartMode::UserDefaultUnchecked;
}
}
else
{
bool ok = false;
mode = restartModes().find( restartMode, ok );
if ( !ok )
{
cWarning() << "Configuring the finished module with bad restartNowMode" << restartMode;
}
}
m_restartNowMode = mode;
m_userWantsRestart = ( mode == RestartMode::Always || mode == RestartMode::UserDefaultChecked );
emit restartModeChanged( m_restartNowMode );
emit restartNowWantedChanged( m_userWantsRestart );
if ( mode != RestartMode::Never )
{
QString restartNowCommand = CalamaresUtils::getString( configurationMap, "restartNowCommand" );
if ( restartNowCommand.isEmpty() )
{
restartNowCommand = QStringLiteral( "shutdown -r now" );
}
m_restartNowCommand = restartNowCommand;
}
m_notifyOnFinished = CalamaresUtils::getBool( configurationMap, "notifyOnFinished", false );
}

@ -0,0 +1,81 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef FINISHED_CONFIG_H
#define FINISHED_CONFIG_H
#include "utils/NamedEnum.h"
#include <QObject>
class Config : public QObject
{
Q_OBJECT
Q_PROPERTY( RestartMode restartNowMode READ restartNowMode WRITE setRestartNowMode NOTIFY restartModeChanged )
Q_PROPERTY( bool restartNowWanted READ restartNowWanted WRITE setRestartNowWanted NOTIFY restartNowWantedChanged )
Q_PROPERTY( QString restartNowCommand READ restartNowCommand CONSTANT FINAL )
Q_PROPERTY( bool notifyOnFinished READ notifyOnFinished CONSTANT FINAL )
public:
Config( QObject* parent = nullptr );
enum class RestartMode
{
Never,
UserDefaultUnchecked,
UserDefaultChecked,
Always
};
Q_ENUM( RestartMode )
RestartMode restartNowMode() const { return m_restartNowMode; }
bool restartNowWanted() const { return m_userWantsRestart; }
QString restartNowCommand() const { return m_restartNowCommand; }
bool notifyOnFinished() const { return m_notifyOnFinished; }
void setConfigurationMap( const QVariantMap& configurationMap );
public slots:
void setRestartNowMode( RestartMode m );
void setRestartNowWanted( bool w );
/** @brief Run the restart command, if desired.
*
* This should generally not be called somewhere during the
* application's execution, but only in response to QApplication::quit()
* or something like that when the user expects the system to restart.
*/
void doRestart();
/** @brief Send DBus notification, if desired.
*
* This takes notifyOnFinished() into account.
*
* At the end of installation (when the FinishedViewStep is activated),
* send a desktop notification via DBus that the install is done.
*/
void doNotify( bool hasFailed = false );
signals:
void restartModeChanged( RestartMode m );
void restartNowWantedChanged( bool w );
private:
QString m_restartNowCommand;
RestartMode m_restartNowMode = RestartMode::Never;
bool m_userWantsRestart = false;
bool m_notifyOnFinished = false;
};
const NamedEnumTable< Config::RestartMode >& restartModes();
#endif

@ -11,26 +11,19 @@
#include "FinishedPage.h"
#include "CalamaresVersion.h"
#include "ViewManager.h"
#include "Config.h"
#include "ui_FinishedPage.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
#include "Branding.h"
#include "Settings.h"
#include "utils/Retranslator.h"
#include <QApplication>
#include <QBoxLayout>
#include <QFocusEvent>
#include <QLabel>
#include <QProcess>
#include "Branding.h"
#include "Settings.h"
FinishedPage::FinishedPage( QWidget* parent )
FinishedPage::FinishedPage( Config* config, QWidget* parent )
: QWidget( parent )
, ui( new Ui::FinishedPage )
, m_mode( FinishedViewStep::RestartMode::UserUnchecked )
{
ui->setupUi( this );
@ -38,9 +31,44 @@ FinishedPage::FinishedPage( QWidget* parent )
ui->mainText->setWordWrap( true );
ui->mainText->setOpenExternalLinks( true );
CALAMARES_RETRANSLATE(
const auto* branding = Calamares::Branding::instance(); ui->retranslateUi( this );
if ( Calamares::Settings::instance()->isSetupMode() ) {
connect( config, &Config::restartModeChanged, [this]( Config::RestartMode mode ) {
using Mode = Config::RestartMode;
ui->restartCheckBox->setVisible( mode != Mode::Never );
ui->restartCheckBox->setEnabled( mode != Mode::Always );
} );
connect( config, &Config::restartNowWantedChanged, ui->restartCheckBox, &QCheckBox::setChecked );
connect( ui->restartCheckBox, &QCheckBox::stateChanged, [config]( int state ) {
config->setRestartNowWanted( state != 0 );
} );
CALAMARES_RETRANSLATE_SLOT( &FinishedPage::retranslate );
}
void
FinishedPage::focusInEvent( QFocusEvent* e )
{
e->accept();
}
void
FinishedPage::onInstallationFailed( const QString& message, const QString& details )
{
m_failure = !message.isEmpty() ? message : details;
retranslate();
}
void
FinishedPage::retranslate()
{
const auto* branding = Calamares::Branding::instance();
ui->retranslateUi( this );
if ( !m_failure.has_value() )
{
if ( Calamares::Settings::instance()->isSetupMode() )
{
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
"%1 has been set up on your computer.<br/>"
"You may now start using your new system." )
@ -50,7 +78,9 @@ FinishedPage::FinishedPage( QWidget* parent )
"restart immediately when you click on "
"<span style=\"font-style:italic;\">Done</span> "
"or close the setup program.</p></body></html>" ) );
} else {
}
else
{
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
"%1 has been installed on your computer.<br/>"
"You may now restart into your new system, or continue "
@ -61,68 +91,27 @@ FinishedPage::FinishedPage( QWidget* parent )
"restart immediately when you click on "
"<span style=\"font-style:italic;\">Done</span> "
"or close the installer.</p></body></html>" ) );
} )
}
void
FinishedPage::setRestart( FinishedViewStep::RestartMode mode )
{
using Mode = FinishedViewStep::RestartMode;
m_mode = mode;
ui->restartCheckBox->setVisible( mode != Mode::Never );
ui->restartCheckBox->setEnabled( mode != Mode::Always );
ui->restartCheckBox->setChecked( ( mode == Mode::Always ) || ( mode == Mode::UserChecked ) );
}
void
FinishedPage::setRestartNowCommand( const QString& command )
{
m_restartNowCommand = command;
}
void
FinishedPage::setUpRestart()
{
cDebug() << "FinishedPage::setUpRestart(), Quit button"
<< "setup=" << FinishedViewStep::modeName( m_mode ) << "command=" << m_restartNowCommand;
}
}
else
{
const QString message = m_failure.value();
connect( qApp, &QApplication::aboutToQuit, [this]() {
if ( ui->restartCheckBox->isVisible() && ui->restartCheckBox->isChecked() )
if ( Calamares::Settings::instance()->isSetupMode() )
{
cDebug() << "Running restart command" << m_restartNowCommand;
QProcess::execute( "/bin/sh", { "-c", m_restartNowCommand } );
ui->mainText->setText( tr( "<h1>Setup Failed</h1><br/>"
"%1 has not been set up on your computer.<br/>"
"The error message was: %2." )
.arg( branding->versionedName() )
.arg( message ) );
}
} );
}
void
FinishedPage::focusInEvent( QFocusEvent* e )
{
e->accept();
}
void
FinishedPage::onInstallationFailed( const QString& message, const QString& details )
{
const auto* branding = Calamares::Branding::instance();
Q_UNUSED( details )
if ( Calamares::Settings::instance()->isSetupMode() )
ui->mainText->setText( tr( "<h1>Setup Failed</h1><br/>"
"%1 has not been set up on your computer.<br/>"
"The error message was: %2." )
.arg( branding->versionedName() )
.arg( message ) );
else
ui->mainText->setText( tr( "<h1>Installation Failed</h1><br/>"
"%1 has not been installed on your computer.<br/>"
"The error message was: %2." )
.arg( branding->versionedName() )
.arg( message ) );
setRestart( FinishedViewStep::RestartMode::Never );
else
{
ui->mainText->setText( tr( "<h1>Installation Failed</h1><br/>"
"%1 has not been installed on your computer.<br/>"
"The error message was: %2." )
.arg( branding->versionedName() )
.arg( message ) );
}
}
}

@ -11,10 +11,12 @@
#ifndef FINISHEDPAGE_H
#define FINISHEDPAGE_H
#include <QWidget>
#include "FinishedViewStep.h"
#include <optional>
class Config;
namespace Ui
{
class FinishedPage;
@ -24,24 +26,19 @@ class FinishedPage : public QWidget
{
Q_OBJECT
public:
explicit FinishedPage( QWidget* parent = nullptr );
void setRestart( FinishedViewStep::RestartMode mode );
void setRestartNowCommand( const QString& command );
explicit FinishedPage( Config* config, QWidget* parent = nullptr );
void setUpRestart();
public slots:
void onInstallationFailed( const QString& message, const QString& details );
void retranslate();
protected:
void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus
private:
Ui::FinishedPage* ui;
FinishedViewStep::RestartMode m_mode;
QString m_restartNowCommand;
std::optional< QString > m_failure;
};
#endif // FINISHEDPAGE_H

@ -10,42 +10,21 @@
*/
#include "FinishedViewStep.h"
#include "Config.h"
#include "FinishedPage.h"
#include "Branding.h"
#include "JobQueue.h"
#include "Settings.h"
#include "utils/Logger.h"
#include "utils/NamedEnum.h"
#include "utils/Variant.h"
#include <QVariantMap>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
static const NamedEnumTable< FinishedViewStep::RestartMode >&
modeNames()
{
using Mode = FinishedViewStep::RestartMode;
static const NamedEnumTable< Mode > names { { QStringLiteral( "never" ), Mode::Never },
{ QStringLiteral( "user-unchecked" ), Mode::UserUnchecked },
{ QStringLiteral( "user-checked" ), Mode::UserChecked },
{ QStringLiteral( "always" ), Mode::Always } };
return names;
}
#include <QApplication>
FinishedViewStep::FinishedViewStep( QObject* parent )
: Calamares::ViewStep( parent )
, m_widget( new FinishedPage() )
, installFailed( false )
, m_notifyOnFinished( false )
, m_config( new Config( this ) )
, m_widget( new FinishedPage( m_config ) )
, m_installFailed( false )
{
auto jq = Calamares::JobQueue::instance();
connect( jq, &Calamares::JobQueue::failed, m_widget, &FinishedPage::onInstallationFailed );
connect( jq, &Calamares::JobQueue::failed, this, &FinishedViewStep::onInstallationFailed );
emit nextStatusChanged( true );
@ -102,54 +81,12 @@ FinishedViewStep::isAtEnd() const
return true;
}
void
FinishedViewStep::sendNotification()
{
// If the installation failed, don't send notification popup;
// there's a (modal) dialog popped up with the failure notice.
if ( installFailed )
{
return;
}
QDBusInterface notify(
"org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications" );
if ( notify.isValid() )
{
const auto* branding = Calamares::Branding::instance();
QDBusReply< uint > r = notify.call(
"Notify",
QString( "Calamares" ),
QVariant( 0U ),
QString( "calamares" ),
Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Complete" ) : tr( "Installation Complete" ),
Calamares::Settings::instance()->isSetupMode()
? tr( "The setup of %1 is complete." ).arg( branding->versionedName() )
: tr( "The installation of %1 is complete." ).arg( branding->versionedName() ),
QStringList(),
QVariantMap(),
QVariant( 0 ) );
if ( !r.isValid() )
{
cWarning() << "Could not call org.freedesktop.Notifications.Notify at end of installation." << r.error();
}
}
else
{
cWarning() << "Could not get dbus interface for notifications at end of installation." << notify.lastError();
}
}
void
FinishedViewStep::onActivate()
{
m_widget->setUpRestart();
if ( m_notifyOnFinished )
{
sendNotification();
}
m_config->doNotify( m_installFailed );
connect( qApp, &QApplication::aboutToQuit, m_config, &Config::doRestart );
}
@ -162,67 +99,15 @@ FinishedViewStep::jobs() const
void
FinishedViewStep::onInstallationFailed( const QString& message, const QString& details )
{
Q_UNUSED( message )
Q_UNUSED( details )
installFailed = true;
m_installFailed = true;
m_config->setRestartNowMode( Config::RestartMode::Never );
m_widget->onInstallationFailed( message, details );
}
void
FinishedViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
RestartMode mode = RestartMode::Never;
QString restartMode = CalamaresUtils::getString( configurationMap, "restartNowMode" );
if ( restartMode.isEmpty() )
{
if ( configurationMap.contains( "restartNowEnabled" ) )
{
cWarning() << "Configuring the finished module with deprecated restartNowEnabled settings";
}
bool restartNowEnabled = CalamaresUtils::getBool( configurationMap, "restartNowEnabled", false );
bool restartNowChecked = CalamaresUtils::getBool( configurationMap, "restartNowChecked", false );
if ( !restartNowEnabled )
{
mode = RestartMode::Never;
}
else
{
mode = restartNowChecked ? RestartMode::UserChecked : RestartMode::UserUnchecked;
}
}
else
{
bool ok = false;
mode = modeNames().find( restartMode, ok );
if ( !ok )
{
cWarning() << "Configuring the finished module with bad restartNowMode" << restartMode;
}
}
m_widget->setRestart( mode );
if ( mode != RestartMode::Never )
{
QString restartNowCommand = CalamaresUtils::getString( configurationMap, "restartNowCommand" );
if ( restartNowCommand.isEmpty() )
{
restartNowCommand = QStringLiteral( "shutdown -r now" );
}
m_widget->setRestartNowCommand( restartNowCommand );
}
m_notifyOnFinished = CalamaresUtils::getBool( configurationMap, "notifyOnFinished", false );
}
QString
FinishedViewStep::modeName( FinishedViewStep::RestartMode m )
{
bool ok = false;
return modeNames().find( m, ok ); // May be QString()
m_config->setConfigurationMap( configurationMap );
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( FinishedViewStepFactory, registerPlugin< FinishedViewStep >(); )

@ -11,13 +11,11 @@
#ifndef FINISHEDVIEWSTEP_H
#define FINISHEDVIEWSTEP_H
#include <QObject>
#include "DllMacro.h"
#include "utils/PluginFactory.h"
#include "viewpages/ViewStep.h"
#include "DllMacro.h"
class Config;
class FinishedPage;
class PLUGINDLLEXPORT FinishedViewStep : public Calamares::ViewStep
@ -25,16 +23,6 @@ class PLUGINDLLEXPORT FinishedViewStep : public Calamares::ViewStep
Q_OBJECT
public:
enum class RestartMode
{
Never = 0, ///< @brief Don't show button, just exit
UserUnchecked, ///< @brief Show button, starts unchecked
UserChecked, ///< @brief Show button, starts checked
Always ///< @brief Show button, can't change, checked
};
/// @brief Returns the config-name of the given restart-mode @p m
static QString modeName( RestartMode m );
explicit FinishedViewStep( QObject* parent = nullptr );
~FinishedViewStep() override;
@ -58,16 +46,9 @@ public slots:
void onInstallationFailed( const QString& message, const QString& details );
private:
Config* m_config;
FinishedPage* m_widget;
/**
* @brief At the end of installation (when this step is activated),
* send a desktop notification via DBus that the install is done.
*/
void sendNotification();
bool installFailed;
bool m_notifyOnFinished;
bool m_installFailed; // Track if onInstallationFailed() was called
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( FinishedViewStepFactory )

Loading…
Cancel
Save