Detect current Syncthing setup as first step of the wizard

This commit is contained in:
Martchus 2022-08-22 23:48:18 +02:00
parent 800cbcc286
commit a48cf61333
2 changed files with 193 additions and 2 deletions

View File

@ -4,10 +4,20 @@
// 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 <QCommandLinkButton>
#include <QDesktopServices>
#include <QFileDialog>
#include <QFrame>
#include <QLabel>
#include <QMessageBox>
#include <QProgressBar>
#include <QPushButton>
#include <QStringList>
#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
@ -24,8 +34,9 @@ Wizard::Wizard(QWidget *parent, Qt::WindowFlags flags)
const auto &settings = Settings::values();
if (settings.firstLaunch || settings.fakeFirstLaunch) {
addPage(new WelcomeWizardPage());
addPage(new WelcomeWizardPage(this));
}
addPage(m_detectionPage = new DetectionWizardPage(this));
}
Wizard::~Wizard()
@ -56,6 +67,20 @@ WelcomeWizardPage::WelcomeWizardPage(QWidget *parent)
"guided/automated setup is still in the works so the manual setup is currently the only option."));
infoLabel->setWordWrap(true);
QCommandLinkButton *startWizardCommand = nullptr;
if (Settings::values().enableWipFeatures) {
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"));
startWizardCommand->setIcon(QIcon::fromTheme(QStringLiteral("quickwizard")));
connect(startWizardCommand, &QCommandLinkButton::clicked, this, [this] {
if (auto *const wizard = qobject_cast<Wizard *>(this->wizard())) {
wizard->next();
}
});
}
auto *const showSettingsCommand = new QCommandLinkButton(this);
showSettingsCommand->setText(tr("Configure connection and launcher settings manually"));
showSettingsCommand->setDescription(
@ -93,6 +118,9 @@ WelcomeWizardPage::WelcomeWizardPage(QWidget *parent)
auto *const layout = new QVBoxLayout;
layout->addWidget(infoLabel);
if (startWizardCommand) {
layout->addWidget(startWizardCommand);
}
layout->addWidget(showSettingsCommand);
layout->addStretch();
layout->addWidget(line);
@ -106,4 +134,116 @@ bool WelcomeWizardPage::isComplete() const
return false;
}
DetectionWizardPage::DetectionWizardPage(QWidget *parent)
: QWizardPage(parent)
, m_connection(nullptr)
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
, m_service(nullptr)
#endif
, m_configOk(false)
{
setTitle(tr("Checking current Syncthing setup"));
setSubTitle(tr("Initializing …"));
m_progressBar = new QProgressBar(this);
m_progressBar->setMinimum(0);
m_progressBar->setMaximum(0);
m_progressBar->setVisible(false);
m_logLabel = new QLabel(this);
auto *const layout = new QVBoxLayout;
layout->addWidget(m_progressBar);
layout->addWidget(m_logLabel);
setLayout(layout);
}
bool DetectionWizardPage::isComplete() const
{
return m_configOk && !m_config.guiAddress.isEmpty() && !m_config.guiApiKey.isEmpty();
}
void DetectionWizardPage::initializePage()
{
m_progressBar->setVisible(true);
m_configOk = false;
m_connectionErrors.clear();
emit completeChanged();
QTimer::singleShot(0, this, &DetectionWizardPage::tryToConnect);
}
void DetectionWizardPage::cleanupPage()
{
m_progressBar->setVisible(false);
if (m_connection) {
m_connection->abortAllRequests();
}
}
void DetectionWizardPage::tryToConnect()
{
setSubTitle(tr("Checking whether Syncthing is already running …"));
m_configFilePath = Data::SyncthingConfig::locateConfigFile();
m_certPath = Data::SyncthingConfig::locateHttpsCertificate();
if (m_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"));
msgbox.setIcon(QMessageBox::Question);
msgbox.setText(
tr("It looks like Syncthing has not been running on this system before as its configuration cannot be found. Is that correct?"));
msgbox.addButton(&yesButton, QMessageBox::YesRole);
msgbox.addButton(&noButton, QMessageBox::NoRole);
msgbox.exec();
if (msgbox.clickedButton() == &noButton) {
m_configFilePath = QFileDialog::getOpenFileName(
wizard(), tr("Select Syncthing's configuration file"), QString(), QStringLiteral("XML files (*.xml);All files (*.*)"));
}
}
m_configOk = m_config.restore(m_configFilePath);
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();
}
void DetectionWizardPage::handleConnectionStatusChanged()
{
if (m_connection->isConnecting()) {
return;
}
showSummary();
}
void DetectionWizardPage::handleConnectionError(const QString &error)
{
m_connectionErrors << QStringLiteral(" - ") + error;
}
void DetectionWizardPage::showSummary()
{
auto info = QStringList();
if (m_configFilePath.isEmpty()) {
info << tr("Unable to locate Syncthing config file.");
} else {
info << tr("Located Syncthing config file: ") + m_configFilePath;
if (isComplete()) {
info << tr("Syncthing config file looks ok.");
} else {
info << tr("Syncthing config file looks invalid/incomplete.");
}
}
if (m_connection->isConnected()) {
info << tr("Could connect to Syncthing under: ") + m_connection->syncthingUrl();
}
if (!m_connectionErrors.isEmpty()) {
info << tr("Connection errors:");
info << m_connectionErrors;
}
emit completeChanged();
setSubTitle(tr("[Some summary should go here]. Select how to proceed."));
m_logLabel->setText(info.join(QChar('\n')));
m_progressBar->setVisible(false);
}
} // namespace QtGui

View File

@ -3,11 +3,25 @@
#include "../global.h"
#include <syncthingconnector/syncthingconfig.h>
#include <QWizard>
#include <QWizardPage>
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 SYNCTHINGWIDGETS_EXPORT Wizard : public QWizard {
Q_OBJECT
@ -16,15 +30,22 @@ public:
~Wizard() override;
static Wizard *instance();
DetectionWizardPage *detectionPage() const;
Q_SIGNALS:
void settingsRequested();
private:
static Wizard *s_instance;
DetectionWizardPage *m_detectionPage;
};
class SYNCTHINGWIDGETS_EXPORT WelcomeWizardPage : public QWizardPage {
inline DetectionWizardPage *Wizard::detectionPage() const
{
return m_detectionPage;
}
class SYNCTHINGWIDGETS_EXPORT WelcomeWizardPage final : public QWizardPage {
Q_OBJECT
public:
@ -33,6 +54,36 @@ public:
bool isComplete() const override;
};
class SYNCTHINGWIDGETS_EXPORT DetectionWizardPage final : public QWizardPage {
Q_OBJECT
public:
explicit DetectionWizardPage(QWidget *parent = nullptr);
bool isComplete() const override;
void initializePage() override;
void cleanupPage() override;
private Q_SLOTS:
void tryToConnect();
void handleConnectionStatusChanged();
void handleConnectionError(const QString &error);
void showSummary();
private:
QString m_configFilePath;
QString m_certPath;
QStringList m_connectionErrors;
Data::SyncthingConfig m_config;
Data::SyncthingConnection *m_connection;
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
Data::SyncthingService *m_service;
#endif
QProgressBar *m_progressBar;
QLabel *m_logLabel;
bool m_configOk;
};
} // namespace QtGui
#endif // SETTINGS_WIZARD_H