Refactor wizard code

* Move code for setup detection into its own class
* Use separate wizard page to show setup detection report
This commit is contained in:
Martchus 2022-08-23 18:19:47 +02:00
parent 352d161144
commit c31b7b9ca8
5 changed files with 350 additions and 224 deletions

View File

@ -26,6 +26,8 @@ set(WIDGETS_HEADER_FILES
set(WIDGETS_SRC_FILES
settings/settings.cpp
settings/settingsdialog.cpp
settings/setupdetection.h
settings/setupdetection.cpp
settings/wizard.cpp
webview/webpage.cpp
webview/webviewdialog.cpp

View File

@ -0,0 +1,136 @@
#include "./setupdetection.h"
#if defined(LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD) && (defined(PLATFORM_UNIX) || defined(PLATFORM_MINGW) || defined(PLATFORM_CYGWIN))
#define PLATFORM_HAS_GETLOGIN
#include <unistd.h>
#endif
namespace QtGui {
SetupDetection::SetupDetection(QObject *parent)
: QObject(parent)
{
// assume default service names
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
userService.setUnitName(QStringLiteral("syncthing.service"));
systemService.setUnitName(QStringLiteral("syncthing@") %
#ifdef PLATFORM_HAS_GETLOGIN
QString::fromLocal8Bit(getlogin()) %
#endif
QStringLiteral(".service"));
#endif
// configure launcher to test invocation of "syncthing --version" capturing output
launcherSettings.syncthingArgs = QStringLiteral("--version");
launcher.setEmittingOutput(true);
// configure timeout
timeout.setInterval(2500);
timeout.setSingleShot(true);
// connect signals & slots
connect(&connection, &Data::SyncthingConnection::error, this, &SetupDetection::handleConnectionError);
connect(&connection, &Data::SyncthingConnection::statusChanged, this, &SetupDetection::checkDone);
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
connect(&userService, &Data::SyncthingService::unitFileStateChanged, this, &SetupDetection::checkDone);
connect(&systemService, &Data::SyncthingService::unitFileStateChanged, this, &SetupDetection::checkDone);
#endif
connect(&launcher, &Data::SyncthingLauncher::outputAvailable, this, &SetupDetection::handleLauncherOutput);
connect(&launcher, &Data::SyncthingLauncher::exited, this, &SetupDetection::handleLauncherExit);
connect(&launcher, &Data::SyncthingLauncher::errorOccurred, this, &SetupDetection::handleLauncherError);
connect(&timeout, &QTimer::timeout, this, &SetupDetection::handleTimeout);
}
void SetupDetection::determinePaths()
{
configFilePath = Data::SyncthingConfig::locateConfigFile();
certPath = Data::SyncthingConfig::locateHttpsCertificate();
}
void SetupDetection::restoreConfig()
{
configOk = config.restore(configFilePath);
}
void SetupDetection::initConnection()
{
connection.setSyncthingUrl(config.syncthingUrl());
connection.setApiKey(config.guiApiKey.toLocal8Bit());
}
bool SetupDetection::hasConfig() const
{
return configOk && !config.guiAddress.isEmpty() && !config.guiApiKey.isEmpty();
}
bool SetupDetection::isDone() const
{
return timedOut
|| (!connection.isConnecting() && (launcherExitCode.has_value() || launcherError.has_value())
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
&& !userService.unitFileState().isEmpty() && !systemService.unitFileState().isEmpty()
#endif
);
}
void SetupDetection::reset()
{
timeout.stop();
timedOut = false;
configOk = false;
connection.abortAllRequests();
launcher.terminate();
connectionErrors.clear();
launcherExitCode.reset();
launcherExitStatus.reset();
launcherError.reset();
launcherOutput.clear();
}
void SetupDetection::startTest()
{
restoreConfig();
initConnection();
connection.reconnect();
launcher.launch(launcherSettings);
timeout.start();
}
void SetupDetection::handleConnectionError(const QString &error)
{
connectionErrors << QStringLiteral(" - ") + error;
}
void SetupDetection::handleLauncherExit(int exitCode, QProcess::ExitStatus exitStatus)
{
launcherExitCode = exitCode;
launcherExitStatus = exitStatus;
checkDone();
}
void SetupDetection::handleLauncherError(QProcess::ProcessError error)
{
launcherError = error;
checkDone();
}
void SetupDetection::handleLauncherOutput(const QByteArray &output)
{
launcherOutput.append(output);
}
void SetupDetection::handleTimeout()
{
timedOut = true;
checkDone();
}
void SetupDetection::checkDone()
{
if (isDone()) {
timeout.stop();
emit done();
}
}
} // namespace QtGui

View File

@ -0,0 +1,72 @@
#ifndef SETTINGS_SETUP_DETECTION_H
#define SETTINGS_SETUP_DETECTION_H
#include "./settings.h"
#include "../misc/syncthinglauncher.h"
#include <syncthingconnector/syncthingconfig.h>
#include <syncthingconnector/syncthingconnection.h>
#include <syncthingconnector/syncthingconnectionsettings.h>
#include <syncthingconnector/syncthingservice.h>
#include <QByteArray>
#include <QProcess>
#include <QStringBuilder>
#include <QTimer>
#include <memory>
#include <optional>
namespace QtGui {
class SetupDetection : public QObject {
Q_OBJECT
public:
explicit SetupDetection(QObject *parent = nullptr);
bool hasConfig() const;
bool isDone() const;
public Q_SLOTS:
void determinePaths();
void restoreConfig();
void initConnection();
void reset();
void startTest();
Q_SIGNALS:
void done();
private Q_SLOTS:
void handleConnectionError(const QString &error);
void handleLauncherExit(int exitCode, QProcess::ExitStatus exitStatus);
void handleLauncherError(QProcess::ProcessError error);
void handleLauncherOutput(const QByteArray &output);
void handleTimeout();
void checkDone();
public:
QString configFilePath;
QString certPath;
QStringList connectionErrors;
Data::SyncthingConfig config;
Data::SyncthingConnection connection;
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
Data::SyncthingService userService = Data::SyncthingService(Data::SystemdScope::User);
Data::SyncthingService systemService = Data::SyncthingService(Data::SystemdScope::System);
#endif
Settings::Launcher launcherSettings;
Data::SyncthingLauncher launcher;
std::optional<int> launcherExitCode;
std::optional<QProcess::ExitStatus> launcherExitStatus;
std::optional<QProcess::ProcessError> launcherError;
QByteArray launcherOutput;
QTimer timeout;
bool timedOut = false;
bool configOk = false;
};
} // namespace QtGui
#endif // SETTINGS_SETUP_DETECTION_H

View File

@ -1,17 +1,12 @@
#include "./wizard.h"
#include "./settings.h"
#include "./setupdetection.h"
#include "../misc/statusinfo.h"
#include "../misc/syncthinglauncher.h"
// use meta-data of syncthingtray application here
#include "resources/../../tray/resources/config.h"
#include <syncthingconnector/syncthingconfig.h>
#include <syncthingconnector/syncthingconnection.h>
#include <syncthingconnector/syncthingconnectionsettings.h>
#include <syncthingconnector/syncthingservice.h>
#include <QCheckBox>
#include <QCommandLinkButton>
#include <QDesktopServices>
#include <QFileDialog>
@ -20,20 +15,12 @@
#include <QMessageBox>
#include <QProgressBar>
#include <QPushButton>
#include <QStringBuilder>
#include <QStringList>
#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
#include <initializer_list>
#include <string_view>
#if defined(LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD) && (defined(PLATFORM_UNIX) || defined(PLATFORM_MINGW) || defined(PLATFORM_CYGWIN))
#define PLATFORM_HAS_GETLOGIN
#include <unistd.h>
#endif
namespace QtGui {
Wizard *Wizard::s_instance = nullptr;
@ -47,7 +34,11 @@ Wizard::Wizard(QWidget *parent, Qt::WindowFlags flags)
if (settings.firstLaunch || settings.fakeFirstLaunch) {
addPage(new WelcomeWizardPage(this));
}
addPage(m_detectionPage = new DetectionWizardPage(this));
auto *const detectionPage = new DetectionWizardPage(this);
auto *const mainConfigPage = new MainConfigWizardPage(this);
connect(mainConfigPage, &MainConfigWizardPage::retry, detectionPage, &DetectionWizardPage::refresh);
addPage(detectionPage);
addPage(mainConfigPage);
}
Wizard::~Wizard()
@ -66,6 +57,14 @@ Wizard *Wizard::instance()
return s_instance;
}
SetupDetection &Wizard::setupDetection()
{
if (!m_setupDetection) {
m_setupDetection = std::make_unique<SetupDetection>();
}
return *m_setupDetection;
}
WelcomeWizardPage::WelcomeWizardPage(QWidget *parent)
: QWizardPage(parent)
{
@ -83,13 +82,9 @@ WelcomeWizardPage::WelcomeWizardPage(QWidget *parent)
startWizardCommand = new QCommandLinkButton(this);
startWizardCommand->setText(tr("Start guided setup"));
startWizardCommand->setDescription(
tr("Allows to configure Syncthing Tray automatically for the local Syncthing instance, helps you starting Syncthing if wanted"));
tr("Allows to configure Syncthing Tray automatically for the local Syncthing instance and helps you starting Syncthing if wanted."));
startWizardCommand->setIcon(QIcon::fromTheme(QStringLiteral("quickwizard")));
connect(startWizardCommand, &QCommandLinkButton::clicked, this, [this] {
if (auto *const wizard = qobject_cast<Wizard *>(this->wizard())) {
wizard->next();
}
});
connect(startWizardCommand, &QCommandLinkButton::clicked, this, [this] { this->wizard()->next(); });
}
auto *const showSettingsCommand = new QCommandLinkButton(this);
@ -147,78 +142,54 @@ bool WelcomeWizardPage::isComplete() const
DetectionWizardPage::DetectionWizardPage(QWidget *parent)
: QWizardPage(parent)
, m_connection(nullptr)
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
, m_userService(nullptr)
, m_systemService(nullptr)
#endif
, m_launcher(nullptr)
, m_timedOut(false)
, m_configOk(false)
{
setTitle(tr("Checking current Syncthing setup"));
setSubTitle(tr("Initializing"));
setSubTitle(tr("Checking Syncthing configuration and whether Syncthing is already running or can be started …"));
m_timeoutTimer.setInterval(1000);
m_timeoutTimer.setSingleShot(true);
m_progressBar = new QProgressBar(this);
m_progressBar->setMinimum(0);
m_progressBar->setMaximum(0);
m_progressBar->setVisible(false);
m_logLabel = new QLabel(this);
auto *const progressBar = new QProgressBar(this);
progressBar->setMinimum(0);
progressBar->setMaximum(0);
auto *const layout = new QVBoxLayout;
layout->addWidget(m_progressBar);
layout->addWidget(m_logLabel);
layout->addWidget(progressBar);
setLayout(layout);
}
bool DetectionWizardPage::isComplete() const
{
return m_configOk && !m_config.guiAddress.isEmpty() && !m_config.guiApiKey.isEmpty();
return m_setupDetection && m_setupDetection->isDone();
}
void DetectionWizardPage::initializePage()
{
m_progressBar->setVisible(true);
m_configOk = false;
m_connectionErrors.clear();
m_launcherExitCode.reset();
m_launcherExitStatus.reset();
m_launcherError.reset();
m_launcherOutput.clear();
auto *const wizard = qobject_cast<Wizard *>(this->wizard());
if (!wizard) {
return;
}
m_setupDetection = &wizard->setupDetection();
m_setupDetection->reset();
emit completeChanged();
QTimer::singleShot(0, this, &DetectionWizardPage::tryToConnect);
}
void DetectionWizardPage::cleanupPage()
{
m_progressBar->setVisible(false);
if (m_connection) {
m_connection->abortAllRequests();
}
if (m_launcher && m_launcher->isRunning()) {
m_launcher->terminate();
if (m_setupDetection) {
m_setupDetection->disconnect(this);
m_setupDetection->reset();
}
}
void DetectionWizardPage::refresh()
{
initializePage();
}
void DetectionWizardPage::tryToConnect()
{
setSubTitle(tr("Checking whether Syncthing is already running …"));
// cleanup old instances possibly still present from previous check
for (auto *instance : std::initializer_list<QObject *>{ m_connection, m_userService, m_systemService, m_launcher }) {
if (instance) {
instance->deleteLater();
}
}
// read Syncthing's config file
m_configFilePath = Data::SyncthingConfig::locateConfigFile();
m_certPath = Data::SyncthingConfig::locateHttpsCertificate();
if (m_configFilePath.isEmpty()) {
// determine path of Syncthing's config file, possibly ask user to select it
m_setupDetection->determinePaths();
if (m_setupDetection->configFilePath.isEmpty()) {
auto msgbox = QMessageBox(wizard());
auto yesButton = QPushButton(tr("Yes, continue configuration"));
auto noButton = QPushButton(tr("No, let me select Syncthing's configuration file manually"));
@ -229,107 +200,61 @@ void DetectionWizardPage::tryToConnect()
msgbox.addButton(&noButton, QMessageBox::NoRole);
msgbox.exec();
if (msgbox.clickedButton() == &noButton) {
m_configFilePath = QFileDialog::getOpenFileName(
m_setupDetection->configFilePath = QFileDialog::getOpenFileName(
wizard(), tr("Select Syncthing's configuration file"), QString(), QStringLiteral("XML files (*.xml);All files (*.*)"));
}
}
m_configOk = m_config.restore(m_configFilePath);
// attempt connecting to Syncthing
m_connection = new Data::SyncthingConnection(
m_config.syncthingUrl(), m_config.guiApiKey.toUtf8(), Data::SyncthingConnectionLoggingFlags::FromEnvironment, this);
connect(m_connection, &Data::SyncthingConnection::error, this, &DetectionWizardPage::handleConnectionError);
connect(m_connection, &Data::SyncthingConnection::statusChanged, this, &DetectionWizardPage::handleConnectionStatusChanged);
m_connection->connect();
// checkout availability of systemd services
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
m_userService = new Data::SyncthingService(Data::SystemdScope::User, this);
m_userService->setUnitName(QStringLiteral("syncthing.service"));
m_systemService = new Data::SyncthingService(Data::SystemdScope::System, this);
m_systemService->setUnitName(QStringLiteral("syncthing@") %
#ifdef PLATFORM_HAS_GETLOGIN
QString::fromLocal8Bit(getlogin()) %
#endif
QStringLiteral(".service"));
connect(m_userService, &Data::SyncthingService::unitFileStateChanged, this, &DetectionWizardPage::continueWithSummaryIfDone);
connect(m_systemService, &Data::SyncthingService::unitFileStateChanged, this, &DetectionWizardPage::continueWithSummaryIfDone);
#endif
// check whether we could launch Syncthing as external binary
auto launcherSettings = Settings::Launcher();
launcherSettings.syncthingArgs = QStringLiteral("--version");
m_launcher = new Data::SyncthingLauncher(this);
m_launcher->setEmittingOutput(true);
connect(m_launcher, &Data::SyncthingLauncher::outputAvailable, this, &DetectionWizardPage::handleLauncherOutput);
connect(m_launcher, &Data::SyncthingLauncher::exited, this, &DetectionWizardPage::handleLauncherExit);
connect(m_launcher, &Data::SyncthingLauncher::errorOccurred, this, &DetectionWizardPage::handleLauncherError);
m_launcher->launch(launcherSettings);
// setup a timeout
m_timeoutTimer.stop();
m_timedOut = false;
m_timeoutTimer.start();
// start setup detection tests
connect(m_setupDetection, &SetupDetection::done, this, &DetectionWizardPage::continueIfDone);
m_setupDetection->startTest();
}
void DetectionWizardPage::handleConnectionStatusChanged()
void DetectionWizardPage::continueIfDone()
{
if (m_connection->isConnecting()) {
m_setupDetection->disconnect(this);
emit completeChanged();
wizard()->next();
}
MainConfigWizardPage::MainConfigWizardPage(QWidget *parent)
: QWizardPage(parent)
, m_detailsLabel(new QLabel(this))
{
setTitle(tr("Select what configuration to apply"));
setSubTitle(tr("Something when wrong when checking the Syncthing setup."));
auto *const showDetailsCheckBox = new QCheckBox(this);
showDetailsCheckBox->setText(tr("Show report from detecting the local Syncthing setup"));
m_detailsLabel->setVisible(false);
m_detailsLabel->setWordWrap(true);
connect(showDetailsCheckBox, &QCheckBox::toggled, m_detailsLabel, &QLabel::setVisible);
auto *const layout = new QVBoxLayout;
layout->addWidget(showDetailsCheckBox);
layout->addWidget(m_detailsLabel);
setLayout(layout);
}
bool MainConfigWizardPage::isComplete() const
{
return false;
}
void MainConfigWizardPage::initializePage()
{
auto *const wizard = qobject_cast<Wizard *>(this->wizard());
if (!wizard) {
return;
}
showSummary();
}
void DetectionWizardPage::handleConnectionError(const QString &error)
{
m_connectionErrors << QStringLiteral(" - ") + error;
}
void DetectionWizardPage::handleLauncherExit(int exitCode, QProcess::ExitStatus exitStatus)
{
m_launcherExitCode = exitCode;
m_launcherExitStatus = exitStatus;
continueWithSummaryIfDone();
}
void DetectionWizardPage::handleLauncherError(QProcess::ProcessError error)
{
m_launcherError = error;
continueWithSummaryIfDone();
}
void DetectionWizardPage::handleLauncherOutput(const QByteArray &output)
{
m_launcherOutput.append(output);
}
void DetectionWizardPage::handleTimeout()
{
m_timedOut = true;
continueWithSummaryIfDone();
}
void DetectionWizardPage::continueWithSummaryIfDone()
{
if (m_timedOut
|| (!m_connection->isConnecting() && (m_launcherExitCode.has_value() || m_launcherError.has_value())
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
&& !m_userService->unitFileState().isEmpty() && !m_systemService->unitFileState().isEmpty()
#endif
)) {
showSummary();
}
}
void DetectionWizardPage::showSummary()
{
auto info = QStringList();
// add config info
if (m_configFilePath.isEmpty()) {
auto const &detection = wizard->setupDetection();
auto info = QStringList();
if (detection.configFilePath.isEmpty()) {
info << tr("Unable to locate Syncthing config file.");
} else {
info << tr("Located Syncthing config file: ") + m_configFilePath;
info << tr("Located Syncthing config file: ") + detection.configFilePath;
if (isComplete()) {
info << tr("Syncthing config file looks ok.");
} else {
@ -338,43 +263,56 @@ void DetectionWizardPage::showSummary()
}
// add connection info
if (m_connection->isConnected()) {
if (detection.connection.isConnected()) {
auto statusInfo = StatusInfo();
statusInfo.updateConnectionStatus(*m_connection);
statusInfo.updateConnectionStatus(*m_connection);
info << tr("Could connect to Syncthing under: ") + m_connection->syncthingUrl();
info << tr("Syncthing's version: ") + m_connection->syncthingVersion();
info << tr("Syncthing's device ID: ") + m_connection->myId();
info << tr("Syncthing's status: ") + statusInfo.statusText();
statusInfo.updateConnectionStatus(detection.connection);
statusInfo.updateConnectionStatus(detection.connection);
info << tr("Could connect to Syncthing under: ") + detection.connection.syncthingUrl();
info << tr("Syncthing version: ") + detection.connection.syncthingVersion();
info << tr("Syncthing device ID: ") + detection.connection.myId();
info << tr("Syncthing status: ") + statusInfo.statusText();
if (!statusInfo.additionalStatusText().isEmpty()) {
info << tr("Additional Syncthing status info: ") + statusInfo.additionalStatusText();
}
}
if (!m_connectionErrors.isEmpty()) {
if (!detection.connectionErrors.isEmpty()) {
info << tr("Connection errors:");
info << m_connectionErrors;
info << detection.connectionErrors;
}
// add systemd service info
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
info << tr("State of systemd user service \"%1\": ").arg(m_userService->unitName()) + m_userService->unitFileState();
info << tr("State of systemd system service \"%1\": ").arg(m_systemService->unitName()) + m_systemService->unitFileState();
info << tr("State of systemd user unit file \"%1\": ").arg(detection.userService.unitName()) + detection.userService.unitFileState();
info << tr("State of systemd system unit file \"%1\": ").arg(detection.systemService.unitName()) + detection.systemService.unitFileState();
#endif
// add launcher info
if (m_launcherExitCode.has_value() && m_launcherExitStatus.value() == QProcess::NormalExit) {
info << tr("Could test-launch Syncthing successfully, exit code: ") + QString::number(m_launcherExitCode.value());
info << tr("Syncthing version returned from test-launch: ") + QString::fromLocal8Bit(m_launcherOutput.trimmed());
const auto successfulTestLaunch = detection.launcherExitCode.has_value() && detection.launcherExitStatus.value() == QProcess::NormalExit;
if (successfulTestLaunch) {
info << tr("Could test-launch Syncthing successfully, exit code: ") + QString::number(detection.launcherExitCode.value());
info << tr("Syncthing version returned from test-launch: ") + QString::fromLocal8Bit(detection.launcherOutput.trimmed());
} else {
info << tr("Unable to test-launch Syncthing: ") + m_launcher->errorString();
info << tr("Unable to test-launch Syncthing: ") + detection.launcher.errorString();
}
info << tr("Built-in Syncthing available: ") + (Data::SyncthingLauncher::isLibSyncthingAvailable() ? tr("yes") : tr("no"));
// update UI
emit completeChanged();
setSubTitle(tr("[Some summary should go here]. Select how to proceed."));
m_logLabel->setText(info.join(QChar('\n')));
m_progressBar->setVisible(false);
// add details info
m_detailsLabel->setText(QStringLiteral("<ul><li>") % info.join(QStringLiteral("</li><li>")) % QStringLiteral("</ul>"));
// add short summary
if (detection.connection.isConnected()) {
setSubTitle(tr("Looks like Syncthing is already running and Syncthing Tray can be configured accordingly automatically."));
} else if (successfulTestLaunch || Data::SyncthingLauncher::isLibSyncthingAvailable()) {
setSubTitle(tr("Looks like Syncthing is not running yet. You can launch it via Syncthing Tray."));
} else {
setSubTitle(tr("Looks like Syncthing is not running yet and needs to be installed before Syncthing Tray can be configured."));
}
}
void MainConfigWizardPage::cleanupPage()
{
m_detailsLabel->clear();
emit retry();
}
} // namespace QtGui

View File

@ -3,29 +3,16 @@
#include "../global.h"
#include <syncthingconnector/syncthingconfig.h>
#include <QByteArray>
#include <QProcess>
#include <QTimer>
#include <QWizard>
#include <QWizardPage>
#include <optional>
#include <memory>
QT_FORWARD_DECLARE_CLASS(QProgressBar)
QT_FORWARD_DECLARE_CLASS(QLabel)
namespace Data {
class SyncthingConnection;
class SyncthingService;
class SyncthingProcess;
class SyncthingLauncher;
} // namespace Data
namespace QtGui {
class DetectionWizardPage;
class SetupDetection;
class SYNCTHINGWIDGETS_EXPORT Wizard : public QWizard {
Q_OBJECT
@ -35,21 +22,16 @@ public:
~Wizard() override;
static Wizard *instance();
DetectionWizardPage *detectionPage() const;
SetupDetection &setupDetection();
Q_SIGNALS:
void settingsRequested();
private:
static Wizard *s_instance;
DetectionWizardPage *m_detectionPage;
std::unique_ptr<SetupDetection> m_setupDetection;
};
inline DetectionWizardPage *Wizard::detectionPage() const
{
return m_detectionPage;
}
class SYNCTHINGWIDGETS_EXPORT WelcomeWizardPage final : public QWizardPage {
Q_OBJECT
@ -69,36 +51,32 @@ public:
void initializePage() override;
void cleanupPage() override;
public Q_SLOTS:
void refresh();
private Q_SLOTS:
void tryToConnect();
void handleConnectionStatusChanged();
void handleConnectionError(const QString &error);
void handleLauncherExit(int exitCode, QProcess::ExitStatus exitStatus);
void handleLauncherError(QProcess::ProcessError error);
void handleLauncherOutput(const QByteArray &output);
void handleTimeout();
void continueWithSummaryIfDone();
void showSummary();
void continueIfDone();
private:
QString m_configFilePath;
QString m_certPath;
QStringList m_connectionErrors;
Data::SyncthingConfig m_config;
Data::SyncthingConnection *m_connection;
Data::SyncthingService *m_userService;
Data::SyncthingService *m_systemService;
Data::SyncthingLauncher *m_launcher;
QTimer m_timeoutTimer;
SetupDetection *m_setupDetection;
};
QProgressBar *m_progressBar;
QLabel *m_logLabel;
std::optional<int> m_launcherExitCode;
std::optional<QProcess::ExitStatus> m_launcherExitStatus;
std::optional<QProcess::ProcessError> m_launcherError;
QByteArray m_launcherOutput;
bool m_timedOut;
bool m_configOk;
class SYNCTHINGWIDGETS_EXPORT MainConfigWizardPage final : public QWizardPage {
Q_OBJECT
public:
explicit MainConfigWizardPage(QWidget *parent = nullptr);
bool isComplete() const override;
void initializePage() override;
void cleanupPage() override;
Q_SIGNALS:
void retry();
private:
QLabel *m_detailsLabel;
};
} // namespace QtGui