diff --git a/COPYING b/COPYING
index 9bfd3353..fe7d02f3 100644
--- a/COPYING
+++ b/COPYING
@@ -248,3 +248,8 @@ Comment: from Freedesktop.org website
Files: share/icons/application/32x32/actions/statistics.png
Copyright: Icon made by Freepik from https://www.flaticon.com/free-icon/bars-chart_265733
+
+Files: share/icons/application/scalable/actions/object-locked.svg
+ share/icons/application/scalable/actions/object-unlocked.svg
+License: LGPL-3
+Comment: from Breeze icon theme (https://github.com/KDE/breeze-icons)
diff --git a/share/icons/application/scalable/actions/object-locked.svg b/share/icons/application/scalable/actions/object-locked.svg
new file mode 100644
index 00000000..090e038c
--- /dev/null
+++ b/share/icons/application/scalable/actions/object-locked.svg
@@ -0,0 +1,14 @@
+
diff --git a/share/icons/application/scalable/actions/object-unlocked.svg b/share/icons/application/scalable/actions/object-unlocked.svg
new file mode 100644
index 00000000..f6c53e58
--- /dev/null
+++ b/share/icons/application/scalable/actions/object-unlocked.svg
@@ -0,0 +1,15 @@
+
diff --git a/src/fdosecrets/CMakeLists.txt b/src/fdosecrets/CMakeLists.txt
index 9d3fcb6a..a9750bc2 100644
--- a/src/fdosecrets/CMakeLists.txt
+++ b/src/fdosecrets/CMakeLists.txt
@@ -4,6 +4,7 @@ if(WITH_XC_FDOSECRETS)
add_library(fdosecrets STATIC
# app settings page
FdoSecretsPlugin.cpp
+ widgets/SettingsModels.cpp
widgets/SettingsWidgetFdoSecrets.cpp
# per database settings page
diff --git a/src/fdosecrets/FdoSecretsPlugin.cpp b/src/fdosecrets/FdoSecretsPlugin.cpp
index 668b5fb0..646f8530 100644
--- a/src/fdosecrets/FdoSecretsPlugin.cpp
+++ b/src/fdosecrets/FdoSecretsPlugin.cpp
@@ -60,11 +60,15 @@ void FdoSecretsPlugin::updateServiceState()
});
if (!m_secretService->initialize()) {
m_secretService.reset();
+ FdoSecrets::settings()->setEnabled(false);
+ return;
}
+ emit secretServiceStarted();
}
} else {
if (m_secretService) {
m_secretService.reset();
+ emit secretServiceStopped();
}
}
}
@@ -74,6 +78,11 @@ Service* FdoSecretsPlugin::serviceInstance() const
return m_secretService.data();
}
+DatabaseTabWidget* FdoSecretsPlugin::dbTabs() const
+{
+ return m_dbTabs;
+}
+
void FdoSecretsPlugin::emitRequestSwitchToDatabases()
{
emit requestSwitchToDatabases();
diff --git a/src/fdosecrets/FdoSecretsPlugin.h b/src/fdosecrets/FdoSecretsPlugin.h
index 2a57ea0d..828c0bd7 100644
--- a/src/fdosecrets/FdoSecretsPlugin.h
+++ b/src/fdosecrets/FdoSecretsPlugin.h
@@ -59,6 +59,11 @@ public:
*/
FdoSecrets::Service* serviceInstance() const;
+ /**
+ * @return The db tabs widget, containing opened databases. Can be nullptr.
+ */
+ DatabaseTabWidget* dbTabs() const;
+
public slots:
void emitRequestSwitchToDatabases();
void emitRequestShowNotification(const QString& msg, const QString& title = {});
@@ -67,6 +72,8 @@ signals:
void error(const QString& msg);
void requestSwitchToDatabases();
void requestShowNotification(const QString& msg, const QString& title, int msTimeoutHint);
+ void secretServiceStarted();
+ void secretServiceStopped();
private:
QPointer m_dbTabs;
diff --git a/src/fdosecrets/widgets/SettingsModels.cpp b/src/fdosecrets/widgets/SettingsModels.cpp
new file mode 100644
index 00000000..edcb275c
--- /dev/null
+++ b/src/fdosecrets/widgets/SettingsModels.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2019 Aetf
+ *
+ * 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 or (at your option)
+ * 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 "SettingsModels.h"
+
+#include "fdosecrets/FdoSecretsPlugin.h"
+#include "fdosecrets/FdoSecretsSettings.h"
+#include "fdosecrets/objects/Service.h"
+#include "fdosecrets/objects/Session.h"
+
+#include "core/Database.h"
+#include "core/DatabaseIcons.h"
+#include "core/FilePath.h"
+#include "gui/DatabaseTabWidget.h"
+#include "gui/DatabaseWidget.h"
+
+#include
+
+namespace FdoSecrets
+{
+
+ SettingsDatabaseModel::SettingsDatabaseModel(DatabaseTabWidget* dbTabs, QObject* parent)
+ : QAbstractTableModel(parent)
+ , m_dbTabs(nullptr)
+ {
+ setTabWidget(dbTabs);
+ }
+
+ void SettingsDatabaseModel::setTabWidget(DatabaseTabWidget* dbTabs)
+ {
+ auto old = m_dbTabs;
+ m_dbTabs = dbTabs;
+ if (old != m_dbTabs) {
+ populateModel();
+ }
+ }
+
+ int SettingsDatabaseModel::rowCount(const QModelIndex& parent) const
+ {
+ if (parent.isValid()) {
+ return 0;
+ }
+ return m_dbs.size();
+ }
+
+ int SettingsDatabaseModel::columnCount(const QModelIndex& parent) const
+ {
+ if (parent.isValid()) {
+ return 0;
+ }
+ return 3;
+ }
+
+ QVariant SettingsDatabaseModel::headerData(int section, Qt::Orientation orientation, int role) const
+ {
+ if (orientation != Qt::Horizontal) {
+ return {};
+ }
+
+ if (role != Qt::DisplayRole) {
+ return {};
+ }
+
+ switch (section) {
+ case 0:
+ return tr("File Name");
+ case 1:
+ return tr("Group");
+ case 2:
+ return tr("Manage");
+ default:
+ return {};
+ }
+ }
+
+ QVariant SettingsDatabaseModel::data(const QModelIndex& index, int role) const
+ {
+ if (!index.isValid()) {
+ return {};
+ }
+ const auto& dbWidget = m_dbs[index.row()];
+ if (!dbWidget) {
+ return {};
+ }
+
+ switch (index.column()) {
+ case 0:
+ return dataForName(dbWidget, role);
+ case 1:
+ return dataForExposedGroup(dbWidget, role);
+ case 2:
+ return dataForManage(dbWidget, role);
+ default:
+ return {};
+ }
+ }
+
+ QVariant SettingsDatabaseModel::dataForName(DatabaseWidget* db, int role) const
+ {
+ switch (role) {
+ case Qt::DisplayRole: {
+ QFileInfo fi(db->database()->filePath());
+ return fi.fileName();
+ }
+ case Qt::ToolTipRole:
+ return db->database()->filePath();
+ default:
+ return {};
+ }
+ }
+
+ QVariant SettingsDatabaseModel::dataForExposedGroup(DatabaseWidget* dbWidget, int role)
+ {
+ if (dbWidget->isLocked()) {
+ switch (role) {
+ case Qt::DisplayRole:
+ return tr("Unlock to show");
+ case Qt::DecorationRole:
+ return filePath()->icon(QStringLiteral("apps"), QStringLiteral("object-locked"), true);
+ case Qt::FontRole: {
+ QFont font;
+ font.setItalic(true);
+ return font;
+ }
+ default:
+ return {};
+ }
+ }
+ auto db = dbWidget->database();
+ auto group = db->rootGroup()->findGroupByUuid(FdoSecrets::settings()->exposedGroup(db));
+ if (group) {
+ switch (role) {
+ case Qt::DisplayRole:
+ return group->name();
+ case Qt::DecorationRole:
+ return group->isExpired() ? databaseIcons()->iconPixmap(DatabaseIcons::ExpiredIconIndex)
+ : group->iconScaledPixmap();
+ case Qt::FontRole:
+ if (group->isExpired()) {
+ QFont font;
+ font.setStrikeOut(true);
+ return font;
+ } else {
+ return {};
+ }
+ default:
+ return {};
+ }
+ } else {
+ switch (role) {
+ case Qt::DisplayRole:
+ return tr("None");
+ case Qt::DecorationRole:
+ return filePath()->icon(QStringLiteral("apps"), QStringLiteral("paint-none"), true);
+ default:
+ return {};
+ }
+ }
+ }
+
+ QVariant SettingsDatabaseModel::dataForManage(DatabaseWidget* db, int role) const
+ {
+ switch (role) {
+ case Qt::EditRole:
+ return QVariant::fromValue(db);
+ default:
+ return {};
+ }
+ }
+
+ void SettingsDatabaseModel::populateModel()
+ {
+ beginResetModel();
+
+ m_dbs.clear();
+
+ if (m_dbTabs) {
+ // Add existing database tabs
+ for (int idx = 0; idx != m_dbTabs->count(); ++idx) {
+ auto dbWidget = m_dbTabs->databaseWidgetFromIndex(idx);
+ databaseAdded(dbWidget, false);
+ }
+ // connect signals
+ connect(m_dbTabs, &DatabaseTabWidget::databaseOpened, this, [this](DatabaseWidget* db) {
+ databaseAdded(db, true);
+ });
+ connect(m_dbTabs, &DatabaseTabWidget::databaseClosed, this, &SettingsDatabaseModel::databaseRemoved);
+ }
+
+ endResetModel();
+ }
+
+ void SettingsDatabaseModel::databaseAdded(DatabaseWidget* db, bool emitSignals)
+ {
+ int row = m_dbs.size();
+ if (emitSignals) {
+ beginInsertRows({}, row, row);
+ }
+
+ m_dbs.append(db);
+ connect(db, &DatabaseWidget::databaseLocked, this, [row, this]() {
+ emit dataChanged(index(row, 1), index(row, 2));
+ });
+ connect(db, &DatabaseWidget::databaseUnlocked, this, [row, this]() {
+ emit dataChanged(index(row, 1), index(row, 2));
+ });
+ connect(db, &DatabaseWidget::databaseModified, this, [row, this]() {
+ emit dataChanged(index(row, 0), index(row, 2));
+ });
+ connect(db, &DatabaseWidget::databaseFilePathChanged, this, [row, this]() {
+ emit dataChanged(index(row, 0), index(row, 2));
+ });
+
+ if (emitSignals) {
+ endInsertRows();
+ }
+ }
+
+ void SettingsDatabaseModel::databaseRemoved(const QString& filePath)
+ {
+ for (int i = 0; i != m_dbs.size(); i++) {
+ if (m_dbs[i] && m_dbs[i]->database()->filePath() == filePath) {
+ beginRemoveRows({}, i, i);
+
+ m_dbs[i]->disconnect(this);
+ m_dbs.removeAt(i);
+
+ endRemoveRows();
+ break;
+ }
+ }
+ }
+
+ SettingsSessionModel::SettingsSessionModel(FdoSecretsPlugin* plugin, QObject* parent)
+ : QAbstractTableModel(parent)
+ , m_service(nullptr)
+ {
+ setService(plugin->serviceInstance());
+ connect(plugin, &FdoSecretsPlugin::secretServiceStarted, this, [plugin, this]() {
+ setService(plugin->serviceInstance());
+ });
+ connect(plugin, &FdoSecretsPlugin::secretServiceStopped, this, [this]() { setService(nullptr); });
+ }
+
+ void SettingsSessionModel::setService(Service* service)
+ {
+ auto old = m_service;
+ m_service = service;
+ if (old != m_service) {
+ populateModel();
+ }
+ }
+
+ int SettingsSessionModel::rowCount(const QModelIndex& parent) const
+ {
+ if (parent.isValid()) {
+ return 0;
+ }
+ return m_sessions.size();
+ }
+
+ int SettingsSessionModel::columnCount(const QModelIndex& parent) const
+ {
+ if (parent.isValid()) {
+ return 0;
+ }
+ return 2;
+ }
+
+ QVariant SettingsSessionModel::headerData(int section, Qt::Orientation orientation, int role) const
+ {
+ if (orientation != Qt::Horizontal) {
+ return {};
+ }
+
+ if (role != Qt::DisplayRole) {
+ return {};
+ }
+
+ switch (section) {
+ case 0:
+ return tr("Application");
+ case 1:
+ return tr("Manage");
+ default:
+ return {};
+ }
+ }
+
+ QVariant SettingsSessionModel::data(const QModelIndex& index, int role) const
+ {
+ if (!index.isValid()) {
+ return {};
+ }
+ const auto& sess = m_sessions[index.row()];
+ if (!sess) {
+ return {};
+ }
+
+ switch (index.column()) {
+ case 0:
+ return dataForApplication(sess, role);
+ case 1:
+ return dataForManage(sess, role);
+ default:
+ return {};
+ }
+ }
+
+ QVariant SettingsSessionModel::dataForApplication(Session* sess, int role) const
+ {
+ switch (role) {
+ case Qt::DisplayRole:
+ return sess->peer();
+ default:
+ return {};
+ }
+ }
+
+ QVariant SettingsSessionModel::dataForManage(Session* sess, int role) const
+ {
+ switch (role) {
+ case Qt::EditRole: {
+ auto v = QVariant::fromValue(sess);
+ qDebug() << v << v.type() << v.userType();
+ return v;
+ }
+ default:
+ return {};
+ }
+ }
+
+ void SettingsSessionModel::populateModel()
+ {
+ beginResetModel();
+
+ m_sessions.clear();
+
+ if (m_service) {
+ // Add existing database tabs
+ for (const auto& sess : m_service->sessions()) {
+ sessionAdded(sess, false);
+ }
+
+ // connect signals
+ connect(m_service, &Service::sessionOpened, this, [this](Session* sess) { sessionAdded(sess, true); });
+ connect(m_service, &Service::sessionClosed, this, &SettingsSessionModel::sessionRemoved);
+ }
+
+ endResetModel();
+ }
+
+ void SettingsSessionModel::sessionAdded(Session* sess, bool emitSignals)
+ {
+ int row = m_sessions.size();
+ if (emitSignals) {
+ beginInsertRows({}, row, row);
+ }
+
+ m_sessions.append(sess);
+
+ if (emitSignals) {
+ endInsertRows();
+ }
+ }
+
+ void SettingsSessionModel::sessionRemoved(Session* sess)
+ {
+ for (int i = 0; i != m_sessions.size(); i++) {
+ if (m_sessions[i] == sess) {
+ beginRemoveRows({}, i, i);
+
+ m_sessions[i]->disconnect(this);
+ m_sessions.removeAt(i);
+
+ endRemoveRows();
+ break;
+ }
+ }
+ }
+
+} // namespace FdoSecrets
diff --git a/src/fdosecrets/widgets/SettingsModels.h b/src/fdosecrets/widgets/SettingsModels.h
new file mode 100644
index 00000000..b07bb163
--- /dev/null
+++ b/src/fdosecrets/widgets/SettingsModels.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 Aetf
+ *
+ * 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 or (at your option)
+ * 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 KEEPASSXC_FDOSECRETS_SETTINGSMODELS_H
+#define KEEPASSXC_FDOSECRETS_SETTINGSMODELS_H
+
+#include
+#include
+
+class DatabaseTabWidget;
+class DatabaseWidget;
+class FdoSecretsPlugin;
+
+namespace FdoSecrets
+{
+ class SettingsDatabaseModel : public QAbstractTableModel
+ {
+ Q_OBJECT
+ public:
+ explicit SettingsDatabaseModel(DatabaseTabWidget* dbTabs, QObject* parent = nullptr);
+
+ void setTabWidget(DatabaseTabWidget* dbTabs);
+
+ int rowCount(const QModelIndex& parent) const override;
+ int columnCount(const QModelIndex& parent) const override;
+ QVariant data(const QModelIndex& index, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+ private:
+ QVariant dataForName(DatabaseWidget* db, int role) const;
+ static QVariant dataForExposedGroup(DatabaseWidget* db, int role);
+ QVariant dataForManage(DatabaseWidget* db, int role) const;
+
+ private slots:
+ void populateModel();
+ void databaseAdded(DatabaseWidget* db, bool emitSignals);
+ void databaseRemoved(const QString& filePath);
+
+ private:
+ // source
+ QPointer m_dbTabs;
+
+ // internal store
+ QList> m_dbs;
+ };
+
+ class Service;
+ class Session;
+
+ class SettingsSessionModel : public QAbstractTableModel
+ {
+ Q_OBJECT
+ public:
+ explicit SettingsSessionModel(FdoSecretsPlugin* plugin, QObject* parent = nullptr);
+
+ int rowCount(const QModelIndex& parent) const override;
+ int columnCount(const QModelIndex& parent) const override;
+ QVariant data(const QModelIndex& index, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+ private:
+ void setService(Service* service);
+
+ QVariant dataForApplication(Session* sess, int role) const;
+ QVariant dataForManage(Session* sess, int role) const;
+
+ private slots:
+ void populateModel();
+ void sessionAdded(Session* sess, bool emitSignals);
+ void sessionRemoved(Session* sess);
+
+ private:
+ // source
+ QPointer m_service;
+
+ // internal copy, so we can emit with changed index
+ QList m_sessions;
+ };
+
+} // namespace FdoSecrets
+
+#endif // KEEPASSXC_FDOSECRETS_SETTINGSMODELS_H
diff --git a/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.cpp b/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.cpp
index 920b603d..59399cde 100644
--- a/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.cpp
+++ b/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.cpp
@@ -20,241 +20,273 @@
#include "fdosecrets/FdoSecretsPlugin.h"
#include "fdosecrets/FdoSecretsSettings.h"
-#include "fdosecrets/objects/Collection.h"
-#include "fdosecrets/objects/Prompt.h"
#include "fdosecrets/objects/Session.h"
+#include "fdosecrets/widgets/SettingsModels.h"
-#include "core/DatabaseIcons.h"
#include "core/FilePath.h"
#include "gui/DatabaseWidget.h"
#include
-#include
-#include
#include
-#include
-#include
+#include
+#include
#include
#include
-using FdoSecrets::Collection;
-using FdoSecrets::Service;
using FdoSecrets::Session;
+using FdoSecrets::SettingsDatabaseModel;
+using FdoSecrets::SettingsSessionModel;
+
+namespace
+{
+ class ManageDatabase : public QToolBar
+ {
+ Q_OBJECT
+
+ Q_PROPERTY(DatabaseWidget* dbWidget READ dbWidget WRITE setDbWidget USER true)
+
+ public:
+ explicit ManageDatabase(FdoSecretsPlugin* plugin, QWidget* parent = nullptr)
+ : QToolBar(parent)
+ , m_plugin(plugin)
+ {
+ setFloatable(false);
+ setMovable(false);
+
+ // use a dummy widget to center the buttons
+ auto spacer = new QWidget(this);
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ spacer->setVisible(true);
+ addWidget(spacer);
+
+ // db settings
+ m_dbSettingsAct = new QAction(tr("Database settings"), this);
+ m_dbSettingsAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("document-edit")));
+ m_dbSettingsAct->setToolTip(tr("Edit database settings"));
+ m_dbSettingsAct->setEnabled(false);
+ connect(m_dbSettingsAct, &QAction::triggered, this, [this]() {
+ if (!m_dbWidget) {
+ return;
+ }
+ auto db = m_dbWidget;
+ m_plugin->serviceInstance()->doSwitchToChangeDatabaseSettings(m_dbWidget);
+ });
+ addAction(m_dbSettingsAct);
+
+ // unlock/lock
+ m_lockAct = new QAction(tr("Unlock database"), this);
+ m_lockAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("object-locked"), false));
+ m_lockAct->setToolTip(tr("Unlock database to show more information"));
+ connect(m_lockAct, &QAction::triggered, this, [this]() {
+ if (!m_dbWidget) {
+ return;
+ }
+ if (m_dbWidget->isLocked()) {
+ m_plugin->serviceInstance()->doUnlockDatabaseInDialog(m_dbWidget);
+ } else {
+ m_dbWidget->lock();
+ }
+ });
+
+ addAction(m_lockAct);
+
+ // use a dummy widget to center the buttons
+ spacer = new QWidget(this);
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ spacer->setVisible(true);
+ addWidget(spacer);
+ }
+
+ DatabaseWidget* dbWidget() const
+ {
+ return m_dbWidget;
+ }
+
+ void setDbWidget(DatabaseWidget* dbWidget)
+ {
+ if (m_dbWidget == dbWidget) {
+ return;
+ }
+
+ if (m_dbWidget) {
+ disconnect();
+ }
+
+ m_dbWidget = dbWidget;
+
+ reconnect();
+ }
+
+ private:
+ void disconnect()
+ {
+ if (!m_dbWidget) {
+ return;
+ }
+ m_dbWidget->disconnect(this);
+ }
+
+ void reconnect()
+ {
+ if (!m_dbWidget) {
+ return;
+ }
+ connect(m_dbWidget, &DatabaseWidget::databaseLocked, this, [this]() {
+ m_lockAct->setText(tr("Unlock database"));
+ m_lockAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("object-locked"), false));
+ m_lockAct->setToolTip(tr("Unlock database to show more information"));
+ m_dbSettingsAct->setEnabled(false);
+ });
+ connect(m_dbWidget, &DatabaseWidget::databaseUnlocked, this, [this]() {
+ m_lockAct->setText(tr("Lock database"));
+ m_lockAct->setIcon(
+ filePath()->icon(QStringLiteral("actions"), QStringLiteral("object-unlocked"), false));
+ m_lockAct->setToolTip(tr("Lock database"));
+ m_dbSettingsAct->setEnabled(true);
+ });
+ }
+
+ private:
+ FdoSecretsPlugin* m_plugin = nullptr;
+ QPointer m_dbWidget = nullptr;
+ QAction* m_dbSettingsAct = nullptr;
+ QAction* m_lockAct = nullptr;
+ };
+
+ class ManageSession : public QToolBar
+ {
+ Q_OBJECT
+
+ Q_PROPERTY(Session* session READ session WRITE setSession USER true)
+
+ public:
+ explicit ManageSession(FdoSecretsPlugin*, QWidget* parent = nullptr)
+ : QToolBar(parent)
+ {
+ setFloatable(false);
+ setMovable(false);
+
+ // use a dummy widget to center the buttons
+ auto spacer = new QWidget(this);
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ spacer->setVisible(true);
+ addWidget(spacer);
+
+ m_disconnectAct = new QAction(tr("Disconnect"), this);
+ m_disconnectAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("dialog-close")));
+ m_disconnectAct->setToolTip(tr("Disconnect this application"));
+ connect(m_disconnectAct, &QAction::triggered, this, [this]() {
+ if (m_session) {
+ m_session->close();
+ }
+ });
+ addAction(m_disconnectAct);
+
+ // use a dummy widget to center the buttons
+ spacer = new QWidget(this);
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ spacer->setVisible(true);
+ addWidget(spacer);
+ }
+
+ Session* session()
+ {
+ return m_session;
+ }
+
+ void setSession(Session* sess)
+ {
+ m_session = sess;
+ }
+
+ private:
+ Session* m_session = nullptr;
+ QAction* m_disconnectAct = nullptr;
+ };
+
+ template class Creator : public QItemEditorCreatorBase
+ {
+ public:
+ inline explicit Creator(FdoSecretsPlugin* plugin)
+ : QItemEditorCreatorBase()
+ , m_plugin(plugin)
+ , m_propertyName(T::staticMetaObject.userProperty().name())
+ {
+ }
+
+ inline QWidget* createWidget(QWidget* parent) const override
+ {
+ return new T(m_plugin, parent);
+ }
+
+ inline QByteArray valuePropertyName() const override
+ {
+ return m_propertyName;
+ }
+
+ private:
+ FdoSecretsPlugin* m_plugin;
+ QByteArray m_propertyName;
+ };
+} // namespace
SettingsWidgetFdoSecrets::SettingsWidgetFdoSecrets(FdoSecretsPlugin* plugin, QWidget* parent)
: QWidget(parent)
, m_ui(new Ui::SettingsWidgetFdoSecrets())
+ , m_factory(new QItemEditorFactory)
, m_plugin(plugin)
{
m_ui->setupUi(this);
- auto sessHeader = m_ui->tableSessions->horizontalHeader();
- sessHeader->setSelectionMode(QAbstractItemView::NoSelection);
- sessHeader->setSectionsClickable(false);
- sessHeader->setSectionResizeMode(0, QHeaderView::Stretch); // application
- sessHeader->setSectionResizeMode(1, QHeaderView::ResizeToContents); // disconnect button
+ auto sessModel = new SettingsSessionModel(plugin, this);
+ m_ui->tableSessions->setModel(sessModel);
+ setupView(m_ui->tableSessions, 1, qMetaTypeId(), new Creator(m_plugin));
- auto dbHeader = m_ui->tableDatabases->horizontalHeader();
- dbHeader->setSelectionMode(QAbstractItemView::NoSelection);
- dbHeader->setSectionsClickable(false);
- dbHeader->setSectionResizeMode(0, QHeaderView::Stretch); // file name
- dbHeader->setSectionResizeMode(1, QHeaderView::Stretch); // group
- dbHeader->setSectionResizeMode(2, QHeaderView::ResizeToContents); // manage button
+ // config header after setting model, otherwise the header doesn't have enough sections
+ auto sessViewHeader = m_ui->tableSessions->horizontalHeader();
+ sessViewHeader->setSelectionMode(QAbstractItemView::NoSelection);
+ sessViewHeader->setSectionsClickable(false);
+ sessViewHeader->setSectionResizeMode(0, QHeaderView::Stretch); // application
+ sessViewHeader->setSectionResizeMode(1, QHeaderView::ResizeToContents); // disconnect button
+
+ auto dbModel = new SettingsDatabaseModel(plugin->dbTabs(), this);
+ m_ui->tableDatabases->setModel(dbModel);
+ setupView(m_ui->tableDatabases, 2, qMetaTypeId(), new Creator(m_plugin));
+
+ // config header after setting model, otherwise the header doesn't have enough sections
+ auto dbViewHeader = m_ui->tableDatabases->horizontalHeader();
+ dbViewHeader->setSelectionMode(QAbstractItemView::NoSelection);
+ dbViewHeader->setSectionsClickable(false);
+ dbViewHeader->setSectionResizeMode(0, QHeaderView::Stretch); // file name
+ dbViewHeader->setSectionResizeMode(1, QHeaderView::Stretch); // group
+ dbViewHeader->setSectionResizeMode(2, QHeaderView::ResizeToContents); // manage button
m_ui->tabWidget->setEnabled(m_ui->enableFdoSecretService->isChecked());
connect(m_ui->enableFdoSecretService, &QCheckBox::toggled, m_ui->tabWidget, &QTabWidget::setEnabled);
}
+void SettingsWidgetFdoSecrets::setupView(QAbstractItemView* view,
+ int manageColumn,
+ int editorTypeId,
+ QItemEditorCreatorBase* creator)
+{
+ auto manageButtonDelegate = new QStyledItemDelegate(this);
+ m_factory->registerEditor(editorTypeId, creator);
+ manageButtonDelegate->setItemEditorFactory(m_factory.data());
+ view->setItemDelegateForColumn(manageColumn, manageButtonDelegate);
+ connect(view->model(),
+ &QAbstractItemModel::rowsInserted,
+ this,
+ [view, manageColumn](const QModelIndex&, int first, int last) {
+ for (int i = first; i <= last; ++i) {
+ auto idx = view->model()->index(i, manageColumn);
+ view->openPersistentEditor(idx);
+ }
+ });
+}
+
SettingsWidgetFdoSecrets::~SettingsWidgetFdoSecrets() = default;
-void SettingsWidgetFdoSecrets::populateSessions(bool enabled)
-{
- m_ui->tableSessions->setRowCount(0);
-
- auto service = m_plugin->serviceInstance();
- if (!service || !enabled) {
- return;
- }
-
- for (const auto& sess : service->sessions()) {
- addSessionRow(sess);
- }
-}
-
-void SettingsWidgetFdoSecrets::addSessionRow(Session* sess)
-{
- auto row = m_ui->tableSessions->rowCount();
- m_ui->tableSessions->insertRow(row);
-
- // column 0: application name
- auto item = new QTableWidgetItem(sess->peer());
- item->setData(Qt::UserRole, QVariant::fromValue(sess));
- m_ui->tableSessions->setItem(row, 0, item);
-
- // column 1: disconnect button
- auto btn = new QPushButton(tr("Disconnect"));
- connect(btn, &QPushButton::clicked, sess, &Session::close);
- m_ui->tableSessions->setCellWidget(row, 1, btn);
-
- // column 2: hidden uuid
- m_ui->tableSessions->setItem(row, 2, new QTableWidgetItem(sess->id()));
-}
-
-void SettingsWidgetFdoSecrets::removeSessionRow(Session* sess)
-{
- int row = 0;
- while (row != m_ui->tableSessions->rowCount()) {
- auto item = m_ui->tableSessions->item(row, 0);
- const auto itemSess = item->data(Qt::UserRole).value();
- if (itemSess == sess) {
- break;
- }
- ++row;
- }
- if (row == m_ui->tableSessions->rowCount()) {
- qWarning() << "Unknown Fdo Secret Service session" << sess->id() << "while removing collection from table";
- return;
- }
-
- m_ui->tableSessions->removeRow(row);
-}
-
-void SettingsWidgetFdoSecrets::populateDatabases(bool enabled)
-{
- m_ui->tableDatabases->setRowCount(0);
-
- auto service = m_plugin->serviceInstance();
- if (!service || !enabled) {
- return;
- }
-
- auto ret = service->collections();
- if (ret.isError()) {
- return;
- }
- for (const auto& coll : ret.value()) {
- addDatabaseRow(coll);
- }
-}
-
-void SettingsWidgetFdoSecrets::addDatabaseRow(Collection* coll)
-{
- auto row = m_ui->tableDatabases->rowCount();
- m_ui->tableDatabases->insertRow(row);
-
- // column 0: File name
- QFileInfo fi(coll->backend()->database()->filePath());
- auto item = new QTableWidgetItem(fi.fileName());
- item->setData(Qt::UserRole, QVariant::fromValue(coll));
- m_ui->tableDatabases->setItem(row, 0, item);
-
- // column 2: manage button: hboxlayout: unlock/lock settings
- // create this first so we have a widget to bind connection to,
- // which can then be auto deleted when the row is deleted.
- auto widget = createManageButtons(coll);
- m_ui->tableDatabases->setCellWidget(row, 2, widget);
-
- // column 1: Group name
- auto itemGroupName = new QTableWidgetItem();
- updateExposedGroupItem(itemGroupName, coll);
-
- connect(coll, &Collection::collectionLockChanged, widget, [this, itemGroupName, coll](bool) {
- updateExposedGroupItem(itemGroupName, coll);
- });
-
- m_ui->tableDatabases->setItem(row, 1, itemGroupName);
-}
-
-QWidget* SettingsWidgetFdoSecrets::createManageButtons(Collection* coll)
-{
- auto toolbar = new QToolBar;
- toolbar->setFloatable(false);
- toolbar->setMovable(false);
-
- // db settings
- auto dbSettingsAct = new QAction(tr("Database settings"), toolbar);
- dbSettingsAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("document-edit")));
- dbSettingsAct->setToolTip(tr("Edit database settings"));
- dbSettingsAct->setEnabled(!coll->locked().value());
- connect(dbSettingsAct, &QAction::triggered, this, [this, coll]() {
- auto db = coll->backend();
- m_plugin->serviceInstance()->doSwitchToChangeDatabaseSettings(db);
- });
- toolbar->addAction(dbSettingsAct);
-
- // unlock/lock
- auto lockAct = new QAction(tr("Unlock database"), toolbar);
- lockAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("object-locked"), true));
- lockAct->setToolTip(tr("Unlock database to show more information"));
- connect(coll, &Collection::collectionLockChanged, lockAct, [lockAct, dbSettingsAct](bool locked) {
- if (locked) {
- lockAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("object-locked"), true));
- lockAct->setToolTip(tr("Unlock database to show more information"));
- } else {
- lockAct->setIcon(filePath()->icon(QStringLiteral("actions"), QStringLiteral("object-unlocked"), true));
- lockAct->setToolTip(tr("Lock database"));
- }
- dbSettingsAct->setEnabled(!locked);
- });
- connect(lockAct, &QAction::triggered, this, [coll]() {
- if (coll->locked().value()) {
- coll->doUnlock();
- } else {
- coll->doLock();
- }
- });
- toolbar->addAction(lockAct);
-
- return toolbar;
-}
-
-void SettingsWidgetFdoSecrets::updateExposedGroupItem(QTableWidgetItem* item, Collection* coll)
-{
- if (coll->locked().value()) {
- item->setText(tr("Unlock to show"));
- item->setIcon(filePath()->icon(QStringLiteral("apps"), QStringLiteral("object-locked"), true));
- QFont font;
- font.setItalic(true);
- item->setFont(font);
- return;
- }
-
- auto db = coll->backend()->database();
- auto group = db->rootGroup()->findGroupByUuid(FdoSecrets::settings()->exposedGroup(db));
- if (group) {
- item->setText(group->name());
- item->setIcon(group->isExpired() ? databaseIcons()->iconPixmap(DatabaseIcons::ExpiredIconIndex)
- : group->iconScaledPixmap());
- if (group->isExpired()) {
- QFont font;
- font.setStrikeOut(true);
- item->setFont(font);
- }
- } else {
- item->setText(tr("None"));
- item->setIcon(filePath()->icon(QStringLiteral("apps"), QStringLiteral("paint-none"), true));
- }
-}
-
-void SettingsWidgetFdoSecrets::removeDatabaseRow(Collection* coll)
-{
- int row = 0;
- while (row != m_ui->tableDatabases->rowCount()) {
- auto item = m_ui->tableDatabases->item(row, 0);
- const auto itemColl = item->data(Qt::UserRole).value();
- if (itemColl == coll) {
- break;
- }
- ++row;
- }
- if (row == m_ui->tableDatabases->rowCount()) {
- qWarning() << "Unknown Fdo Secret Service collection" << coll->name() << "while removing collection from table";
- return;
- }
-
- m_ui->tableDatabases->removeRow(row);
-}
-
void SettingsWidgetFdoSecrets::loadSettings()
{
m_ui->enableFdoSecretService->setChecked(FdoSecrets::settings()->isEnabled());
@@ -269,52 +301,4 @@ void SettingsWidgetFdoSecrets::saveSettings()
FdoSecrets::settings()->setNoConfirmDeleteItem(m_ui->noConfirmDeleteItem->isChecked());
}
-void SettingsWidgetFdoSecrets::showEvent(QShowEvent* event)
-{
- QWidget::showEvent(event);
-
- QMetaObject::invokeMethod(this, "updateTables", Qt::QueuedConnection, Q_ARG(bool, true));
-}
-
-void SettingsWidgetFdoSecrets::hideEvent(QHideEvent* event)
-{
- QWidget::hideEvent(event);
-
- QMetaObject::invokeMethod(this, "updateTables", Qt::QueuedConnection, Q_ARG(bool, false));
-}
-
-void SettingsWidgetFdoSecrets::updateTables(bool enabled)
-{
- if (enabled) {
- // update the table
- populateDatabases(m_ui->enableFdoSecretService->isChecked());
- populateSessions(m_ui->enableFdoSecretService->isChecked());
-
- // re-layout the widget to adjust the table cell size
- adjustSize();
-
- connect(m_ui->enableFdoSecretService, &QCheckBox::toggled, this, &SettingsWidgetFdoSecrets::populateSessions);
- connect(m_ui->enableFdoSecretService, &QCheckBox::toggled, this, &SettingsWidgetFdoSecrets::populateDatabases);
-
- auto service = m_plugin->serviceInstance();
- if (service) {
- connect(service, &Service::sessionOpened, this, &SettingsWidgetFdoSecrets::addSessionRow);
- connect(service, &Service::sessionClosed, this, &SettingsWidgetFdoSecrets::removeSessionRow);
- connect(service, &Service::collectionCreated, this, &SettingsWidgetFdoSecrets::addDatabaseRow);
- connect(service, &Service::collectionDeleted, this, &SettingsWidgetFdoSecrets::removeDatabaseRow);
- }
- } else {
- disconnect(
- m_ui->enableFdoSecretService, &QCheckBox::toggled, this, &SettingsWidgetFdoSecrets::populateSessions);
- disconnect(
- m_ui->enableFdoSecretService, &QCheckBox::toggled, this, &SettingsWidgetFdoSecrets::populateDatabases);
-
- auto service = m_plugin->serviceInstance();
- if (service) {
- disconnect(service, &Service::sessionOpened, this, &SettingsWidgetFdoSecrets::addSessionRow);
- disconnect(service, &Service::sessionClosed, this, &SettingsWidgetFdoSecrets::removeSessionRow);
- disconnect(service, &Service::collectionCreated, this, &SettingsWidgetFdoSecrets::addDatabaseRow);
- disconnect(service, &Service::collectionDeleted, this, &SettingsWidgetFdoSecrets::removeDatabaseRow);
- }
- }
-}
+#include "SettingsWidgetFdoSecrets.moc"
diff --git a/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.h b/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.h
index eac1f1e3..2bf58f82 100644
--- a/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.h
+++ b/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.h
@@ -21,7 +21,9 @@
#include
#include
-class QTableWidgetItem;
+class QAbstractItemView;
+class QItemEditorCreatorBase;
+class QItemEditorFactory;
namespace FdoSecrets
{
@@ -48,28 +50,12 @@ public slots:
void loadSettings();
void saveSettings();
-private slots:
- void populateSessions(bool enabled);
- void populateDatabases(bool enabled);
- void addSessionRow(FdoSecrets::Session* sess);
- void removeSessionRow(FdoSecrets::Session* sess);
- void addDatabaseRow(FdoSecrets::Collection* coll);
- void removeDatabaseRow(FdoSecrets::Collection* coll);
-
- void updateTables(bool enabled);
-
-protected:
- void showEvent(QShowEvent* event) override;
-
- void hideEvent(QHideEvent* event) override;
-
private:
- QWidget* createManageButtons(FdoSecrets::Collection* coll);
-
- void updateExposedGroupItem(QTableWidgetItem* item, FdoSecrets::Collection* coll);
+ void setupView(QAbstractItemView* view, int manageColumn, int editorTypeId, QItemEditorCreatorBase* creator);
private:
QScopedPointer m_ui;
+ QScopedPointer m_factory;
FdoSecretsPlugin* m_plugin;
};
diff --git a/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.ui b/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.ui
index b77e086c..660181f5 100644
--- a/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.ui
+++ b/src/fdosecrets/widgets/SettingsWidgetFdoSecrets.ui
@@ -75,7 +75,7 @@
-
-
+
Qt::NoFocus
@@ -91,21 +91,6 @@
false
-
-
- File Name
-
-
-
-
- Group
-
-
-
-
- Manage
-
-
@@ -123,7 +108,7 @@
-
-
+
Qt::NoFocus
@@ -139,16 +124,6 @@
false
-
-
- Application
-
-
-
-
- Manage
-
-