Commit 18db0b79 authored by Ivan Čukić's avatar Ivan Čukić 👁

Refactored the wizard logic

Common implementation for both the vault creation and vault importing
wizards.
parent 7ee10da0
......@@ -32,7 +32,7 @@ set (
ui/vaultcreationwizard.cpp
ui/vaultimportingwizard.cpp
ui/vaultconfigurationwizard.cpp
ui/vaultconfigurationdialog.cpp
ui/mountdialog.cpp
../common/vaultinfo.cpp
......@@ -53,7 +53,7 @@ ki18n_wrap_ui (
ui/vaultcreationwizard.ui
ui/vaultimportingwizard.ui
ui/vaultconfigurationwizard.ui
ui/vaultconfigurationdialog.ui
ui/mountdialog.ui
)
......
......@@ -33,7 +33,7 @@
#include "ui/vaultcreationwizard.h"
#include "ui/vaultimportingwizard.h"
#include "ui/vaultconfigurationwizard.h"
#include "ui/vaultconfigurationdialog.h"
#include "ui/mountdialog.h"
#include <functional>
......@@ -344,7 +344,7 @@ void PlasmaVaultService::closeVault(const QString &device)
void PlasmaVaultService::configureVault(const QString &device)
{
if (auto vault = d->vaultFor(device)) {
const auto dialog = new VaultConfigurationWizard(vault);
const auto dialog = new VaultConfigurationDialog(vault);
dialog->show();
}
......
......@@ -18,8 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vaultconfigurationwizard.h"
#include "ui_vaultconfigurationwizard.h"
#include "vaultconfigurationdialog.h"
#include "ui_vaultconfigurationdialog.h"
#include <QPushButton>
#include <QMap>
......@@ -45,12 +45,12 @@ using namespace DialogDsl::operators;
using PlasmaVault::Vault;
class VaultConfigurationWizard::Private {
class VaultConfigurationDialog::Private {
public:
VaultConfigurationWizard *const q;
VaultConfigurationDialog *const q;
Vault *vault;
Ui::VaultConfigurationWizard ui;
Ui::VaultConfigurationDialog ui;
QStackedLayout *layout;
steps currentSteps;
......@@ -85,7 +85,7 @@ public:
}
};
Private(Vault *vault, VaultConfigurationWizard *parent)
Private(Vault *vault, VaultConfigurationDialog *parent)
: q(parent)
, vault(vault)
{
......@@ -169,7 +169,7 @@ public:
VaultConfigurationWizard::VaultConfigurationWizard(Vault *vault, QWidget *parent)
VaultConfigurationDialog::VaultConfigurationDialog(Vault *vault, QWidget *parent)
: QDialog(parent)
, d(new Private(vault, this))
{
......@@ -195,7 +195,7 @@ VaultConfigurationWizard::VaultConfigurationWizard(Vault *vault, QWidget *parent
VaultConfigurationWizard::~VaultConfigurationWizard()
VaultConfigurationDialog::~VaultConfigurationDialog()
{
}
......
......@@ -18,8 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLASMAVAULT_KDED_UI_VAULT_CONFIGURATION_WIZARD_H
#define PLASMAVAULT_KDED_UI_VAULT_CONFIGURATION_WIZARD_H
#ifndef PLASMAVAULT_KDED_UI_VAULT_CONFIGURATION_DIALOG_H
#define PLASMAVAULT_KDED_UI_VAULT_CONFIGURATION_DIALOG_H
#include <QDialog>
......@@ -27,12 +27,12 @@ namespace PlasmaVault {
class Vault;
} // namespace PlasmaVault
class VaultConfigurationWizard: public QDialog {
class VaultConfigurationDialog: public QDialog {
Q_OBJECT
public:
VaultConfigurationWizard(PlasmaVault::Vault *vault, QWidget *parent = nullptr);
~VaultConfigurationWizard();
VaultConfigurationDialog(PlasmaVault::Vault *vault, QWidget *parent = nullptr);
~VaultConfigurationDialog();
Q_SIGNALS:
void configurationChanged(PlasmaVault::Vault *vault);
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>VaultConfigurationWizard</class>
<widget class="QDialog" name="VaultConfigurationWizard">
<class>VaultConfigurationDialog</class>
<widget class="QDialog" name="VaultConfigurationDialog">
<property name="geometry">
<rect>
<x>0</x>
......@@ -14,7 +14,8 @@
<string>Dialog</string>
</property>
<property name="windowIcon">
<iconset theme="plasmavault"/>
<iconset theme="plasmavault">
<normaloff>.</normaloff>.</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
......@@ -90,7 +91,7 @@
<connection>
<sender>buttons</sender>
<signal>accepted()</signal>
<receiver>VaultConfigurationWizard</receiver>
<receiver>VaultConfigurationDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
......@@ -106,7 +107,7 @@
<connection>
<sender>buttons</sender>
<signal>rejected()</signal>
<receiver>VaultConfigurationWizard</receiver>
<receiver>VaultConfigurationDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
......
......@@ -40,24 +40,10 @@ using namespace DialogDsl::operators;
#include "passwordchooserwidget.h"
#include "offlineonlywidget.h"
class VaultCreationWizard::Private {
public:
VaultCreationWizard *const q;
Ui::VaultCreationWizard ui;
QPushButton *buttonPrevious;
QPushButton *buttonNext;
QPushButton *buttonCreate;
QStackedLayout *layout;
inline void buttonNextSetEnabled(bool enabled) {
buttonNext->setEnabled(enabled);
buttonCreate->setEnabled(enabled);
}
#include "vaultwizardbase.h"
QVector<DialogDsl::DialogModule*> currentStepModules;
steps currentSteps;
BackendChooserWidget *firstStepModule = nullptr;
DialogDsl::DialogModule *currentModule = nullptr;
class VaultCreationWizard::Private: public WBASE(VaultCreationWizard) {
public:
Logic logic
{
......@@ -127,154 +113,13 @@ public:
}
};
// to suggest the highest priority to the user as a starting value
QMap<QString, int> priorities = {
{ "encfs", 1 },
{ "cryfs", 2 }
};
template <typename ClickHandler>
QPushButton *addDialogButton(const QString &icon, const QString &title, ClickHandler clickHandler)
{
auto button = new QPushButton(QIcon::fromTheme(icon), title);
ui.buttons->addButton(button, QDialogButtonBox::ActionRole);
QObject::connect(button, &QPushButton::clicked,
q, clickHandler);
return button;
}
Private(VaultCreationWizard *parent)
: q(parent)
{
ui.setupUi(parent);
ui.message->hide();
layout = new QStackedLayout();
layout->setContentsMargins(0, 0, 0, 0);
ui.container->setLayout(layout);
// The dialog buttons do not have previous/next by default
// so we need to create them
buttonPrevious = addDialogButton("go-previous", i18n("Previous"), [this] { previousStep(); });
buttonNext = addDialogButton("go-next", i18n("Next"), [this] { nextStep(); });
buttonCreate = addDialogButton("dialog-ok-apply", i18n("Create"), [this] { createVault(); });
// The 'Create' button should be hidden by default
buttonCreate->hide();
buttonPrevious->setEnabled(false);
buttonNextSetEnabled(false);
// Loading the fist page of the wizard
firstStepModule = new BackendChooserWidget();
setCurrentModule(firstStepModule);
layout->addWidget(firstStepModule);
// Loading the backends to the combo box
for (const auto& key: logic.keys()) {
firstStepModule->addItem(key, key.translation(), priorities.value(key));
}
firstStepModule->checkBackendAvailable();
}
void setCurrentModule(DialogDsl::DialogModule *module)
: WBASE(VaultCreationWizard)(parent)
{
// If there is a current module already, disconnect it
if (currentModule) {
currentModule->aboutToBeHidden();
currentModule->disconnect();
}
// The current module needs to be changed
currentModule = module;
currentModule->aboutToBeShown();
QObject::connect(
currentModule, &DialogModule::isValidChanged,
q, [&] (bool valid) {
buttonNextSetEnabled(valid);
});
// Lets update the button states
// 1. next/create button is enabled only if the current
// module is in the valid state
buttonNextSetEnabled(currentModule->isValid());
// 2. previous button is enabled only if we are not on
// the first page
buttonPrevious->setEnabled(currentStepModules.size() > 0);
// 3. If we have loaded the last page, we want to show the
// 'Create' button instead of 'Next'
if (!currentSteps.isEmpty() && currentStepModules.size() == currentSteps.size()) {
buttonNext->hide();
buttonCreate->show();
} else {
buttonNext->show();
buttonCreate->hide();
}
// Calling to initialize the module -- we are passing all the
// previously collected data to it
auto collectedPayload = firstStepModule->fields();
for (const auto* module: currentStepModules) {
collectedPayload.unite(module->fields());
}
currentModule->init(collectedPayload);
}
void previousStep()
{
if (currentStepModules.isEmpty()) return;
// We want to kill the current module, and move to the previous one
currentStepModules.takeLast();
currentModule->deleteLater();;
if (currentStepModules.size()) {
setCurrentModule(currentStepModules.last());
} else {
setCurrentModule(firstStepModule);
}
if (!currentModule->shouldBeShown()) {
previousStep();
}
}
void nextStep()
{
// If the step modules are empty, this means that we
// have just started - the user chose the backend
// and we need to load the vault creation steps
if (currentStepModules.isEmpty()) {
const auto &fields = firstStepModule->fields();
currentSteps = logic[fields[KEY_BACKEND].toByteArray()];
}
// Loading the modulws that we need to show now
auto subModules = currentSteps[currentStepModules.size()];
// If there is only one module on the current page,
// lets not complicate things by creating the compound module
DialogModule *stepWidget =
(subModules.size() == 1) ? subModules.first()()
: new CompoundDialogModule(subModules);
// Adding the widget to the list and the layout
currentStepModules << stepWidget;
layout->addWidget(stepWidget);
layout->setCurrentWidget(stepWidget);
// Set the newly added module to be the current
setCurrentModule(stepWidget);
if (!currentModule->shouldBeShown()) {
nextStep();
}
initBase();
}
void createVault()
void finish()
{
auto collectedPayload = firstStepModule->fields();
for (const auto* module: currentStepModules) {
......
......@@ -40,24 +40,10 @@ using namespace DialogDsl::operators;
#include "passwordchooserwidget.h"
#include "offlineonlywidget.h"
class VaultImportingWizard::Private {
public:
VaultImportingWizard *const q;
Ui::VaultImportingWizard ui;
QPushButton *buttonPrevious;
QPushButton *buttonNext;
QPushButton *buttonImport;
QStackedLayout *layout;
inline void buttonNextSetEnabled(bool enabled) {
buttonNext->setEnabled(enabled);
buttonImport->setEnabled(enabled);
}
#include "vaultwizardbase.h"
QVector<DialogDsl::DialogModule*> currentStepModules;
steps currentSteps;
BackendChooserWidget *firstStepModule = nullptr;
DialogDsl::DialogModule *currentModule = nullptr;
class VaultImportingWizard::Private: public WBASE(VaultImportingWizard) {
public:
Logic logic
{
......@@ -94,154 +80,14 @@ public:
}
};
// to suggest the highest priority to the user as a starting value
QMap<QString, int> priorities = {
{ "encfs", 1 },
{ "cryfs", 2 }
};
template <typename ClickHandler>
QPushButton *addDialogButton(const QString &icon, const QString &title, ClickHandler clickHandler)
{
auto button = new QPushButton(QIcon::fromTheme(icon), title);
ui.buttons->addButton(button, QDialogButtonBox::ActionRole);
QObject::connect(button, &QPushButton::clicked,
q, clickHandler);
return button;
}
Private(VaultImportingWizard *parent)
: q(parent)
{
ui.setupUi(parent);
ui.message->hide();
layout = new QStackedLayout();
layout->setContentsMargins(0, 0, 0, 0);
ui.container->setLayout(layout);
// The dialog buttons do not have previous/next by default
// so we need to create them
buttonPrevious = addDialogButton("go-previous", i18n("Previous"), [this] { previousStep(); });
buttonNext = addDialogButton("go-next", i18n("Next"), [this] { nextStep(); });
buttonImport = addDialogButton("dialog-ok-apply", i18n("Import"), [this] { importVault(); });
// The 'Import' button should be hidden by default
buttonImport->hide();
buttonPrevious->setEnabled(false);
buttonNextSetEnabled(false);
// Loading the fist page of the wizard
firstStepModule = new BackendChooserWidget();
setCurrentModule(firstStepModule);
layout->addWidget(firstStepModule);
// Loading the backends to the combo box
for (const auto& key: logic.keys()) {
firstStepModule->addItem(key, key.translation(), priorities.value(key));
}
firstStepModule->checkBackendAvailable();
}
void setCurrentModule(DialogDsl::DialogModule *module)
: WBASE(VaultImportingWizard)(parent)
{
// If there is a current module already, disconnect it
if (currentModule) {
currentModule->aboutToBeHidden();
currentModule->disconnect();
}
// The current module needs to be changed
currentModule = module;
currentModule->aboutToBeShown();
QObject::connect(
currentModule, &DialogModule::isValidChanged,
q, [&] (bool valid) {
buttonNextSetEnabled(valid);
});
// Lets update the button states
// 1. next/Import button is enabled only if the current
// module is in the valid state
buttonNextSetEnabled(currentModule->isValid());
// 2. previous button is enabled only if we are not on
// the first page
buttonPrevious->setEnabled(currentStepModules.size() > 0);
// 3. If we have loaded the last page, we want to show the
// 'Import' button instead of 'Next'
if (!currentSteps.isEmpty() && currentStepModules.size() == currentSteps.size()) {
buttonNext->hide();
buttonImport->show();
} else {
buttonNext->show();
buttonImport->hide();
}
// Calling to initialize the module -- we are passing all the
// previously collected data to it
auto collectedPayload = firstStepModule->fields();
for (const auto* module: currentStepModules) {
collectedPayload.unite(module->fields());
}
currentModule->init(collectedPayload);
}
void previousStep()
{
if (currentStepModules.isEmpty()) return;
// We want to kill the current module, and move to the previous one
currentStepModules.takeLast();
currentModule->deleteLater();;
if (currentStepModules.size()) {
setCurrentModule(currentStepModules.last());
} else {
setCurrentModule(firstStepModule);
}
if (!currentModule->shouldBeShown()) {
previousStep();
}
}
void nextStep()
{
// If the step modules are empty, this means that we
// have just started - the user chose the backend
// and we need to load the vault creation steps
if (currentStepModules.isEmpty()) {
const auto &fields = firstStepModule->fields();
currentSteps = logic[fields[KEY_BACKEND].toByteArray()];
}
// Loading the modulws that we need to show now
auto subModules = currentSteps[currentStepModules.size()];
// If there is only one module on the current page,
// lets not complicate things by creating the compound module
DialogModule *stepWidget =
(subModules.size() == 1) ? subModules.first()()
: new CompoundDialogModule(subModules);
// Adding the widget to the list and the layout
currentStepModules << stepWidget;
layout->addWidget(stepWidget);
layout->setCurrentWidget(stepWidget);
// Set the newly added module to be the current
setCurrentModule(stepWidget);
if (!currentModule->shouldBeShown()) {
nextStep();
}
lastButtonText = i18n("Import");
initBase();
}
void importVault()
void finish()
{
auto collectedPayload = firstStepModule->fields();
for (const auto* module: currentStepModules) {
......
/*
* Copyright 2017 by Ivan Cukic <ivan.cukic (at) kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLASMAVAULT_KDED_UI_VAULT_WIZARD_BASE_P_H
#define PLASMAVAULT_KDED_UI_VAULT_WIZARD_BASE_P_H
#include <QPushButton>
namespace PlasmaVault {
class Vault;
} // namespace PlasmaVault
#define WBASE(Class) VaultWizardBase<Class, Ui::Class, Class::Private>
template <typename Class, typename Ui, typename Impl>
class VaultWizardBase {
public:
Class *const q;
Ui ui;
QPushButton *buttonPrevious;
QPushButton *buttonNext;
QStackedLayout *layout;
bool lastModule = false;
QString lastButtonText;
inline void setLastModule(bool last) {
lastModule = last;
if (last) {
buttonNext->setText(lastButtonText);
buttonNext->setIcon(QIcon::fromTheme("dialog-ok-apply"));
} else {
buttonNext->setText(i18n("Next"));
buttonNext->setIcon(QIcon::fromTheme("go-next"));
}
}
QVector<DialogDsl::DialogModule*> currentStepModules;
steps currentSteps;
BackendChooserWidget *firstStepModule = nullptr;
DialogDsl::DialogModule *currentModule = nullptr;
// to suggest the highest priority to the user as a starting value
QMap<QString, int> priorities = {
{ "encfs", 1 },
{ "cryfs", 2 }
};
template <typename ClickHandler>
QPushButton *addDialogButton(const QString &icon, const QString &title,
ClickHandler clickHandler)
{
auto button = new QPushButton(QIcon::fromTheme(icon), title);
ui.buttons->addButton(button, QDialogButtonBox::ActionRole);
QObject::connect(button, &QPushButton::clicked,
q, clickHandler);
return button;
}
Impl* self()
{
return static_cast<Impl*>(this);
}
VaultWizardBase(Class *parent)
: q(parent)
{
ui.setupUi(parent);
ui.message->hide();
layout = new QStackedLayout();
layout->setContentsMargins(0, 0, 0, 0);
ui.container->setLayout(layout);
lastButtonText = i18n("Create");
}
void initBase()
{
// The dialog buttons do not have previous/next by default
// so we need to create them
buttonPrevious = addDialogButton("go-previous", i18n("Previous"),
[this] { previousStep(); });
buttonNext = addDialogButton("go-next", i18n("Next"),
[this] { if (lastModule) self()->finish(); else nextStep(); });
// The 'Create' button should be hidden by default
buttonPrevious->setEnabled(false);
buttonNext->setEnabled(false);
buttonNext->setDefault(true);
// Loading the fist page of the wizard
firstStepModule = new BackendChooserWidget();
setCurrentModule(firstStepModule);
layout->addWidget(firstStepModule);
// Loading the backends to the combo box
for (const auto& key: self()->logic.keys()) {
firstStepModule->addItem(key, key.translation(), priorities.value(key));
}
firstStepModule->checkBackendAvailable();
}
void setCurrentModule(DialogDsl::DialogModule *module)
{
// If there is a current module already, disconnect it
if (currentModule) {
currentModule->aboutToBeHidden();
currentModule->disconnect();
}
// The current module needs to be changed
currentModule = module;
currentModule->aboutToBeShown();
QObject::connect(
currentModule, &DialogModule::isValidChanged,
q, [&] (bool valid) {
buttonNext->setEnabled(valid);
});
// Lets update the button states
// 1. next/create button is enabled only if the current
// module is in the valid state
buttonNext->setEnabled(currentModule->isValid());
// 2. previous button is enabled only if we are not on
// the first page
buttonPrevious->setEnabled(currentStepModules.size() > 0);
// 3. If we have loaded the last page, we want to show the
// 'Create' button instead of 'Next'
setLastModule(!currentSteps.isEmpty() && currentStepModules.size() == currentSteps.size());
// Calling to initialize the module -- we are passing all the
// previously collected data to it
auto collectedPayload = firstStepModule->fields();
for (const auto* module: currentStepModules) {
collectedPayload.unite(module->fields());
}
currentModule->init(collectedPayload);
}