Compare commits

...

4 Commits

Author SHA1 Message Date
Adriaan de Groot
810f8d7081 [finished] Sketch the way configuration is parsed now 2024-07-02 20:40:11 +02:00
Adriaan de Groot
e59e916405 [finishedq] Pull in the previous finished configuration
Since finished is getting new options, which I don't immediately
know how to support in finishedq, put the previous config and
example file in the finishedq module.
2024-07-02 20:40:11 +02:00
Adriaan de Groot
cf4d2d432f [finished] Rip out most of the logic
This breaks finishedq at runtime, too.
2024-07-02 20:40:11 +02:00
Adriaan de Groot
38dfbdccf3 [finished] Allow more possibilities for final steps
This is just a sketch in the .conf file of what is wanted.
2024-07-02 20:40:11 +02:00
8 changed files with 543 additions and 199 deletions

View File

@@ -19,10 +19,7 @@
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
const NamedEnumTable< Config::RestartMode >&
restartModes()
{
using M = Config::RestartMode;
#if 0
static const NamedEnumTable< M > table { { "never", M::Never },
{ "user-unchecked", M::UserDefaultUnchecked },
{ "unchecked", M::UserDefaultUnchecked },
@@ -31,91 +28,37 @@ restartModes()
{ "always", M::Always }
};
return table;
}
#endif
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::onInstallationFailed( const QString& message, const QString& details )
{
const bool msgChange = message != m_failureMessage;
const bool detChange = details != m_failureDetails;
const bool messageChange = message != m_failureMessage;
const bool detailsChange = details != m_failureDetails;
m_failureMessage = message;
m_failureDetails = details;
if ( msgChange )
if ( messageChange )
{
emit failureMessageChanged( message );
}
if ( detChange )
if ( detailsChange )
{
emit failureDetailsChanged( message );
}
if ( ( msgChange || detChange ) )
if ( ( messageChange || detailsChange ) )
{
emit failureChanged( hasFailed() );
if ( hasFailed() )
{
setRestartNowMode( Config::RestartMode::Never );
}
}
}
void
Config::doRestart( bool restartAnyway )
Config::doRestart()
{
cDebug() << "mode=" << restartModes().find( restartNowMode() ) << " user wants restart?" << restartNowWanted()
<< "force restart?" << restartAnyway;
if ( restartNowMode() != RestartMode::Never && restartAnyway )
{
cDebug() << Logger::SubEntry << "Running restart command" << m_restartNowCommand;
QProcess::execute( "/bin/sh", { "-c", m_restartNowCommand } );
}
}
void
@@ -175,56 +118,94 @@ Config::doNotify( bool hasFailed, bool sendAnyway )
}
}
void
Config::setConfigurationMap( const QVariantMap& configurationMap )
using Choices = int;
static Choices loadLive(bool isSelected)
{
RestartMode mode = RestartMode::Never;
return isSelected ? 1 : 0;
}
//TODO:3.3 remove deprecated restart settings
QString restartMode = Calamares::getString( configurationMap, "restartNowMode" );
if ( restartMode.isEmpty() )
static Choices loadRestart(bool isSelected, const QString & /* command */ )
{
return isSelected ? 1 : 0;
}
static Choices loadFromV3(const QVariantList & items, const QString & defaultChoice )
{
return 0;
}
static Choices loadFromV2(const QString & restartNowMode, const QString & restartNowCommand)
{
if (restartNowMode == QStringLiteral( "never"))
{
if ( configurationMap.contains( "restartNowEnabled" ) )
{
cWarning() << "Configuring the finished module with deprecated restartNowEnabled settings";
}
return loadLive(true);
}
bool restartNowEnabled = Calamares::getBool( configurationMap, "restartNowEnabled", false );
bool restartNowChecked = Calamares::getBool( configurationMap, "restartNowChecked", false );
// Empty if not specified, defaults to user-unchecked according to the suggested config
if (restartNowMode == QStringLiteral("user-unchecked") || restartNowMode == QStringLiteral("unchecked") || restartNowMode.isEmpty())
{
Choices c = loadLive(true);
c += loadRestart(false, restartNowCommand);
return c;
}
if ( !restartNowEnabled )
{
mode = RestartMode::Never;
}
else
{
mode = restartNowChecked ? RestartMode::UserDefaultChecked : RestartMode::UserDefaultUnchecked;
}
if (restartNowMode == QStringLiteral("user-checked") || restartNowMode == QStringLiteral("checked"))
{
Choices c = loadLive(false);
c += loadRestart(true, restartNowCommand);
return c;
}
if (restartNowMode == QStringLiteral("always"))
{
return loadRestart(true, restartNowCommand);
}
cError() << "Unknown v2 restart mode" << restartNowMode << "using 'never'";
return loadLive(true);
}
static Choices loadFromV1(bool restartNowEnabled, bool restartNowChecked, const QString & restartNowCommand)
{
if (!restartNowEnabled)
{
return loadFromV2( QStringLiteral("never"), QString());
}
if (restartNowChecked)
{
return loadFromV2( QStringLiteral("user-checked"), restartNowCommand);
}
else
{
bool ok = false;
mode = restartModes().find( restartMode, ok );
if ( !ok )
{
cWarning() << "Configuring the finished module with bad restartNowMode" << restartMode;
}
return loadFromV2( QStringLiteral("user-unchecked"), restartNowCommand);
}
}
void
Config::setConfigurationMap( const QVariantMap& configurationMap )
{
m_notifyOnFinished = Calamares::getBool( configurationMap, "notifyOnFinished", false );
const auto v1Enabled = QStringLiteral( "restartNowEnabled" );
const auto v1Checked = QStringLiteral( "restartNowChecked" );
const auto v2Mode = QStringLiteral("restartNowMode");
const auto v2Command = QStringLiteral("restartNowCommand");
if(configurationMap.contains( v1Enabled) || configurationMap.contains(v1Checked))
{
cWarning() << "Configuration uses v1 settings" << v1Enabled << "and" << v1Checked;
loadFromV1(Calamares::getBool(configurationMap, v1Enabled, true), Calamares::getBool(configurationMap, v1Checked, false), Calamares::getString(configurationMap, v2Command));
}
else if(configurationMap.contains( v2Mode) || configurationMap.contains(v2Command))
{
cWarning() << "Configuration uses v2 settings" << v2Mode << "and" << v2Command;
loadFromV2(Calamares::getString(configurationMap, v2Mode, QStringLiteral("user-unchecked")), Calamares::getString(configurationMap, v2Command));
}
else
{
loadFromV3(Calamares::getList(configurationMap, QStringLiteral("choices")), Calamares::getString(configurationMap, QStringLiteral("defaultChoice")));
}
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 = Calamares::getString( configurationMap, "restartNowCommand" );
if ( restartNowCommand.isEmpty() )
{
restartNowCommand = QStringLiteral( "shutdown -r now" );
}
m_restartNowCommand = restartNowCommand;
}
m_notifyOnFinished = Calamares::getBool( configurationMap, "notifyOnFinished", false );
}

View File

@@ -18,10 +18,6 @@ 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 )
Q_PROPERTY( QString failureMessage READ failureMessage NOTIFY failureMessageChanged )
@@ -31,32 +27,9 @@ class Config : public QObject
public:
Config( QObject* parent = nullptr );
enum class RestartMode
{
Never,
UserDefaultUnchecked,
UserDefaultChecked,
Always
};
Q_ENUM( RestartMode )
void setConfigurationMap( const QVariantMap& configurationMap );
public Q_SLOTS:
RestartMode restartNowMode() const { return m_restartNowMode; }
void setRestartNowMode( RestartMode m );
bool restartNowWanted() const
{
if ( restartNowMode() == RestartMode::Never )
{
return false;
}
return ( restartNowMode() == RestartMode::Always ) || m_userWantsRestart;
}
void setRestartNowWanted( bool w );
QString restartNowCommand() const { return m_restartNowCommand; }
bool notifyOnFinished() const { return m_notifyOnFinished; }
QString failureMessage() const { return m_failureMessage; }
@@ -64,23 +37,6 @@ public Q_SLOTS:
/// Failure is if any of the failure messages is non-empty
bool hasFailed() const { return !m_failureMessage.isEmpty() || !m_failureDetails.isEmpty(); }
/** @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.
*
* The "if desired" part is: only if the restart mode allows it,
* **and** the user has checked the box (or done whatever to
* turn on restartNowWanted()).
*
* - The one-argument form ignores what the user wants and restarts
* if @p restartAnyway is @c true **unless** the mode is Never
* - The no-argument form uses the user setting
*/
void doRestart( bool restartAnyway );
void doRestart() { doRestart( restartNowWanted() ); }
/** @brief Send DBus notification
*
* At the end of installation (when the FinishedViewStep is activated),
@@ -105,18 +61,16 @@ public Q_SLOTS:
*/
void onInstallationFailed( const QString& message, const QString& details );
signals:
void restartModeChanged( RestartMode m );
void restartNowWantedChanged( bool w );
/// @brief Does whatever restart-action is selected / configured
void doRestart();
Q_SIGNALS:
void failureMessageChanged( const QString& );
void failureDetailsChanged( const QString& );
void failureChanged( bool );
private:
// Configuration parts
QString m_restartNowCommand;
RestartMode m_restartNowMode = RestartMode::Never;
bool m_userWantsRestart = false;
bool m_notifyOnFinished = false;
// Dynamic parts
@@ -125,6 +79,4 @@ private:
QString m_failureDetails;
};
const NamedEnumTable< Config::RestartMode >& restartModes();
#endif

View File

@@ -31,20 +31,6 @@ FinishedPage::FinishedPage( Config* config, QWidget* parent )
ui->mainText->setWordWrap( true );
ui->mainText->setOpenExternalLinks( true );
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 );
}

View File

@@ -17,6 +17,8 @@
# checkbox is shown by restartNowEnabled.
# restartNowChecked: false
# DEPRECATED
#
# Behavior of the "restart system now" button.
#
# There are four usable values:
@@ -34,14 +36,60 @@
# This is new behavior.
#
# The three combinations of legacy values are still supported.
restartNowMode: user-unchecked
#
# restartNowMode: user-unchecked
# DEPRECATED
#
# If the checkbox is shown, and the checkbox is checked, then when
# Calamares exits from the finished-page it will run this command.
# If not set, falls back to "shutdown -r now".
restartNowCommand: "systemctl -i reboot"
#
# restartNowCommand: "systemctl -i reboot"
# When the last page is (successfully) reached, send a DBus notification
# to the desktop that the installation is done. This works only if the
# user as whom Calamares is run, can reach the regular desktop session bus.
notifyOnFinished: false
# Choices displayed for the last page: this is a list of items. Each item
# has a name. There are known names "live", "reboot" and "poweroff", but
# you can add others. Each item also has an optional subkey "commands"
# which is a list of commands -- see *shellprocess* for details. It is
# legal to have an empty list of commands, written []. The known names
# "live", "reboot" and "poweroff" have default-values for the commands,
# other names will need a specific command.
#
# If nothing is specified for "choices", the default value is ["live", "reboot"]
choices:
- name: "live"
commands: []
- name: "reboot"
commands:
- "systemctl -i reboot"
- name: "poweroff"
commands:
- "sync ; sleep 1"
- "halt -p"
# Selects one of the choices -- by name -- from the list above.
# If nothing is specified, or a name that does not exist in the list,
# then no choice is specified and the user must select one before continuing.
#
defaultChoice: "live"
# Mapping restartNowMode values to choices:
# - "never" means choices: ["live"] defaultChoice: "live"
# - "user-unchecked" is equivalent to this:
# choices: ["live", "reboot"]
# defaultChoice: "live"
# - "user-checked" is equivalent to the same configuration, but
# choices: ["live", "reboot"]
# defaultChoice: "reboot"
# - "always" is equivalent to
# choices: ["reboot"]
# defaultChoice: "reboot"
#
# Mapping restartNowCommand to choices: this sets the value of
# *commands* for the "reboot" item (if there is one) to a one-item
# list with the specified command.

View File

@@ -3,6 +3,10 @@
# SPDX-FileCopyrightText: 2021 Anke Boersma <demm@kaosx.us>
# SPDX-License-Identifier: BSD-2-Clause
#
# NOTE: finishedq module uses a different configuration from what
# the finished module uses and is not compatible with
# with the configurable shutdown actions.
if(NOT WITH_QML)
calamares_skip_module( "finishedq (QML is not supported in this build)" )
return()
@@ -14,15 +18,12 @@ if(NOT TARGET ${qtname}::DBus OR NOT TARGET ${qtname}::Network)
return()
endif()
set(_finished ${CMAKE_CURRENT_SOURCE_DIR}/../finished)
include_directories(${_finished})
calamares_add_plugin(finishedq
TYPE viewmodule
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
FinishedQmlViewStep.cpp
${_finished}/Config.cpp
Config.cpp
RESOURCES
finishedq${QT_VERSION_SUFFIX}.qrc
LINK_PRIVATE_LIBRARIES

View File

@@ -0,0 +1,230 @@
/* === 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::onInstallationFailed( const QString& message, const QString& details )
{
const bool msgChange = message != m_failureMessage;
const bool detChange = details != m_failureDetails;
m_failureMessage = message;
m_failureDetails = details;
if ( msgChange )
{
emit failureMessageChanged( message );
}
if ( detChange )
{
emit failureDetailsChanged( message );
}
if ( ( msgChange || detChange ) )
{
emit failureChanged( hasFailed() );
if ( hasFailed() )
{
setRestartNowMode( Config::RestartMode::Never );
}
}
}
void
Config::doRestart( bool restartAnyway )
{
cDebug() << "mode=" << restartModes().find( restartNowMode() ) << " user wants restart?" << restartNowWanted()
<< "force restart?" << restartAnyway;
if ( restartNowMode() != RestartMode::Never && restartAnyway )
{
cDebug() << Logger::SubEntry << "Running restart command" << m_restartNowCommand;
QProcess::execute( "/bin/sh", { "-c", m_restartNowCommand } );
}
}
void
Config::doNotify( bool hasFailed, bool sendAnyway )
{
const char* const failName = hasFailed ? "failed" : "succeeded";
if ( !sendAnyway )
{
cDebug() << "Notification not sent; completion:" << failName;
return;
}
QDBusInterface notify(
"org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications" );
if ( notify.isValid() )
{
cDebug() << "Sending notification of completion:" << failName;
QString title;
QString message;
if ( hasFailed )
{
title = Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Failed", "@title" )
: tr( "Installation Failed", "@title" );
message = Calamares::Settings::instance()->isSetupMode()
? tr( "The setup of %1 did not complete successfully.", "@info" )
: tr( "The installation of %1 did not complete successfully.", "@info" );
}
else
{
title = Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Complete", "@title" )
: tr( "Installation Complete", "@title" );
message = Calamares::Settings::instance()->isSetupMode()
? tr( "The setup of %1 is complete.", "@info" )
: tr( "The installation of %1 is complete.", "@info" );
}
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 = Calamares::getString( configurationMap, "restartNowMode" );
if ( restartMode.isEmpty() )
{
if ( configurationMap.contains( "restartNowEnabled" ) )
{
cWarning() << "Configuring the finished module with deprecated restartNowEnabled settings";
}
bool restartNowEnabled = Calamares::getBool( configurationMap, "restartNowEnabled", false );
bool restartNowChecked = Calamares::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 = Calamares::getString( configurationMap, "restartNowCommand" );
if ( restartNowCommand.isEmpty() )
{
restartNowCommand = QStringLiteral( "shutdown -r now" );
}
m_restartNowCommand = restartNowCommand;
}
m_notifyOnFinished = Calamares::getBool( configurationMap, "notifyOnFinished", false );
}

View File

@@ -0,0 +1,130 @@
/* === 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 )
Q_PROPERTY( QString failureMessage READ failureMessage NOTIFY failureMessageChanged )
Q_PROPERTY( QString failureDetails READ failureDetails NOTIFY failureDetailsChanged )
Q_PROPERTY( bool failed READ hasFailed NOTIFY failureChanged )
public:
Config( QObject* parent = nullptr );
enum class RestartMode
{
Never,
UserDefaultUnchecked,
UserDefaultChecked,
Always
};
Q_ENUM( RestartMode )
void setConfigurationMap( const QVariantMap& configurationMap );
public Q_SLOTS:
RestartMode restartNowMode() const { return m_restartNowMode; }
void setRestartNowMode( RestartMode m );
bool restartNowWanted() const
{
if ( restartNowMode() == RestartMode::Never )
{
return false;
}
return ( restartNowMode() == RestartMode::Always ) || m_userWantsRestart;
}
void setRestartNowWanted( bool w );
QString restartNowCommand() const { return m_restartNowCommand; }
bool notifyOnFinished() const { return m_notifyOnFinished; }
QString failureMessage() const { return m_failureMessage; }
QString failureDetails() const { return m_failureDetails; }
/// Failure is if any of the failure messages is non-empty
bool hasFailed() const { return !m_failureMessage.isEmpty() || !m_failureDetails.isEmpty(); }
/** @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.
*
* The "if desired" part is: only if the restart mode allows it,
* **and** the user has checked the box (or done whatever to
* turn on restartNowWanted()).
*
* - The one-argument form ignores what the user wants and restarts
* if @p restartAnyway is @c true **unless** the mode is Never
* - The no-argument form uses the user setting
*/
void doRestart( bool restartAnyway );
void doRestart() { doRestart( restartNowWanted() ); }
/** @brief Send DBus notification
*
* At the end of installation (when the FinishedViewStep is activated),
* send a desktop notification via DBus that the install is done.
*
* - The two-argument form sends success or failure, and can be
* forced to send by setting @p sendAnyway to @c true.
* - The one-argument form sends success or failure and takes
* the notifyOnFinished() configuration into account.
* - The no-argument form checks if a failure was signalled previously
* and uses that to decide if it was a failure.
*
*/
void doNotify( bool hasFailed, bool sendAnyway );
void doNotify( bool hasFailed ) { doNotify( hasFailed, notifyOnFinished() ); }
void doNotify() { doNotify( hasFailed() ); }
/** @brief Tell the config the install failed
*
* This should be connected to the JobQueue and is called by
* the queue when the installation fails, with a suitable message.
*/
void onInstallationFailed( const QString& message, const QString& details );
signals:
void restartModeChanged( RestartMode m );
void restartNowWantedChanged( bool w );
void failureMessageChanged( const QString& );
void failureDetailsChanged( const QString& );
void failureChanged( bool );
private:
// Configuration parts
QString m_restartNowCommand;
RestartMode m_restartNowMode = RestartMode::Never;
bool m_userWantsRestart = false;
bool m_notifyOnFinished = false;
// Dynamic parts
bool m_hasFailed = false;
QString m_failureMessage;
QString m_failureDetails;
};
const NamedEnumTable< Config::RestartMode >& restartModes();
#endif

View File

@@ -4,33 +4,49 @@
# Configuration for the "finishedq" page, which is usually shown only at
# the end of the installation (successful or not).
#
# See the documentation for the "finished" module for a full explanation
# of the configuration options; the description here applies primarily
# to the use that the QML makes of them.
# NOTE: finishedq module uses a different configuration from what
# the finished module uses and is not compatible with
# with the configurable shutdown actions.
---
# DEPRECATED
#
# The finished page can hold a "restart system now" checkbox.
# If this is false, no checkbox is shown and the system is not restarted
# when Calamares exits.
# restartNowEnabled: true
# DEPRECATED
#
# Initial state of the checkbox "restart now". Only relevant when the
# checkbox is shown by restartNowEnabled.
# restartNowChecked: false
# Behavior of the "restart system now" button.
#
# The example QML for this module offers a "Restart Now" button,
# which the user can click on. It calls directly to the restart
# function. If the user closes the installer in some other way,
# (the "Done" button or close-window) a restart **might** happen:
#
# There are four usable values:
# - never
# Do not restart (this will also block the "Restart Now" button,
# so it is not very useful)
# Does not show the button and does not restart.
# This matches the old behavior with restartNowEnabled=false.
# - user-unchecked
# Do not restart on other ways of closing the window. No checkbox
# is shown in the example QML, so there is no way for the user to
# express a choice -- except by clicking the "Restart Now" button.
# Shows the button, defaults to unchecked, restarts if it is checked.
# This matches the old behavior with restartNowEnabled=true and restartNowChecked=false.
# - user-checked
# Do restart on other ways of closing the window. This makes close
# and "Restart Now" do the same thing. No checkbox is shown by the QML,
# so the machine will **always** restart.
# Shows the button, defaults to checked, restarts if it is checked.
# This matches the old behavior with restartNowEnabled=true and restartNowChecked=true.
# - always
# Same as above.
# Shows the button, checked, but the user cannot change it.
# This is new behavior.
#
# For the **specific** example QML included with this module, only
# *user-unchecked* really makes sense.
# The three combinations of legacy values are still supported.
restartNowMode: user-unchecked
# If the checkbox is shown, and the checkbox is checked, then when
# Calamares exits from the finished-page it will run this command.
# If not set, falls back to "shutdown -r now".
restartNowCommand: "systemctl -i reboot"
# When the last page is (successfully) reached, send a DBus notification
# to the desktop that the installation is done. This works only if the
# user as whom Calamares is run, can reach the regular desktop session bus.
notifyOnFinished: false