diff --git a/kded/CMakeLists.txt b/kded/CMakeLists.txt index 10edcf4..303c513 100644 --- a/kded/CMakeLists.txt +++ b/kded/CMakeLists.txt @@ -1,79 +1,85 @@ include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/engine ) set ( kded_plasmavault_SRCS service.cpp engine/vault.cpp engine/backend_p.cpp engine/fusebackend_p.cpp engine/types.cpp engine/commandresult.cpp engine/backends/encfs/encfsbackend.cpp engine/backends/cryfs/cryfsbackend.cpp ui/dialogdsl.cpp ui/activitieslinkingwidget.cpp ui/backendchooserwidget.cpp ui/cryfscypherchooserwidget.cpp ui/directorypairchooserwidget.cpp + ui/directorychooserwidget.cpp + ui/namechooserwidget.cpp ui/noticewidget.cpp ui/passwordchooserwidget.cpp ui/vaultcreationwizard.cpp + ui/vaultconfigurationwizard.cpp ../common/vaultinfo.cpp ) ki18n_wrap_ui ( kded_plasmavault_SRCS ui/activitieslinkingwidget.ui ui/backendchooserwidget.ui ui/cryfscypherchooserwidget.ui ui/directorypairchooserwidget.ui + ui/directorychooserwidget.ui + ui/namechooserwidget.ui ui/noticewidget.ui ui/passwordchooserwidget.ui ui/vaultcreationwizard.ui + ui/vaultconfigurationwizard.ui ) add_library ( kded_plasmavault MODULE ${kded_plasmavault_SRCS} ) set_target_properties ( kded_plasmavault PROPERTIES OUTPUT_NAME plasmavault ) kcoreaddons_desktop_to_json ( kded_plasmavault plasmavault.desktop ) target_link_libraries ( kded_plasmavault Qt5::Core Qt5::DBus Qt5::Widgets KF5::Activities KF5::ConfigCore KF5::ConfigWidgets KF5::CoreAddons KF5::DBusAddons KF5::I18n KF5::KIOCore KF5::KIOWidgets KF5::SysGuard KF5::WidgetsAddons KF5::ProcessCore ) install ( TARGETS kded_plasmavault DESTINATION ${PLUGIN_INSTALL_DIR}/kf5/kded) diff --git a/kded/engine/vault.cpp b/kded/engine/vault.cpp index 36a283f..ec0b9e2 100644 --- a/kded/engine/vault.cpp +++ b/kded/engine/vault.cpp @@ -1,574 +1,632 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #include "vault.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "backend_p.h" #include "asynqt/basic/all.h" #include "asynqt/wrappers/process.h" #include "asynqt/operations/listen.h" #include "asynqt/operations/cast.h" #include #define CFG_NAME "name" #define CFG_LAST_STATUS "lastStatus" #define CFG_MOUNT_POINT "mountPoint" #define CFG_BACKEND "backend" #define CFG_ACTIVITIES "activities" namespace PlasmaVault { class Vault::Private { public: Vault * const q; KSharedConfigPtr config; Device device; + QTimer savingDelay; + struct Data { QString name; MountPoint mountPoint; VaultInfo::Status status; QStringList activities; QString message; QString backendName; Backend::Ptr backend; }; using ExpectedData = AsynQt::Expected; ExpectedData data; void updateMessage(const QString &message) { if (!data) return; data->message = message; emit q->messageChanged(message); } void updateStatus() { if (data) { // Checking the status, and whether we should update it const auto oldStatus = data->status; const auto newStatus = isOpened() ? VaultInfo::Opened : isInitialized() ? VaultInfo::Closed : VaultInfo::NotInitialized; if (oldStatus == newStatus) return; data->status = newStatus; emit q->statusChanged(data->status); - if (oldStatus == VaultInfo::Opened || newStatus == VaultInfo::Opened) { - emit q->isOpenedChanged(newStatus); + if (newStatus == VaultInfo::Closed || newStatus == VaultInfo::Opened) { + emit q->isOpenedChanged(newStatus == VaultInfo::Opened); } if (oldStatus == VaultInfo::NotInitialized || newStatus == VaultInfo::NotInitialized) { emit q->isInitializedChanged(newStatus); } if (oldStatus == VaultInfo::Creating || oldStatus == VaultInfo::Opening || oldStatus == VaultInfo::Closing || oldStatus == VaultInfo::Destroying) { emit q->isBusyChanged(false); } // Saving the data for the current mount KConfigGroup generalConfig(config, "EncryptedDevices"); generalConfig.writeEntry(device.data(), true); KConfigGroup vaultConfig(config, device.data()); vaultConfig.writeEntry(CFG_LAST_STATUS, (int)data->status); vaultConfig.writeEntry(CFG_MOUNT_POINT, data->mountPoint.data()); vaultConfig.writeEntry(CFG_NAME, data->name); vaultConfig.writeEntry(CFG_BACKEND, data->backend->name()); vaultConfig.writeEntry(CFG_ACTIVITIES, data->activities); org::kde::KDirNotify::emitFilesAdded( QUrl::fromLocalFile(data->mountPoint.data())); config->sync(); } else { emit q->isOpenedChanged(false); emit q->isInitializedChanged(false); emit q->isBusyChanged(false); KConfigGroup generalConfig(config, "EncryptedDevices"); generalConfig.writeEntry(device.data(), false); KConfigGroup vaultConfig(config, device.data()); vaultConfig.writeEntry(CFG_LAST_STATUS, (int)VaultInfo::Error); // vaultConfig.deleteEntry(CFG_MOUNT_POINT); // vaultConfig.deleteEntry(CFG_NAME); // vaultConfig.deleteEntry(CFG_BACKEND); // vaultConfig.deleteEntry(CFG_ACTIVITIES); emit q->statusChanged(VaultInfo::Error); } config->sync(); } ExpectedData errorData(Error::Code error, const QString &message) const { qWarning() << "error: " << message; return ExpectedData::error(error, message); } ExpectedData loadVault(const Device &device, const QString &name = QString(), const MountPoint &mountPoint = MountPoint(), const Payload &payload = Payload()) const { if (!config->hasGroup(device.data())) { return errorData(Error::DeviceError, i18n("Unknown device")); } Data vaultData; const QString backendName = payload[KEY_BACKEND].toString(); const QStringList activities = payload[KEY_ACTIVITIES].toStringList(); // status should never be in this state, if we got an error, // d->data should not be valid vaultData.status = VaultInfo::Error; // Reading the mount data from the config const KConfigGroup vaultConfig(config, device.data()); vaultData.name = vaultConfig.readEntry(CFG_NAME, name); vaultData.mountPoint = MountPoint(vaultConfig.readEntry(CFG_MOUNT_POINT, mountPoint.data())); vaultData.backendName = vaultConfig.readEntry(CFG_BACKEND, backendName); vaultData.activities = vaultConfig.readEntry(CFG_ACTIVITIES, activities); const QDir mountPointDir(vaultData.mountPoint); return // If the backend is not known, we need to fail !Backend::availableBackends().contains(vaultData.backendName) ? errorData(Error::BackendError, i18n("Configured backend does not exist: %1", vaultData.backendName)) : // If the mount point is empty, we can not do anything vaultData.mountPoint.isEmpty() ? errorData(Error::MountPointError, i18n("Mount point is not specified")) : // Lets try to create the mount point !mountPointDir.exists() && !QDir().mkpath(vaultData.mountPoint) ? errorData(Error::MountPointError, i18n("Can not create the mount point")) : // Instantiate the backend if possible !(vaultData.backend = Backend::instance(vaultData.backendName)) ? errorData(Error::BackendError, i18n("Configured backend can not be instantiated: %1", vaultData.backendName)) : // otherwise ExpectedData::success(vaultData); } Private(Vault *parent, const Device &device) : q(parent) , config(KSharedConfig::openConfig(PLASMAVAULT_CONFIG_FILE)) , device(device) , data(loadVault(device)) { updateStatus(); } template T followFuture(VaultInfo::Status whileNotFinished, const T &future) { using namespace AsynQt::operators; emit q->isBusyChanged(true); data->status = whileNotFinished; return future | onSuccess([this] { updateStatus(); }); } bool isInitialized() const { return data && data->backend->isInitialized(device); } bool isOpened() const { return data && data->backend->isOpened(data->mountPoint); } }; Vault::Vault(const Device &device, QObject *parent) : QObject(parent) , d(new Private(this, device)) { + d->savingDelay.setInterval(300); + d->savingDelay.setSingleShot(true); + connect(&d->savingDelay, &QTimer::timeout, + this, [&] { + qDebug() << "Saving vault info:" + << d->data->name + << d->data->activities + << d->data->mountPoint; + KConfigGroup vaultConfig(d->config, d->device.data()); + vaultConfig.writeEntry(CFG_MOUNT_POINT, d->data->mountPoint.data()); + vaultConfig.writeEntry(CFG_NAME, d->data->name); + vaultConfig.writeEntry(CFG_ACTIVITIES, d->data->activities); + + d->config->sync(); + + emit infoChanged(); + }); } Vault::~Vault() { close(); } +void Vault::saveConfiguration() +{ + d->savingDelay.start(); +} + + + FutureResult<> Vault::create(const QString &name, const MountPoint &mountPoint, const Payload &payload) { using namespace AsynQt::operators; return // If the backend is already known, and the device is initialized, // we do not want to do it again d->data && d->data->backend->isInitialized(d->device) ? errorResult(Error::DeviceError, i18n("This device is already registered. Can not recreate it.")) : // Mount not open, check the error messages !(d->data = d->loadVault(d->device, name, mountPoint, payload)) ? errorResult(Error::BackendError, i18n("Unknown error, unable to create the backend.")) : // otherwise d->followFuture(VaultInfo::Creating, d->data->backend->initialize(name, d->device, mountPoint, payload)) | onSuccess([mountPoint] { // If we have successfully created the vault, // lets try to set its icon QFile dotDir(mountPoint + "/.directory"); if (dotDir.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream out(&dotDir); out << "[Desktop Entry]\nIcon=folder-decrypted\n"; } }); } FutureResult<> Vault::open(const Payload &payload) { return // We can not mount something that has not been registered // with us before !d->data ? errorResult(Error::BackendError, i18n("Can not open an unknown vault.")) : // otherwise d->followFuture(VaultInfo::Opening, d->data->backend->open(d->device, d->data->mountPoint, payload)); } FutureResult<> Vault::close() { using namespace AsynQt::operators; return // We can not mount something that has not been registered // with us before !d->data ? errorResult(Error::BackendError, i18n("The vault is unknown, can not close it.")) : // otherwise d->followFuture(VaultInfo::Closing, d->data->backend->close(d->device, d->data->mountPoint)) | onSuccess([this] (const Result<> &result) { if (!isOpened() || result) { d->updateMessage(QString()); } else { // We want to check whether there is an application // that is accessing the vault AsynQt::Process::getOutput("lsof", { "-t", mountPoint() }) | cast() | onError([this] { d->updateMessage(i18n("Unable to close the vault, an application is using it")); }) | onSuccess([this] (const QString &result) { // based on ksolidnotify.cpp QStringList blockApps; const auto &pidList = result.split(QRegExp(QStringLiteral("\\s+")), QString::SkipEmptyParts); if (pidList.size() == 0) { d->updateMessage(i18n("Unable to close the vault, an application is using it")); close(); } else { KSysGuard::Processes procs; for (const QString &pidStr: pidList) { int pid = pidStr.toInt(); if (!pid) { continue; } procs.updateOrAddProcess(pid); KSysGuard::Process *proc = procs.getProcess(pid); if (!blockApps.contains(proc->name())) { blockApps << proc->name(); } } blockApps.removeDuplicates(); d->updateMessage(i18n("Unable to close the vault, it is used by %1", blockApps.join(", "))); } }); } }); } -FutureResult<> Vault::configure() -{ - return close(); -} +// FutureResult<> Vault::configure() +// { +// return close(); +// } FutureResult<> Vault::forceClose() { using namespace AsynQt::operators; AsynQt::await( AsynQt::Process::getOutput("lsof", { "-t", mountPoint() }) | cast() | onError([this] { d->updateMessage(i18n("Failed to fetch the list of applications using this vault")); }) | onSuccess([this] (const QString &result) { // based on ksolidnotify.cpp QStringList blockApps; const auto &pidList = result.split(QRegExp(QStringLiteral("\\s+")), QString::SkipEmptyParts); KSysGuard::Processes procs; for (const QString &pidStr: pidList) { int pid = pidStr.toInt(); if (!pid) { continue; } procs.sendSignal(pid, SIGKILL); } })); return close(); } FutureResult<> Vault::destroy(const Payload &payload) { return // We can not mount something that has not been registered // with us before !d->data ? errorResult(Error::BackendError, i18n("The vault is unknown, can not destroy it.")) : // otherwise d->followFuture(VaultInfo::Destroying, d->data->backend->destroy(d->device, d->data->mountPoint, payload)); } VaultInfo::Status Vault::status() const { return d->data->status; } bool Vault::isValid() const { return d->data; } -QString Vault::name() const -{ - return d->data->name; -} - - - Device Vault::device() const { return d->device; } -MountPoint Vault::mountPoint() const -{ - return d->data->mountPoint; -} - - - QList Vault::availableDevices() { const auto config = KSharedConfig::openConfig(PLASMAVAULT_CONFIG_FILE); const KConfigGroup general(config, "EncryptedDevices"); QList results; for (const auto& item: general.keyList()) { results << Device(item); } return results; } QStringList Vault::statusMessage() { for (const auto& backendName: Backend::availableBackends()) { auto backend = Backend::instance(backendName); backend->validateBackend(); } return {}; } QString Vault::message() const { if (!d->data) { return d->data.error().message(); } else { return d->data->message; } } bool Vault::isInitialized() const { return d->isInitialized(); } bool Vault::isOpened() const { return d->isOpened(); } +MountPoint Vault::mountPoint() const +{ + return d->data->mountPoint; +} + +void Vault::setMountPoint(const MountPoint &mountPoint) +{ + if (d->data->mountPoint != mountPoint.data()) { + QDir().rmpath(d->data->mountPoint.data()); + QDir().mkpath(mountPoint.data()); + + d->data->mountPoint = mountPoint; + saveConfiguration(); + } +} + + + QStringList Vault::activities() const { return d->data->activities; } +void Vault::setActivities(const QStringList &activities) +{ + d->data->activities = activities; + emit activitiesChanged(activities); + saveConfiguration(); +} + + + +QString Vault::name() const +{ + return d->data->name; +} + +void Vault::setName(const QString &name) +{ + d->data->name = name; + emit nameChanged(name); + saveConfiguration(); +} + + + +QString Vault::backend() const +{ + return d->data->backendName; +} + bool Vault::isBusy() const { if (!d->data) { return false; } switch (status()) { case VaultInfo::Creating: case VaultInfo::Opening: case VaultInfo::Closing: case VaultInfo::Destroying: return true; default: return false; } } VaultInfo Vault::info() const { VaultInfo vaultInfo; vaultInfo.device = device(); vaultInfo.name = name(); vaultInfo.status = status(); vaultInfo.activities = activities(); vaultInfo.message = message(); return vaultInfo; } } // namespace PlasmaVault diff --git a/kded/engine/vault.h b/kded/engine/vault.h index 66ab98d..bdcf15e 100644 --- a/kded/engine/vault.h +++ b/kded/engine/vault.h @@ -1,116 +1,128 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #ifndef PLASMAVAULT_KDED_ENGINE_VAULT_H #define PLASMAVAULT_KDED_ENGINE_VAULT_H #include #include #include #include #include #include "types.h" #include "commandresult.h" class QDBusArgument; namespace PlasmaVault { #define KEY_NAME "vault-name" #define KEY_BACKEND "vault-backend" #define KEY_PASSWORD "vault-password" #define KEY_DEVICE "vault-device" #define KEY_MOUNT_POINT "vault-mount-point" #define KEY_ACTIVITIES "vault-activities" class Vault: public QObject { Q_OBJECT Q_PROPERTY(PlasmaVault::Device device READ device) Q_PROPERTY(QString mountPoint READ mountPoint NOTIFY mountPointChanged) Q_PROPERTY(VaultInfo::Status status READ status NOTIFY statusChanged) Q_PROPERTY(bool isInitialized READ isInitialized NOTIFY isInitializedChanged) Q_PROPERTY(bool isOpened READ isOpened NOTIFY isOpenedChanged) Q_PROPERTY(bool isBusy READ isBusy NOTIFY isBusyChanged) + Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(QStringList activities READ activities NOTIFY activitiesChanged) Q_PROPERTY(QString message READ message NOTIFY messageChanged) public: Vault(const Device &device, QObject *parent = nullptr); ~Vault(); typedef QHash Payload; bool isValid() const; FutureResult<> create(const QString &name, const MountPoint &mountPoint, const Payload &payload); FutureResult<> open(const Payload &payload); FutureResult<> close(); - FutureResult<> configure(); + // FutureResult<> configure(); FutureResult<> forceClose(); FutureResult<> destroy(const Payload &payload); VaultInfo info() const; public Q_SLOTS: QString message() const; VaultInfo::Status status() const; bool isInitialized() const; bool isOpened() const; bool isBusy() const; - QString name() const; Device device() const; + QString backend() const; + MountPoint mountPoint() const; + void setMountPoint(const MountPoint &mountPoint); + + QString name() const; + void setName(const QString &name); + QStringList activities() const; + void setActivities(const QStringList &activities); + + void saveConfiguration(); Q_SIGNALS: void mountPointChanged(const QString &mountPoint); void statusChanged(VaultInfo::Status status); void isInitializedChanged(bool isInitialized); void isOpenedChanged(bool isOpened); void isBusyChanged(bool isBusy); void activitiesChanged(const QStringList &activities); void messageChanged(const QString &message); + void nameChanged(const QString &name); + void infoChanged(); public: static QList availableDevices(); static QStringList statusMessage(); private: class Private; QScopedPointer d; }; } // namespace PlasmaVault #endif // include guard diff --git a/kded/service.cpp b/kded/service.cpp index 67e9434..941b8a6 100644 --- a/kded/service.cpp +++ b/kded/service.cpp @@ -1,298 +1,314 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #include "service.h" #include #include #include #include #include #include #include "engine/vault.h" #include "engine/commandresult.h" #include "ui/vaultcreationwizard.h" +#include "ui/vaultconfigurationwizard.h" K_PLUGIN_FACTORY_WITH_JSON(PlasmaVaultServiceFactory, "plasmavault.json", registerPlugin();) using namespace PlasmaVault; class PlasmaVaultService::Private { public: QHash knownVaults; KActivities::Consumer kamd; Vault* vaultFor(const QString &device_) const { const Device device(device_); if (!knownVaults.contains(device)) { return nullptr; } return knownVaults[device]; } }; PlasmaVaultService::PlasmaVaultService(QObject * parent, const QVariantList&) : KDEDModule(parent) , d(new Private()) { connect(this, &KDEDModule::moduleRegistered, this, &PlasmaVaultService::slotRegistered); connect(&d->kamd, &KActivities::Consumer::currentActivityChanged, this, &PlasmaVaultService::onCurrentActivityChanged); init(); } PlasmaVaultService::~PlasmaVaultService() { } void PlasmaVaultService::init() { for (const Device &device: Vault::availableDevices()) { registerVault(new Vault(device, this)); } } PlasmaVault::VaultInfoList PlasmaVaultService::availableDevices() const { PlasmaVault::VaultInfoList result; for (const auto &vault: d->knownVaults.values()) { const auto vaultData = vault->info(); result << vaultData; } return result; } void PlasmaVaultService::requestNewVault() { const auto dialog = new VaultCreationWizard(); connect(dialog, &VaultCreationWizard::createdVault, this, &PlasmaVaultService::registerVault); dialog->show(); } void PlasmaVaultService::slotRegistered(const QDBusObjectPath &path) { if (path.path() == QLatin1String("/modules/plasmavault")) { emit registered(); } } void PlasmaVaultService::registerVault(Vault *vault) { if (!vault->isValid()) { qWarning() << "Warning: Trying to register an invalid vault: " << vault->device(); return; } if (d->knownVaults.contains(vault->device())) { qWarning() << "Warning: This one is already registered: " << vault->device(); return; } vault->setParent(this); d->knownVaults[vault->device()] = vault; connect(vault, &Vault::statusChanged, this, &PlasmaVaultService::onVaultStatusChanged); connect(vault, &Vault::messageChanged, this, &PlasmaVaultService::onVaultMessageChanged); + connect(vault, &Vault::infoChanged, + this, &PlasmaVaultService::onVaultInfoChanged); emit vaultAdded(vault->info()); } void PlasmaVaultService::onVaultStatusChanged(VaultInfo::Status status) { Q_UNUSED(status); const auto vault = qobject_cast(sender()); emit vaultChanged(vault->info()); } +void PlasmaVaultService::onVaultInfoChanged() +{ + const auto vault = qobject_cast(sender()); + emit vaultChanged(vault->info()); +} + + + void PlasmaVaultService::onVaultMessageChanged(const QString &message) { Q_UNUSED(message); const auto vault = qobject_cast(sender()); emit vaultChanged(vault->info()); } template class PasswordMountDialog: protected KPasswordDialog { //_ public: PasswordMountDialog(Vault *vault, Function function) : m_vault(vault) , m_function(function) { } void show() { KPasswordDialog::show(); } private: bool checkPassword() override { auto future = m_vault->open({ { KEY_PASSWORD, password() } }); const auto result = AsynQt::await(future); if (result) { m_function(); return true; } else { showErrorMessage(result.error().message()); return false; } } void hideEvent(QHideEvent *) override { deleteLater(); } Vault *m_vault; Function m_function; }; template void showPasswordMountDialog(Vault *vault, Function &&function) { auto dialog = new PasswordMountDialog( vault, std::forward(function)); dialog->show(); } //^ void PlasmaVaultService::openVault(const QString &device) { if (auto vault = d->vaultFor(device)) { if (vault->isOpened()) return; showPasswordMountDialog(vault, [this, vault] { emit vaultChanged(vault->info()); }); } } void PlasmaVaultService::closeVault(const QString &device) { if (auto vault = d->vaultFor(device)) { if (!vault->isOpened()) return; vault->close(); } } void PlasmaVaultService::configureVault(const QString &device) { if (auto vault = d->vaultFor(device)) { - vault->configure(); + const auto dialog = new VaultConfigurationWizard(vault); + + // connect(dialog, &VaultConfigurationWizard::configurationChanged, + // this, &PlasmaVaultService::registerVault); + + dialog->show(); } } void PlasmaVaultService::forceCloseVault(const QString &device) { if (auto vault = d->vaultFor(device)) { if (!vault->isOpened()) return; vault->forceClose(); } } void PlasmaVaultService::openVaultInFileManager(const QString &device) { if (auto vault = d->vaultFor(device)) { if (vault->isOpened()) { new KRun(QUrl::fromLocalFile((QString)vault->mountPoint()), 0); } else { showPasswordMountDialog(vault, [this, vault] { emit vaultChanged(vault->info()); new KRun(QUrl::fromLocalFile((QString)vault->mountPoint()), 0); }); } } } void PlasmaVaultService::onCurrentActivityChanged( const QString ¤tActivity) { for (auto* vault: d->knownVaults.values()) { const auto vaultActivities = vault->activities(); if (!vaultActivities.isEmpty() && !vaultActivities.contains(currentActivity)) { vault->close(); } } } #include "service.moc" diff --git a/kded/service.h b/kded/service.h index e618132..7759ba0 100644 --- a/kded/service.h +++ b/kded/service.h @@ -1,75 +1,76 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #ifndef PLASMAVAULT_KDED_SERVICE_H #define PLASMAVAULT_KDED_SERVICE_H #include #include #include #include class Q_DECL_EXPORT PlasmaVaultService : public KDEDModule { Q_CLASSINFO("D-Bus Interface", "org.kde.plasmavault") Q_OBJECT public: PlasmaVaultService(QObject *parent, const QVariantList&); ~PlasmaVaultService(); public Q_SLOTS: Q_SCRIPTABLE void init(); Q_SCRIPTABLE void requestNewVault(); Q_SCRIPTABLE void openVault(const QString &device); Q_SCRIPTABLE void closeVault(const QString &device); Q_SCRIPTABLE void configureVault(const QString &device); Q_SCRIPTABLE void forceCloseVault(const QString &device); Q_SCRIPTABLE void openVaultInFileManager(const QString &device); Q_SCRIPTABLE PlasmaVault::VaultInfoList availableDevices() const; Q_SIGNALS: void registered(); Q_SCRIPTABLE void vaultAdded(const PlasmaVault::VaultInfo &vaultData); Q_SCRIPTABLE void vaultRemoved(const QString &device); Q_SCRIPTABLE void vaultChanged(const PlasmaVault::VaultInfo &vaultData); private Q_SLOTS: void slotRegistered(const QDBusObjectPath &path); void registerVault(PlasmaVault::Vault *vault); void onVaultStatusChanged(PlasmaVault::VaultInfo::Status status); void onVaultMessageChanged(const QString &message); + void onVaultInfoChanged(); void onCurrentActivityChanged(const QString ¤tActivity); private: class Private; QScopedPointer d; }; #endif // include guard diff --git a/kded/ui/activitieslinkingwidget.cpp b/kded/ui/activitieslinkingwidget.cpp index b329684..7f199f9 100644 --- a/kded/ui/activitieslinkingwidget.cpp +++ b/kded/ui/activitieslinkingwidget.cpp @@ -1,109 +1,140 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #include "activitieslinkingwidget.h" #include "ui_activitieslinkingwidget.h" #include #include class ActivitiesLinkingWidget::Private { public: Ui::ActivitiesLinkingWidget ui; }; namespace { class CheckboxDelegate: public QItemDelegate { //_ public: CheckboxDelegate(QObject *parent) : QItemDelegate(parent) { } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { auto wholeRect = option.rect; // Drawing the checkbox auto checkRect = wholeRect; checkRect.setWidth(checkRect.height()); drawCheck(painter, option, checkRect, option.state & QStyle::State_Selected ? Qt::Checked : Qt::Unchecked); // Drawing the text auto textRect = wholeRect; textRect.setLeft(textRect.left() + 8 + textRect.height()); drawDisplay(painter, option, textRect, index.data(Qt::DisplayRole).toString()); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override { Q_UNUSED(option); Q_UNUSED(index); return QSize(100, 22); } }; //^ } ActivitiesLinkingWidget::ActivitiesLinkingWidget() : DialogDsl::DialogModule(true) , d(new Private()) { d->ui.setupUi(this); d->ui.listActivities->setModel(new KActivities::ActivitiesModel(this)); d->ui.listActivities->setItemDelegate(new CheckboxDelegate(this)); } ActivitiesLinkingWidget::~ActivitiesLinkingWidget() { } PlasmaVault::Vault::Payload ActivitiesLinkingWidget::fields() const { const auto selection = d->ui.listActivities->selectionModel(); QStringList selectedActivities; for (const auto &selectedIndex: selection->selectedIndexes()) { selectedActivities << selectedIndex.data(KActivities::ActivitiesModel::ActivityId) .toString(); } return { { KEY_ACTIVITIES, selectedActivities } }; } +void ActivitiesLinkingWidget::init( + const PlasmaVault::Vault::Payload &payload) +{ + const auto activities = payload[KEY_ACTIVITIES].toStringList(); + + d->ui.checkLimitActivities->setChecked(false); + d->ui.listActivities->setEnabled(false); + + auto model = d->ui.listActivities->model(); + auto selection = d->ui.listActivities->selectionModel(); + selection->clearSelection(); + + if (activities.size() > 0) { + d->ui.checkLimitActivities->setChecked(true); + d->ui.listActivities->setEnabled(true); + + for (int row = 0; row < d->ui.listActivities->model()->rowCount(); ++row) { + const auto index = model->index(row, 0); + const auto activity + = model->data(index, KActivities::ActivitiesModel::ActivityId) + .toString(); + + if (activities.contains(activity)) { + selection->select(index, QItemSelectionModel::Select); + } + } + } +} + + + diff --git a/kded/ui/activitieslinkingwidget.h b/kded/ui/activitieslinkingwidget.h index 2aa2a82..99b9421 100644 --- a/kded/ui/activitieslinkingwidget.h +++ b/kded/ui/activitieslinkingwidget.h @@ -1,48 +1,50 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #ifndef PLASMAVAULT_KDED_UI_ACTIVITIES_LINKING_WIDGET_H #define PLASMAVAULT_KDED_UI_ACTIVITIES_LINKING_WIDGET_H #include "dialogdsl.h" class ActivitiesLinkingWidget: public DialogDsl::DialogModule { Q_OBJECT public: ActivitiesLinkingWidget(); ~ActivitiesLinkingWidget(); PlasmaVault::Vault::Payload fields() const override; + void init(const PlasmaVault::Vault::Payload &payload) override; + private: class Private; QScopedPointer d; }; inline DialogDsl::ModuleFactory activitiesChooser() { return [=] { return new ActivitiesLinkingWidget(); }; } #endif // include guard diff --git a/kded/ui/dialogdsl.h b/kded/ui/dialogdsl.h index 1bd54c2..3583b7b 100644 --- a/kded/ui/dialogdsl.h +++ b/kded/ui/dialogdsl.h @@ -1,105 +1,130 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #ifndef PLASMAVAULT_KDED_UI_DIALOG_DSL_H #define PLASMAVAULT_KDED_UI_DIALOG_DSL_H #include #include #include #include #include #include namespace DialogDsl { // We want to have a normal ID for the QMap or QHash, // but we also want it to have a translated name class Key: public QByteArray { public: Key(const QByteArray &id, const QString &translation = QString()); QString translation() const; private: QString m_translation; }; namespace operators { // A nicer way to define a Key and its translation inline Key operator/ (const char *id, const QString &name) { return Key(id, name); } } // A dialog module can return a set of configured key-value pairs class DialogModule: public QWidget { Q_OBJECT Q_PROPERTY(bool isValid READ isValid WRITE setIsValid NOTIFY isValidChanged) public: DialogModule(bool isValid); virtual PlasmaVault::Vault::Payload fields() const = 0; virtual void init(const PlasmaVault::Vault::Payload &payload); virtual void aboutToBeShown(); virtual bool shouldBeShown() const; virtual void aboutToBeHidden(); bool isValid() const; void setIsValid(bool valid); Q_SIGNALS: void isValidChanged(bool valid); private: bool m_isValid; }; typedef std::function ModuleFactory; -typedef QVector step; +class step: public QVector { +public: + step() = default; + + step(const std::initializer_list& modules) + : QVector(modules) + { + } + + friend + step operator/(const QString &title, step &&from) + { + step result(std::move(from)); + result.m_title = title; + return result; + } + + QString title() const + { + return m_title; + } + +private: + QString m_title; +}; + typedef QVector steps; typedef QMap Logic; // If we want to have a single page containing multiple modules class CompoundDialogModule: public DialogModule { public: CompoundDialogModule(const step &children); PlasmaVault::Vault::Payload fields() const override; void init(const PlasmaVault::Vault::Payload &payload) override; private: QVector m_children; }; } // namespace DialogDsl #endif // include guard diff --git a/kded/ui/directorypairchooserwidget.cpp b/kded/ui/directorychooserwidget.cpp similarity index 55% copy from kded/ui/directorypairchooserwidget.cpp copy to kded/ui/directorychooserwidget.cpp index 011e472..fd8e6e4 100644 --- a/kded/ui/directorypairchooserwidget.cpp +++ b/kded/ui/directorychooserwidget.cpp @@ -1,128 +1,102 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ -#include "directorypairchooserwidget.h" -#include "ui_directorypairchooserwidget.h" +#include "directorychooserwidget.h" +#include "ui_directorychooserwidget.h" #include "vault.h" -class DirectoryPairChooserWidget::Private { +class DirectoryChooserWidget::Private { public: - Ui::DirectoryPairChooserWidget ui; - DirectoryPairChooserWidgetFlags flags; + Ui::DirectoryChooserWidget ui; + DirectoryChooserWidget::Flags flags; bool mountPointValid = false; - bool encryptedLocationValid = false; - DirectoryPairChooserWidget *const q; - Private(DirectoryPairChooserWidget *parent) + DirectoryChooserWidget *const q; + Private(DirectoryChooserWidget *parent) : q(parent) { } - void setEncryptedLocationValid(bool valid) - { - if (encryptedLocationValid == valid) return; - - encryptedLocationValid = valid; - - // We only change the global valid state if - // the mount point was already valid - if (mountPointValid) { - q->setIsValid(valid); - } - } - void setMountPointValid(bool valid) { if (mountPointValid == valid) return; mountPointValid = valid; - // We only change the global valid state if - // the enc location was already valid - if (encryptedLocationValid) { - q->setIsValid(valid); - } + q->setIsValid(valid); } bool isDirectoryValid(const QUrl &url) const { if (url.isEmpty()) return false; QDir directory(url.toString()); // TODO: Support alternative flags once they are needed if (!directory.exists() || directory.entryList().isEmpty()) return true; return false; } }; -DirectoryPairChooserWidget::DirectoryPairChooserWidget( - DirectoryPairChooserWidgetFlags flags) +DirectoryChooserWidget::DirectoryChooserWidget( + DirectoryChooserWidget::Flags flags) : DialogDsl::DialogModule(false), d(new Private(this)) { d->ui.setupUi(this); d->flags = flags; - connect(d->ui.editDevice, &KUrlRequester::textEdited, - this, [&] (const QString &url) { - d->setEncryptedLocationValid(d->isDirectoryValid(url)); - }); - connect(d->ui.editMountPoint, &KUrlRequester::textEdited, this, [&] (const QString &url) { d->setMountPointValid(d->isDirectoryValid(url)); }); - } -DirectoryPairChooserWidget::~DirectoryPairChooserWidget() +DirectoryChooserWidget::~DirectoryChooserWidget() { } -PlasmaVault::Vault::Payload DirectoryPairChooserWidget::fields() const +PlasmaVault::Vault::Payload DirectoryChooserWidget::fields() const { return { - { KEY_DEVICE, d->ui.editDevice->url().toLocalFile() }, { KEY_MOUNT_POINT, d->ui.editMountPoint->url().toLocalFile() } }; } -void DirectoryPairChooserWidget::init( +void DirectoryChooserWidget::init( const PlasmaVault::Vault::Payload &payload) { - const auto name = payload[KEY_NAME].toString(); + const auto mountPoint = payload[KEY_MOUNT_POINT].toString(); - d->ui.editDevice->setText("~/.vaults/" + name + ".enc"); - d->ui.editMountPoint->setText("~/Vaults/" + name); + d->ui.editMountPoint->setText(mountPoint); } diff --git a/kded/ui/noticewidget.h b/kded/ui/directorychooserwidget.h similarity index 68% copy from kded/ui/noticewidget.h copy to kded/ui/directorychooserwidget.h index 6b0f821..06be041 100644 --- a/kded/ui/noticewidget.h +++ b/kded/ui/directorychooserwidget.h @@ -1,54 +1,55 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ -#ifndef PLASMAVAULT_KDED_UI_NOTICE_WIDGET_H -#define PLASMAVAULT_KDED_UI_NOTICE_WIDGET_H +#ifndef PLASMAVAULT_KDED_UI_DIRECTORY_CHOOSER_WIDGET_H +#define PLASMAVAULT_KDED_UI_DIRECTORY_CHOOSER_WIDGET_H #include "dialogdsl.h" -class NoticeWidget: public DialogDsl::DialogModule { + +class DirectoryChooserWidget: public DialogDsl::DialogModule { Q_OBJECT public: - NoticeWidget(const QString ¬iceId, const QString &message); + enum Flags { + RequireNothing = 0, + RequireEmptyMountPoint = 1, + }; - ~NoticeWidget(); + DirectoryChooserWidget(Flags flags); + ~DirectoryChooserWidget(); PlasmaVault::Vault::Payload fields() const override; - - void aboutToBeShown() override; - bool shouldBeShown() const override; - void aboutToBeHidden() override; + void init(const PlasmaVault::Vault::Payload &payload) override; private: class Private; QScopedPointer d; }; -inline DialogDsl::ModuleFactory notice(const QByteArray ¬iceId, - const QString &message) +inline DialogDsl::ModuleFactory directoryChooser(DirectoryChooserWidget::Flags flags) { return [=] { - return new NoticeWidget(noticeId, message); + return new DirectoryChooserWidget(flags); }; } #endif // include guard diff --git a/kded/ui/directorychooserwidget.ui b/kded/ui/directorychooserwidget.ui new file mode 100644 index 0000000..796e55c --- /dev/null +++ b/kded/ui/directorychooserwidget.ui @@ -0,0 +1,39 @@ + + + DirectoryChooserWidget + + + + 0 + 0 + 653 + 65 + + + + + + + Mount point: + + + + + + + KFile::Directory|KFile::File|KFile::LocalOnly + + + + + + + + KUrlRequester + QWidget +
kurlrequester.h
+
+
+ + +
diff --git a/kded/ui/directorypairchooserwidget.cpp b/kded/ui/directorypairchooserwidget.cpp index 011e472..85d3c0d 100644 --- a/kded/ui/directorypairchooserwidget.cpp +++ b/kded/ui/directorypairchooserwidget.cpp @@ -1,128 +1,128 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #include "directorypairchooserwidget.h" #include "ui_directorypairchooserwidget.h" #include "vault.h" class DirectoryPairChooserWidget::Private { public: Ui::DirectoryPairChooserWidget ui; - DirectoryPairChooserWidgetFlags flags; + DirectoryPairChooserWidget::Flags flags; bool mountPointValid = false; bool encryptedLocationValid = false; DirectoryPairChooserWidget *const q; Private(DirectoryPairChooserWidget *parent) : q(parent) { } void setEncryptedLocationValid(bool valid) { if (encryptedLocationValid == valid) return; encryptedLocationValid = valid; // We only change the global valid state if // the mount point was already valid if (mountPointValid) { q->setIsValid(valid); } } void setMountPointValid(bool valid) { if (mountPointValid == valid) return; mountPointValid = valid; // We only change the global valid state if // the enc location was already valid if (encryptedLocationValid) { q->setIsValid(valid); } } bool isDirectoryValid(const QUrl &url) const { if (url.isEmpty()) return false; QDir directory(url.toString()); // TODO: Support alternative flags once they are needed if (!directory.exists() || directory.entryList().isEmpty()) return true; return false; } }; DirectoryPairChooserWidget::DirectoryPairChooserWidget( - DirectoryPairChooserWidgetFlags flags) + DirectoryPairChooserWidget::Flags flags) : DialogDsl::DialogModule(false), d(new Private(this)) { d->ui.setupUi(this); d->flags = flags; connect(d->ui.editDevice, &KUrlRequester::textEdited, this, [&] (const QString &url) { d->setEncryptedLocationValid(d->isDirectoryValid(url)); }); connect(d->ui.editMountPoint, &KUrlRequester::textEdited, this, [&] (const QString &url) { d->setMountPointValid(d->isDirectoryValid(url)); }); } DirectoryPairChooserWidget::~DirectoryPairChooserWidget() { } PlasmaVault::Vault::Payload DirectoryPairChooserWidget::fields() const { return { { KEY_DEVICE, d->ui.editDevice->url().toLocalFile() }, { KEY_MOUNT_POINT, d->ui.editMountPoint->url().toLocalFile() } }; } void DirectoryPairChooserWidget::init( const PlasmaVault::Vault::Payload &payload) { const auto name = payload[KEY_NAME].toString(); d->ui.editDevice->setText("~/.vaults/" + name + ".enc"); d->ui.editMountPoint->setText("~/Vaults/" + name); } diff --git a/kded/ui/directorypairchooserwidget.h b/kded/ui/directorypairchooserwidget.h index 789b42b..f2ff2cc 100644 --- a/kded/ui/directorypairchooserwidget.h +++ b/kded/ui/directorypairchooserwidget.h @@ -1,56 +1,57 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #ifndef PLASMAVAULT_KDED_UI_DIRECTORY_PAIR_CHOOSER_WIDGET_H #define PLASMAVAULT_KDED_UI_DIRECTORY_PAIR_CHOOSER_WIDGET_H #include "dialogdsl.h" -enum DirectoryPairChooserWidgetFlags { - RequireEmptyEncryptedLocation = 1, - RequireEmptyMountPoint = 2, - RequireEmptyDirectories = RequireEmptyEncryptedLocation | RequireEmptyMountPoint -}; - class DirectoryPairChooserWidget: public DialogDsl::DialogModule { Q_OBJECT public: - DirectoryPairChooserWidget(DirectoryPairChooserWidgetFlags flags); + enum Flags { + RequireNothing = 0, + RequireEmptyEncryptedLocation = 1, + RequireEmptyMountPoint = 2, + RequireEmptyDirectories = RequireEmptyEncryptedLocation | RequireEmptyMountPoint + }; + + DirectoryPairChooserWidget(Flags flags); ~DirectoryPairChooserWidget(); PlasmaVault::Vault::Payload fields() const override; void init(const PlasmaVault::Vault::Payload &payload) override; private: class Private; QScopedPointer d; }; -inline DialogDsl::ModuleFactory directoryPairChooser(DirectoryPairChooserWidgetFlags flags) +inline DialogDsl::ModuleFactory directoryPairChooser(DirectoryPairChooserWidget::Flags flags) { return [=] { return new DirectoryPairChooserWidget(flags); }; } #endif // include guard diff --git a/kded/ui/noticewidget.h b/kded/ui/namechooserwidget.cpp similarity index 57% copy from kded/ui/noticewidget.h copy to kded/ui/namechooserwidget.cpp index 6b0f821..6aa5c6b 100644 --- a/kded/ui/noticewidget.h +++ b/kded/ui/namechooserwidget.cpp @@ -1,54 +1,71 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ -#ifndef PLASMAVAULT_KDED_UI_NOTICE_WIDGET_H -#define PLASMAVAULT_KDED_UI_NOTICE_WIDGET_H +#include "namechooserwidget.h" +#include "ui_namechooserwidget.h" -#include "dialogdsl.h" - -class NoticeWidget: public DialogDsl::DialogModule { - Q_OBJECT +#include "vault.h" +class NameChooserWidget::Private { public: - NoticeWidget(const QString ¬iceId, const QString &message); + Ui::NameChooserWidget ui; - ~NoticeWidget(); + NameChooserWidget *const q; + Private(NameChooserWidget *parent) + : q(parent) + { + } +}; - PlasmaVault::Vault::Payload fields() const override; - void aboutToBeShown() override; - bool shouldBeShown() const override; - void aboutToBeHidden() override; -private: - class Private; - QScopedPointer d; -}; +NameChooserWidget::NameChooserWidget() + : DialogDsl::DialogModule(false), d(new Private(this)) +{ + d->ui.setupUi(this); +} -inline DialogDsl::ModuleFactory notice(const QByteArray ¬iceId, - const QString &message) + + +NameChooserWidget::~NameChooserWidget() { - return [=] { - return new NoticeWidget(noticeId, message); +} + + + +PlasmaVault::Vault::Payload NameChooserWidget::fields() const +{ + return { + { KEY_NAME, d->ui.editVaultName->text() } }; } -#endif // include guard + + +void NameChooserWidget::init( + const PlasmaVault::Vault::Payload &payload) +{ + const auto name = payload[KEY_NAME].toString(); + + d->ui.editVaultName->setText(name); +} + + diff --git a/kded/ui/activitieslinkingwidget.h b/kded/ui/namechooserwidget.h similarity index 76% copy from kded/ui/activitieslinkingwidget.h copy to kded/ui/namechooserwidget.h index 2aa2a82..0ec8e7c 100644 --- a/kded/ui/activitieslinkingwidget.h +++ b/kded/ui/namechooserwidget.h @@ -1,48 +1,50 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ -#ifndef PLASMAVAULT_KDED_UI_ACTIVITIES_LINKING_WIDGET_H -#define PLASMAVAULT_KDED_UI_ACTIVITIES_LINKING_WIDGET_H +#ifndef PLASMAVAULT_KDED_UI_NAME_CHOOSER_WIDGET_H +#define PLASMAVAULT_KDED_UI_NAME_CHOOSER_WIDGET_H #include "dialogdsl.h" -class ActivitiesLinkingWidget: public DialogDsl::DialogModule { + +class NameChooserWidget: public DialogDsl::DialogModule { Q_OBJECT public: - ActivitiesLinkingWidget(); - ~ActivitiesLinkingWidget(); + NameChooserWidget(); + ~NameChooserWidget(); PlasmaVault::Vault::Payload fields() const override; + void init(const PlasmaVault::Vault::Payload &payload) override; private: class Private; QScopedPointer d; }; -inline DialogDsl::ModuleFactory activitiesChooser() +inline DialogDsl::ModuleFactory nameChooser() { return [=] { - return new ActivitiesLinkingWidget(); + return new NameChooserWidget(); }; } #endif // include guard diff --git a/kded/ui/namechooserwidget.ui b/kded/ui/namechooserwidget.ui new file mode 100644 index 0000000..6b3144a --- /dev/null +++ b/kded/ui/namechooserwidget.ui @@ -0,0 +1,51 @@ + + + NameChooserWidget + + + + 0 + 0 + 653 + 64 + + + + + + + Vaul&t name: + + + editVaultName + + + + + + + 0 + + + + + + + + Qt::Horizontal + + + + 313 + 26 + + + + + + + + + + + diff --git a/kded/ui/noticewidget.cpp b/kded/ui/noticewidget.cpp index 4f9faf9..f40037c 100644 --- a/kded/ui/noticewidget.cpp +++ b/kded/ui/noticewidget.cpp @@ -1,90 +1,92 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #include "noticewidget.h" #include "ui_noticewidget.h" #include #include class NoticeWidget::Private { public: Ui::NoticeWidget ui; KSharedConfig::Ptr config; bool shouldBeShown; QString noticeId; }; -NoticeWidget::NoticeWidget(const QString ¬iceId, const QString &message) +NoticeWidget::NoticeWidget(const QString ¬iceId, const QString &message, + Mode mode) : DialogDsl::DialogModule(true) , d(new Private()) { d->ui.setupUi(this); d->ui.textNotice->setHtml(message); + d->ui.checkShouldBeHidden->setVisible(mode == DoNotShowAgainOption); d->noticeId = noticeId; d->config = KSharedConfig::openConfig(PLASMAVAULT_CONFIG_FILE); } NoticeWidget::~NoticeWidget() { } PlasmaVault::Vault::Payload NoticeWidget::fields() const { return {}; } void NoticeWidget::aboutToBeShown() { KConfigGroup noticeUi(d->config, "UI-notice"); d->shouldBeShown = !noticeUi.readEntry("SkipNotice-" + d->noticeId, false); d->ui.checkShouldBeHidden->setChecked(!d->shouldBeShown); } bool NoticeWidget::shouldBeShown() const { return d->shouldBeShown; } void NoticeWidget::aboutToBeHidden() { KConfigGroup noticeUi(d->config, "UI-notice"); noticeUi.writeEntry("SkipNotice-" + d->noticeId, d->ui.checkShouldBeHidden->isChecked()); d->config->sync(); } diff --git a/kded/ui/noticewidget.h b/kded/ui/noticewidget.h index 6b0f821..e2806f8 100644 --- a/kded/ui/noticewidget.h +++ b/kded/ui/noticewidget.h @@ -1,54 +1,60 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #ifndef PLASMAVAULT_KDED_UI_NOTICE_WIDGET_H #define PLASMAVAULT_KDED_UI_NOTICE_WIDGET_H #include "dialogdsl.h" class NoticeWidget: public DialogDsl::DialogModule { Q_OBJECT public: - NoticeWidget(const QString ¬iceId, const QString &message); + enum Mode { + ShowAlways, + DoNotShowAgainOption + }; + + NoticeWidget(const QString ¬iceId, const QString &message, Mode mode); ~NoticeWidget(); PlasmaVault::Vault::Payload fields() const override; void aboutToBeShown() override; bool shouldBeShown() const override; void aboutToBeHidden() override; private: class Private; QScopedPointer d; }; inline DialogDsl::ModuleFactory notice(const QByteArray ¬iceId, - const QString &message) + const QString &message, + NoticeWidget::Mode mode = NoticeWidget::DoNotShowAgainOption) { return [=] { - return new NoticeWidget(noticeId, message); + return new NoticeWidget(noticeId, message, mode); }; } #endif // include guard diff --git a/kded/ui/vaultconfigurationwizard.cpp b/kded/ui/vaultconfigurationwizard.cpp new file mode 100644 index 0000000..f41f1a3 --- /dev/null +++ b/kded/ui/vaultconfigurationwizard.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2017 by Ivan Cukic + * + * 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 . + */ + +#include "vaultconfigurationwizard.h" +#include "ui_vaultconfigurationwizard.h" + +#include +#include +#include +#include + +#include "dialogdsl.h" +#include "vault.h" + +using namespace DialogDsl; +using namespace DialogDsl::operators; + +#include "backendchooserwidget.h" +#include "activitieslinkingwidget.h" +#include "cryfscypherchooserwidget.h" +#include "directorychooserwidget.h" +#include "noticewidget.h" +#include "namechooserwidget.h" +#include "passwordchooserwidget.h" + +using PlasmaVault::Vault; + +class VaultConfigurationWizard::Private { +public: + VaultConfigurationWizard *const q; + Vault *vault; + + Ui::VaultConfigurationWizard ui; + QStackedLayout *layout; + + steps currentSteps; + QVector currentModuleDialogs; + + steps defaultSteps + { + i18n("General") / step { + nameChooser(), + directoryChooser(DirectoryChooserWidget::RequireEmptyMountPoint) + }, + + i18n("Activities") / step { + activitiesChooser() + }, + + i18n("Dismantle") / step { + notice( + "dismantle-message", + i18n("Note that Plasma Vault will not delete any of the files,\n\ + the dismantling process only removes the vault from Plasma.\n\ + You will need to remove the files manually."), + NoticeWidget::ShowAlways) + } + }; + + Logic logic + { + { "encfs" / i18n("EncFS"), + defaultSteps + }, + + { "cryfs" / i18n("CryFS"), + defaultSteps + } + }; + + Private(Vault *vault, VaultConfigurationWizard *parent) + : q(parent) + , vault(vault) + { + ui.setupUi(parent); + ui.message->hide(); + + layout = new QStackedLayout(); + layout->setContentsMargins(0, 0, 0, 0); + ui.container->setLayout(layout); + + auto tabs = new QTabWidget(); + layout->addWidget(tabs); + + // Loading the backends + auto modules = logic[Key(vault->backend().toLatin1())]; + + Vault::Payload payload { + { KEY_NAME, QVariant(vault->name()) }, + { KEY_MOUNT_POINT, QVariant(vault->mountPoint()) }, + { KEY_ACTIVITIES, QVariant(vault->activities()) } + }; + + for (const auto& module: modules) { + DialogModule *stepWidget = new CompoundDialogModule(module); + stepWidget->init(payload); + tabs->addTab(stepWidget, module.title()); + currentModuleDialogs << stepWidget; + } + } + + void setVaultOpened(bool vaultOpened) + { + bool configurationEnabled = !vaultOpened; + ui.buttons->button(QDialogButtonBox::Ok)->setEnabled(configurationEnabled); + ui.frameUnlockVault->setVisible(!configurationEnabled); + ui.container->setEnabled(configurationEnabled); + } + + void saveConfiguration() + { + Vault::Payload collectedPayload; + qDebug() << "Getting the data"; + for (const auto* module: currentModuleDialogs) { + qDebug() << "Data: " << module->fields(); + collectedPayload.unite(module->fields()); + } + + const auto name = collectedPayload[KEY_NAME].toString(); + const PlasmaVault::MountPoint mountPoint(collectedPayload[KEY_MOUNT_POINT].toString()); + const auto activities = collectedPayload[KEY_ACTIVITIES].toStringList(); + + if (name.isEmpty() || mountPoint.isEmpty()) return; + + vault->setName(name); + vault->setMountPoint(mountPoint); + vault->setActivities(activities); + } +}; + + + +VaultConfigurationWizard::VaultConfigurationWizard(Vault *vault, QWidget *parent) + : QDialog(parent) + , d(new Private(vault, this)) +{ + setWindowTitle(i18n("Configure")); + + d->setVaultOpened(vault->isOpened()); + + connect(d->ui.buttonCloseVault, &QPushButton::clicked, + this, [=] () { + vault->close(); + }); + + connect(vault, &Vault::isOpenedChanged, + this, [=] (bool isOpened) { + d->setVaultOpened(isOpened); + }); + + connect(d->ui.buttons, &QDialogButtonBox::accepted, + this, [=] { + d->saveConfiguration(); + }); +} + + + +VaultConfigurationWizard::~VaultConfigurationWizard() +{ +} + + + diff --git a/kded/ui/activitieslinkingwidget.h b/kded/ui/vaultconfigurationwizard.h similarity index 70% copy from kded/ui/activitieslinkingwidget.h copy to kded/ui/vaultconfigurationwizard.h index 2aa2a82..9765248 100644 --- a/kded/ui/activitieslinkingwidget.h +++ b/kded/ui/vaultconfigurationwizard.h @@ -1,48 +1,47 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ -#ifndef PLASMAVAULT_KDED_UI_ACTIVITIES_LINKING_WIDGET_H -#define PLASMAVAULT_KDED_UI_ACTIVITIES_LINKING_WIDGET_H +#ifndef PLASMAVAULT_KDED_UI_VAULT_CONFIGURATION_WIZARD_H +#define PLASMAVAULT_KDED_UI_VAULT_CONFIGURATION_WIZARD_H -#include "dialogdsl.h" +#include -class ActivitiesLinkingWidget: public DialogDsl::DialogModule { +namespace PlasmaVault { + class Vault; +} // namespace PlasmaVault + +class VaultConfigurationWizard: public QDialog { Q_OBJECT public: - ActivitiesLinkingWidget(); - ~ActivitiesLinkingWidget(); + VaultConfigurationWizard(PlasmaVault::Vault *vault, QWidget *parent = nullptr); + ~VaultConfigurationWizard(); - PlasmaVault::Vault::Payload fields() const override; +Q_SIGNALS: + void configurationChanged(PlasmaVault::Vault *vault); private: class Private; QScopedPointer d; }; -inline DialogDsl::ModuleFactory activitiesChooser() -{ - return [=] { - return new ActivitiesLinkingWidget(); - }; -} #endif // include guard diff --git a/kded/ui/vaultconfigurationwizard.ui b/kded/ui/vaultconfigurationwizard.ui new file mode 100644 index 0000000..0f5fc29 --- /dev/null +++ b/kded/ui/vaultconfigurationwizard.ui @@ -0,0 +1,120 @@ + + + VaultConfigurationWizard + + + + 0 + 0 + 646 + 529 + + + + Dialog + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + The vault configuration can only be changed while it is closed. + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close the vault + + + + + + + + + + + + + false + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + KMessageWidget + QFrame +
kmessagewidget.h
+
+
+ + + + buttons + accepted() + VaultConfigurationWizard + accept() + + + 254 + 522 + + + 157 + 274 + + + + + buttons + rejected() + VaultConfigurationWizard + reject() + + + 322 + 522 + + + 286 + 274 + + + + +
diff --git a/kded/ui/vaultcreationwizard.cpp b/kded/ui/vaultcreationwizard.cpp index 5305971..ff6aae7 100644 --- a/kded/ui/vaultcreationwizard.cpp +++ b/kded/ui/vaultcreationwizard.cpp @@ -1,300 +1,301 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ #include "vaultcreationwizard.h" #include "ui_vaultcreationwizard.h" #include #include #include #include #include "dialogdsl.h" #include "vault.h" using namespace DialogDsl; using namespace DialogDsl::operators; #include "backendchooserwidget.h" #include "activitieslinkingwidget.h" #include "cryfscypherchooserwidget.h" #include "directorypairchooserwidget.h" #include "noticewidget.h" #include "passwordchooserwidget.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); } QVector currentStepModules; steps currentSteps; BackendChooserWidget *firstStepModule = nullptr; DialogDsl::DialogModule *currentModule = nullptr; Logic logic { { "encfs" / i18n("EncFS"), { step { notice("encfs-message", i18n("Security notice:\n\ According to a security audit by Taylor Hornby (Defuse Security),\n\ the current implementation of Encfs is vulnerable or potentially vulnerable\n\ to multiple types of attacks.\n\ For example, an attacker with read/write access\n\ to encrypted data might lower the decryption complexity\n\ for subsequently encrypted data without this being noticed by a legitimate user,\n\ or might use timing analysis to deduce information.\n\

\n\ This means that you should not synchronize\n\ the encrypted data to a cloud storage service,\n\ or use it in other circumstances where the attacker\n\ can frequently access the encrypted data.\n\

\n\ See defuse.ca/audits/encfs.htm for more information.")) }, step { passwordChooser() }, - step { directoryPairChooser(RequireEmptyDirectories) }, + step { directoryPairChooser(DirectoryPairChooserWidget::RequireEmptyDirectories) }, step { activitiesChooser() } } }, { "cryfs" / i18n("CryFS"), { step { notice("cryfs-message", i18n("Security notice:\n\ CryFS encrypts your files, so you can safely store them anywhere.\n\ It works well together with cloud services like Dropbox, iCloud, OneDrive and others.\n\

\n\ Unlike some other file-system overlay solutions,\n\ it does not expose the directory structure,\n\ the number of files nor the file sizes\n\ through the encrypted data format.\n\

\n\ One important thing to note is that,\n\ while CryFS is considered safe,\n\ there is no independent security audit\n\ which confirms this.")) }, step { passwordChooser() }, - step { directoryPairChooser(RequireEmptyDirectories) }, + step { directoryPairChooser(DirectoryPairChooserWidget::RequireEmptyDirectories) }, step { cryfsCypherChooser(), activitiesChooser() } } } }; template 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()); } } 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) { 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(); } } void createVault() { auto collectedPayload = firstStepModule->fields(); for (const auto* module: currentStepModules) { collectedPayload.unite(module->fields()); } const auto name = collectedPayload[KEY_NAME].toString(); const PlasmaVault::Device device(collectedPayload[KEY_DEVICE].toString()); const PlasmaVault::MountPoint mountPoint(collectedPayload[KEY_MOUNT_POINT].toString()); auto vault = new PlasmaVault::Vault(device, q); auto future = vault->create(name, mountPoint, collectedPayload); auto result = AsynQt::await(future); if (result) { emit q->createdVault(vault); q->QDialog::accept(); } else { ui.message->setText(result.error().message()); ui.message->setMessageType(KMessageWidget::Error); ui.message->show(); delete vault; } } }; VaultCreationWizard::VaultCreationWizard(QWidget *parent) : QDialog(parent) , d(new Private(this)) { + setWindowTitle(i18n("Create a New Vault")); } VaultCreationWizard::~VaultCreationWizard() { } diff --git a/plasma/package/contents/ui/VaultItem.qml b/plasma/package/contents/ui/VaultItem.qml index 9b8939f..3db4afe 100644 --- a/plasma/package/contents/ui/VaultItem.qml +++ b/plasma/package/contents/ui/VaultItem.qml @@ -1,229 +1,229 @@ /* * Copyright 2017 by Ivan Cukic * * 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 . */ import QtQuick 2.1 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras MouseArea { id: vaultItem property alias icon: vaultIcon.source property alias name: vaultName.text property alias message: vaultMessage.text property string device: "" property bool isOpened: false property bool isBusy: false signal itemExpanded(variant item); function collapse() { actionsList.visible = false; } property var vaultsModelActions: plasmoid.nativeInterface.vaultsModel.source() hoverEnabled: true height: units.iconSizes.medium + 2 * units.smallSpacing + (actionsList.visible ? (actionsList.height + actionsListSpacer.height) : 0) onContainsMouseChanged: { vaultItem.ListView.view.currentIndex = (containsMouse ? index : -1) } PlasmaCore.IconItem { id: vaultIcon anchors { left: parent.left top: parent.top margins: units.smallSpacing } width: units.iconSizes.medium height: units.iconSizes.medium PlasmaCore.IconItem { anchors { left: parent.left bottom: parent.bottom } width: units.iconSizes.small height: units.iconSizes.small visible: source != "" source: { return vaultItem.message != "" ? "emblem-error" : vaultItem.isOpened ? "emblem-mounted" : "" } } } PlasmaComponents.ToolButton { id: buttonOpenClose anchors { right: parent.right top: parent.top margins: units.smallSpacing } width: units.iconSizes.medium height: units.iconSizes.medium visible: !busyIndicator.visible iconName: isOpened ? "media-eject" : "media-mount" onClicked: { vaultsModelActions.toggle(vaultItem.device); collapse(); itemExpanded(null); } } PlasmaComponents.BusyIndicator { id: busyIndicator anchors.fill: buttonOpenClose visible: isBusy } Column { anchors { left: vaultIcon.right right: buttonOpenClose.left verticalCenter: parent.verticalCenter margins: units.smallSpacing leftMargin: 2 * units.smallSpacing } PlasmaComponents.Label { id: vaultName width: parent.width height: undefined elide: Text.ElideRight } PlasmaComponents.Label { id: vaultMessage width: parent.width height: undefined elide: Text.ElideRight visible: { return vaultMessage.text != ""; } } Item { id: actionsListSpacer height: units.largeSpacing width: parent.width visible: actionsList.visible } ListView { id: actionsList height: units.iconSizes.medium * model.count width: parent.width visible: false highlight: PlasmaComponents.Highlight { id: highlight } model: actionsModel ListModel { id: actionsModel } delegate: ActionItem { icon: model.icon text: model.text width: parent.width onActivated: { if (model.action == "file-manager") { vaultsModelActions.openInFileManager(vaultItem.device); } else if (model.action == "force-close") { vaultsModelActions.forceClose(vaultItem.device); } else if (model.action == "configure") { vaultsModelActions.configure(vaultItem.device); } collapse(); itemExpanded(null); } } } } MouseArea { anchors.fill: parent visible: !actionsList.visible onClicked: { actionsList.visible = !actionsList.visible; if (actionsList.visible) { vaultItem.itemExpanded(vaultItem); actionsModel.clear(); actionsModel.append({ "icon" : "system-file-manager", "text" : i18nd("plasmavault-kde", "Open with File Manager"), "action" : "file-manager" }); if (vaultItem.message != "") { actionsModel.append({ "icon" : "window-close", "text" : i18nd("plasmavault-kde", "Forcefully close "), "action" : "force-close" }); } - // actionsModel.append({ - // "icon" : "configure", - // "text" : i18nd("plasmavault-kde", "Configure Vault..."), - // "action" : "configure" - // }); + actionsModel.append({ + "icon" : "configure", + "text" : i18nd("plasmavault-kde", "Configure Vault..."), + "action" : "configure" + }); } } } }