2022-08-06 21:08:55 +02:00
|
|
|
#include "./wizard.h"
|
|
|
|
#include "./settings.h"
|
|
|
|
|
|
|
|
// use meta-data of syncthingtray application here
|
|
|
|
#include "resources/../../tray/resources/config.h"
|
|
|
|
|
2022-08-22 23:48:18 +02:00
|
|
|
#include <syncthingconnector/syncthingconfig.h>
|
|
|
|
#include <syncthingconnector/syncthingconnection.h>
|
|
|
|
#include <syncthingconnector/syncthingconnectionsettings.h>
|
|
|
|
|
2022-08-06 21:08:55 +02:00
|
|
|
#include <QCommandLinkButton>
|
|
|
|
#include <QDesktopServices>
|
2022-08-22 23:48:18 +02:00
|
|
|
#include <QFileDialog>
|
2022-08-06 21:08:55 +02:00
|
|
|
#include <QFrame>
|
|
|
|
#include <QLabel>
|
2022-08-22 23:48:18 +02:00
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QProgressBar>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QTimer>
|
2022-08-06 21:08:55 +02:00
|
|
|
#include <QUrl>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
namespace QtGui {
|
|
|
|
|
|
|
|
Wizard *Wizard::s_instance = nullptr;
|
|
|
|
|
|
|
|
Wizard::Wizard(QWidget *parent, Qt::WindowFlags flags)
|
|
|
|
: QWizard(parent, flags)
|
|
|
|
{
|
|
|
|
setWindowTitle(tr("Setup wizard - ") + QStringLiteral(APP_NAME));
|
|
|
|
|
|
|
|
const auto &settings = Settings::values();
|
|
|
|
if (settings.firstLaunch || settings.fakeFirstLaunch) {
|
2022-08-22 23:48:18 +02:00
|
|
|
addPage(new WelcomeWizardPage(this));
|
2022-08-06 21:08:55 +02:00
|
|
|
}
|
2022-08-22 23:48:18 +02:00
|
|
|
addPage(m_detectionPage = new DetectionWizardPage(this));
|
2022-08-06 21:08:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Wizard::~Wizard()
|
|
|
|
{
|
|
|
|
if (this == s_instance) {
|
|
|
|
s_instance = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Wizard *Wizard::instance()
|
|
|
|
{
|
|
|
|
if (!s_instance) {
|
|
|
|
s_instance = new Wizard();
|
|
|
|
s_instance->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
|
}
|
|
|
|
return s_instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
WelcomeWizardPage::WelcomeWizardPage(QWidget *parent)
|
|
|
|
: QWizardPage(parent)
|
|
|
|
{
|
2022-08-08 23:05:55 +02:00
|
|
|
setTitle(tr("Welcome to Syncthing Tray"));
|
|
|
|
setSubTitle(tr("It looks like you're launching Syncthing Tray for the first time."));
|
2022-08-06 21:08:55 +02:00
|
|
|
|
|
|
|
auto *const infoLabel = new QLabel(this);
|
2022-08-06 21:18:34 +02:00
|
|
|
infoLabel->setText(tr(
|
2022-08-06 21:08:55 +02:00
|
|
|
"You must configure how to connect to Syncthing and how to launch Syncthing (if that's wanted) when using Syncthing Tray the first time. A "
|
|
|
|
"guided/automated setup is still in the works so the manual setup is currently the only option."));
|
|
|
|
infoLabel->setWordWrap(true);
|
|
|
|
|
2022-08-22 23:48:18 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-08-06 21:08:55 +02:00
|
|
|
auto *const showSettingsCommand = new QCommandLinkButton(this);
|
|
|
|
showSettingsCommand->setText(tr("Configure connection and launcher settings manually"));
|
|
|
|
showSettingsCommand->setDescription(
|
2022-08-08 23:05:55 +02:00
|
|
|
tr("Note that the connection settings allow importing URL, credentials and API-key from the local Syncthing configuration."));
|
2022-08-06 21:08:55 +02:00
|
|
|
showSettingsCommand->setIcon(QIcon::fromTheme(QStringLiteral("preferences-other")));
|
|
|
|
connect(showSettingsCommand, &QCommandLinkButton::clicked, this, [this] {
|
|
|
|
if (auto *const wizard = qobject_cast<Wizard *>(this->wizard())) {
|
|
|
|
emit wizard->settingsRequested();
|
|
|
|
wizard->close();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
auto *const line = new QFrame(this);
|
|
|
|
line->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
|
|
|
|
line->setFrameShape(QFrame::HLine);
|
|
|
|
line->setFrameShadow(QFrame::Sunken);
|
|
|
|
|
|
|
|
auto *const showDocsCommand = new QCommandLinkButton(this);
|
|
|
|
showDocsCommand->setText(tr("Show Syncthing's documentation"));
|
2022-08-08 23:05:55 +02:00
|
|
|
showDocsCommand->setDescription(tr("It contains general information about configuring Syncthing."));
|
2022-08-06 21:08:55 +02:00
|
|
|
showDocsCommand->setIcon(QIcon::fromTheme(QStringLiteral("help-contents")));
|
|
|
|
connect(showDocsCommand, &QCommandLinkButton::clicked, this, [] { QDesktopServices::openUrl(QStringLiteral("https://docs.syncthing.net/")); });
|
|
|
|
|
|
|
|
auto *const showReadmeCommand = new QCommandLinkButton(this);
|
2022-08-08 23:05:55 +02:00
|
|
|
showReadmeCommand->setText(tr("Show Syncthing Tray's README"));
|
|
|
|
showReadmeCommand->setDescription(tr("It contains documentation about this GUI integration specifically."));
|
2022-08-06 21:08:55 +02:00
|
|
|
showReadmeCommand->setIcon(showDocsCommand->icon());
|
|
|
|
connect(showReadmeCommand, &QCommandLinkButton::clicked, this, [] {
|
|
|
|
if constexpr (std::string_view(APP_VERSION).find('-') == std::string_view::npos) {
|
|
|
|
QDesktopServices::openUrl(QStringLiteral(APP_URL "/blob/v" APP_VERSION "/README.md"));
|
|
|
|
} else {
|
|
|
|
QDesktopServices::openUrl(QStringLiteral(APP_URL "/blob/master/README.md"));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
auto *const layout = new QVBoxLayout;
|
|
|
|
layout->addWidget(infoLabel);
|
2022-08-22 23:48:18 +02:00
|
|
|
if (startWizardCommand) {
|
|
|
|
layout->addWidget(startWizardCommand);
|
|
|
|
}
|
2022-08-06 21:08:55 +02:00
|
|
|
layout->addWidget(showSettingsCommand);
|
|
|
|
layout->addStretch();
|
|
|
|
layout->addWidget(line);
|
|
|
|
layout->addWidget(showDocsCommand);
|
|
|
|
layout->addWidget(showReadmeCommand);
|
|
|
|
setLayout(layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WelcomeWizardPage::isComplete() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-22 23:48:18 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-08-06 21:08:55 +02:00
|
|
|
} // namespace QtGui
|