diff options
author | Fabian Müller <fmueller@owncloud.com> | 2022-03-30 21:54:47 +0300 |
---|---|---|
committer | Hannah von Reth <vonreth@kde.org> | 2022-04-12 15:51:18 +0300 |
commit | a25f0068e1353f116c8ca251bf608fe2e4e794b1 (patch) | |
tree | f813f18abb5f43392315e2007dcccd38c1b3bdeb /src/gui/newwizard | |
parent | 44db53318351b061ba2db4c7bf6b30a789b8f8b1 (diff) |
Implement advanced sync options in wizard
Diffstat (limited to 'src/gui/newwizard')
-rw-r--r-- | src/gui/newwizard/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/gui/newwizard/pages/accountconfiguredwizardpage.cpp | 146 | ||||
-rw-r--r-- | src/gui/newwizard/pages/accountconfiguredwizardpage.h | 9 | ||||
-rw-r--r-- | src/gui/newwizard/pages/accountconfiguredwizardpage.ui | 196 | ||||
-rw-r--r-- | src/gui/newwizard/setupwizardcontroller.cpp | 48 | ||||
-rw-r--r-- | src/gui/newwizard/setupwizardcontroller.h | 3 | ||||
-rw-r--r-- | src/gui/newwizard/syncmode.cpp | 2 | ||||
-rw-r--r-- | src/gui/newwizard/syncmode.h | 15 |
8 files changed, 410 insertions, 11 deletions
diff --git a/src/gui/newwizard/CMakeLists.txt b/src/gui/newwizard/CMakeLists.txt index 28e188870..df390431e 100644 --- a/src/gui/newwizard/CMakeLists.txt +++ b/src/gui/newwizard/CMakeLists.txt @@ -33,6 +33,8 @@ add_library(newwizard OBJECT jobs/resolveurljobfactory.cpp jobs/resolveurljobfactory.h + + syncmode.cpp ) target_link_libraries(newwizard PUBLIC Qt5::Widgets libsync) set_target_properties(newwizard PROPERTIES AUTOUIC ON AUTORCC ON) diff --git a/src/gui/newwizard/pages/accountconfiguredwizardpage.cpp b/src/gui/newwizard/pages/accountconfiguredwizardpage.cpp index f0bf2077c..3e1bc1739 100644 --- a/src/gui/newwizard/pages/accountconfiguredwizardpage.cpp +++ b/src/gui/newwizard/pages/accountconfiguredwizardpage.cpp @@ -1,20 +1,160 @@ #include "accountconfiguredwizardpage.h" -#include <QMessageBox> -#include "gui/selectivesyncdialog.h" #include "theme.h" #include "ui_accountconfiguredwizardpage.h" +#include <QDir> +#include <QFileDialog> +#include <QMessageBox> + namespace OCC::Wizard { -AccountConfiguredWizardPage::AccountConfiguredWizardPage() +AccountConfiguredWizardPage::AccountConfiguredWizardPage(const QString &defaultSyncTargetDir, bool vfsIsAvailable, bool enableVfsByDefault, bool vfsModeIsExperimental) : _ui(new ::Ui::AccountConfiguredWizardPage) { _ui->setupUi(this); + + // by default, sync everything to an automatically chosen directory, VFS use depends on the OS + // the defaults are provided by the controller + _ui->localDirectoryLineEdit->setText(QDir::toNativeSeparators(defaultSyncTargetDir)); + _ui->syncEverythingRadioButton->setChecked(true); + + // could also make it invisible, but then the UX is different for different installations + // this may be overwritten by a branding option (see below) + _ui->useVfsRadioButton->setEnabled(vfsIsAvailable); + + _ui->useVfsRadioButton->setText(tr("Use &virtual files instead of downloading content immediately")); + if (vfsModeIsExperimental) { + _ui->useVfsRadioButton->setIcon(QIcon(QStringLiteral(":/client/resources/light/warning.svg"))); + } + + // just adjusting the visibility should be sufficient for these branding options + if (Theme::instance()->wizardSkipAdvancedPage()) { + _ui->advancedConfigSeparatorLine->setVisible(false); + _ui->advancedConfigGroupBox->setVisible(false); + } + + if (!Theme::instance()->showVirtualFilesOption()) { + _ui->useVfsRadioButton->setVisible(false); + vfsIsAvailable = false; + } + + if (!vfsIsAvailable) { + enableVfsByDefault = false; + } + + if (enableVfsByDefault) { + _ui->useVfsRadioButton->setChecked(true); + + // move up top + _ui->syncModeGroupBoxLayout->removeWidget(_ui->useVfsRadioButton); + _ui->syncModeGroupBoxLayout->insertWidget(0, _ui->useVfsRadioButton); + } + + if (!vfsIsAvailable) { + // fallback: it's set as default option in Qt Designer, but we should make sure the option is selected if VFS is not available + _ui->syncEverythingRadioButton->setChecked(true); + + _ui->useVfsRadioButton->setToolTip(tr("The virtual filesystem feature is not available for this installation.")); + } else if (vfsModeIsExperimental) { + _ui->useVfsRadioButton->setToolTip(tr("The virtual filesystem feature is not stable yet. Use with caution.")); + } + + connect(_ui->chooseLocalDirectoryButton, &QToolButton::clicked, this, [=]() { + auto dialog = new QFileDialog(this, tr("Choose"), defaultSyncTargetDir); + dialog->setFileMode(QFileDialog::Directory); + dialog->setOption(QFileDialog::ShowDirsOnly); + + connect(dialog, &QFileDialog::fileSelected, this, [this](const QString &directory) { + // the directory chooser should guarantee that the directory exists + Q_ASSERT(QDir(directory).exists()); + + _ui->localDirectoryLineEdit->setText(QDir::toNativeSeparators(directory)); + }); + + dialog->show(); + }); + + // this should be handled on application startup, too + OC_ENFORCE(!Theme::instance()->forceVirtualFilesOption() || vfsIsAvailable); + + if (Theme::instance()->forceVirtualFilesOption()) { + // this has no visual effect, but is needed for syncMode() + _ui->useVfsRadioButton->setChecked(true); + + // we want to hide the entire sync mode selection from the user, not just disable it + _ui->syncModeGroupBox->setVisible(false); + } + + connect(_ui->advancedConfigGroupBox, &QGroupBox::toggled, this, [this](bool enabled) { + // layouts cannot be hidden, therefore we use a plain widget within the group box to "house" the contained widgets + _ui->advancedConfigGroupBoxContentWidget->setVisible(enabled); + + // could not find a better way to hide the frame on demand, which is needed to hide the widget completely + _ui->advancedConfigGroupBox->setStyleSheet(enabled ? QString() : QStringLiteral("QGroupBox#advancedConfigGroupBox{border: 0}")); + }); + + if (vfsModeIsExperimental) { + connect(_ui->useVfsRadioButton, &QRadioButton::clicked, this, [this]() { + auto messageBox = new QMessageBox( + QMessageBox::Warning, + tr("Enable experimental feature?"), + tr("When the \"virtual files\" mode is enabled no files will be downloaded initially. " + "Instead, a tiny file will be created for each file that exists on the server. " + "The contents can be downloaded by running these files or by using their context menu." + "\n\n" + "The virtual files mode is mutually exclusive with selective sync. " + "Currently unselected folders will be translated to online-only folders " + "and your selective sync settings will be reset." + "\n\n" + "Switching to this mode will abort any currently running synchronization." + "\n\n" + "This is a new, experimental mode. If you decide to use it, please report any " + "issues that come up."), + QMessageBox::NoButton, + this); + + messageBox->addButton(tr("Enable experimental placeholder mode"), QMessageBox::AcceptRole); + messageBox->addButton(tr("Stay safe"), QMessageBox::RejectRole); + + messageBox->setAttribute(Qt::WA_DeleteOnClose); + + connect(messageBox, &QMessageBox::rejected, this, [this]() { + // bring back to "safety" + _ui->syncEverythingRadioButton->setChecked(true); + }); + + messageBox->show(); + }); + } + + // toggle once to have the according handlers set up the initial UI state + _ui->advancedConfigGroupBox->setChecked(true); + _ui->advancedConfigGroupBox->setChecked(false); } AccountConfiguredWizardPage::~AccountConfiguredWizardPage() noexcept { delete _ui; } + +QString AccountConfiguredWizardPage::syncTargetDir() const +{ + return QDir::toNativeSeparators(_ui->localDirectoryLineEdit->text()); +} + +SyncMode AccountConfiguredWizardPage::syncMode() const +{ + if (_ui->syncEverythingRadioButton->isChecked()) { + return SyncMode::SyncEverything; + } + if (_ui->selectiveSyncRadioButton->isChecked()) { + return SyncMode::SelectiveSync; + } + if (_ui->useVfsRadioButton->isChecked()) { + return SyncMode::UseVfs; + } + + Q_UNREACHABLE(); +} } diff --git a/src/gui/newwizard/pages/accountconfiguredwizardpage.h b/src/gui/newwizard/pages/accountconfiguredwizardpage.h index b75c3e22c..9c905dba7 100644 --- a/src/gui/newwizard/pages/accountconfiguredwizardpage.h +++ b/src/gui/newwizard/pages/accountconfiguredwizardpage.h @@ -1,6 +1,9 @@ #pragma once +#include <QSharedPointer> + #include "abstractsetupwizardpage.h" +#include "setupwizardcontroller.h" namespace Ui { class AccountConfiguredWizardPage; @@ -13,9 +16,13 @@ class AccountConfiguredWizardPage : public AbstractSetupWizardPage Q_OBJECT public: - AccountConfiguredWizardPage(); + explicit AccountConfiguredWizardPage(const QString &defaultSyncTargetDir, bool vfsIsAvailable, bool enableVfsByDefault, bool vfsModeIsExperimental); ~AccountConfiguredWizardPage() noexcept override; + QString syncTargetDir() const; + + SyncMode syncMode() const; + private: ::Ui::AccountConfiguredWizardPage *_ui; }; diff --git a/src/gui/newwizard/pages/accountconfiguredwizardpage.ui b/src/gui/newwizard/pages/accountconfiguredwizardpage.ui index f56a74d7c..ca88b9749 100644 --- a/src/gui/newwizard/pages/accountconfiguredwizardpage.ui +++ b/src/gui/newwizard/pages/accountconfiguredwizardpage.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>732</width> - <height>434</height> + <width>689</width> + <height>513</height> </rect> </property> <property name="windowTitle"> @@ -50,8 +50,198 @@ </property> </spacer> </item> + <item> + <widget class="Line" name="advancedConfigSeparatorLine"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="advancedConfigGroupBox"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Advanced configuration</string> + </property> + <property name="flat"> + <bool>false</bool> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>60</number> + </property> + <item> + <widget class="QWidget" name="advancedConfigGroupBoxContentWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>50</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="syncModeGroupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">QGroupBox {border:0;}</string> + </property> + <property name="title"> + <string notr="true"/> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="syncModeGroupBoxLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QRadioButton" name="syncEverythingRadioButton"> + <property name="text"> + <string>Download everything</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="selectiveSyncRadioButton"> + <property name="toolTip"> + <string>You can configure which directories to download from the server in a dialog once the wizard has finished.</string> + </property> + <property name="text"> + <string>Choose what to download</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="useVfsRadioButton"> + <property name="text"> + <string notr="true">Enable virtual filesystem (placeholder)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">QGroupBox {border:0;}</string> + </property> + <property name="title"> + <string notr="true"/> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Choose local download directory:</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLineEdit" name="localDirectoryLineEdit"/> + </item> + <item> + <widget class="QToolButton" name="chooseLocalDirectoryButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>1</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> </layout> </widget> - <resources/> + <resources> + <include location="../../../../client.qrc"/> + </resources> <connections/> </ui> diff --git a/src/gui/newwizard/setupwizardcontroller.cpp b/src/gui/newwizard/setupwizardcontroller.cpp index 5d35e4411..2b08715c5 100644 --- a/src/gui/newwizard/setupwizardcontroller.cpp +++ b/src/gui/newwizard/setupwizardcontroller.cpp @@ -7,12 +7,32 @@ #include "pages/oauthcredentialssetupwizardpage.h" #include "pages/serverurlsetupwizardpage.h" +#include "gui/folderman.h" +#include "theme.h" + +#include <QDir> #include <QTimer> #include <chrono> using namespace std::chrono_literals; +namespace { + +QString initLocalFolder() +{ + auto localFolder = OCC::Theme::instance()->defaultClientFolder(); + // Update the local folder - this is not guaranteed to find a good one + // if its a relative path, prepend with users home dir, otherwise use as absolute path + + if (!QDir(localFolder).isAbsolute()) { + localFolder = QDir::homePath() + QDir::separator() + localFolder; + } + return OCC::FolderMan::instance()->findGoodPathForNewSyncFolder(localFolder); +} + +} + namespace OCC::Wizard { SetupWizardController::SetupWizardController(QWidget *parent) @@ -28,7 +48,7 @@ SetupWizardController::SetupWizardController(QWidget *parent) // allow settings dialog to clean up the wizard controller and all the objects it created connect(_wizardWindow, &SetupWizardWindow::rejected, this, [this]() { - Q_EMIT finished(nullptr); + Q_EMIT finished(nullptr, {}, SyncMode::Invalid); }); connect(_wizardWindow, &SetupWizardWindow::paginationEntryClicked, this, [this, paginationEntries](PageIndex currentPage, PageIndex clickedPageIndex) { @@ -129,9 +149,11 @@ void SetupWizardController::nextStep(std::optional<PageIndex> currentPage, std:: // final step if (currentPage == 2) { + const auto *pagePtr = qobject_cast<AccountConfiguredWizardPage *>(_currentPage); + auto account = _accountBuilder.build(); Q_ASSERT(account != nullptr); - emit finished(account); + Q_EMIT finished(account, pagePtr->syncTargetDir(), pagePtr->syncMode()); return; } } @@ -240,7 +262,27 @@ void SetupWizardController::nextStep(std::optional<PageIndex> currentPage, std:: } if (desiredPage == 2) { - _currentPage = new AccountConfiguredWizardPage; + // being pessimistic by default + bool vfsIsAvailable = false; + bool enableVfsByDefault = false; + bool vfsModeIsExperimental = false; + + switch (bestAvailableVfsMode()) { + case Vfs::WindowsCfApi: + vfsIsAvailable = true; + enableVfsByDefault = true; + vfsModeIsExperimental = false; + break; + case Vfs::WithSuffix: + vfsIsAvailable = true; + enableVfsByDefault = false; + vfsModeIsExperimental = true; + break; + default: + break; + } + + _currentPage = new AccountConfiguredWizardPage(initLocalFolder(), vfsIsAvailable, enableVfsByDefault, vfsModeIsExperimental); _wizardWindow->displayPage(_currentPage, 2); return; } diff --git a/src/gui/newwizard/setupwizardcontroller.h b/src/gui/newwizard/setupwizardcontroller.h index 097150b78..4b3ccb124 100644 --- a/src/gui/newwizard/setupwizardcontroller.h +++ b/src/gui/newwizard/setupwizardcontroller.h @@ -1,6 +1,7 @@ #pragma once #include "pages/abstractsetupwizardpage.h" +#include "syncmode.h" #include <QDialog> #include <account.h> #include <optional> @@ -31,7 +32,7 @@ Q_SIGNALS: /** * Emitted when the wizard has finished. It passes the built account object. */ - void finished(AccountPtr newAccount); + void finished(AccountPtr newAccount, const QString &localFolder, SyncMode syncMode); private: void nextStep(std::optional<PageIndex> currentPage, std::optional<PageIndex> desiredPage); diff --git a/src/gui/newwizard/syncmode.cpp b/src/gui/newwizard/syncmode.cpp new file mode 100644 index 000000000..63a336a42 --- /dev/null +++ b/src/gui/newwizard/syncmode.cpp @@ -0,0 +1,2 @@ +// just a stub so the MOC file can be included somewhere +#include "moc_syncmode.cpp" diff --git a/src/gui/newwizard/syncmode.h b/src/gui/newwizard/syncmode.h new file mode 100644 index 000000000..fd1bbd16d --- /dev/null +++ b/src/gui/newwizard/syncmode.h @@ -0,0 +1,15 @@ +#pragma once + +#include <QObject> + +namespace OCC::Wizard { +Q_NAMESPACE + +enum class SyncMode { + Invalid = 0, + SyncEverything, + SelectiveSync, + UseVfs, +}; +Q_ENUM_NS(SyncMode) +} |