diff --git a/COPYING b/COPYING
index 797bc7b07a..6eec65ea40 100644
--- a/COPYING
+++ b/COPYING
@@ -146,6 +146,8 @@ License: MIT
Files: share/icons/application/scalable/actions/chevron-double-down.svg
share/icons/application/scalable/actions/chevron-double-right.svg
+ share/icons/application/scalable/actions/database-lock.svg
+ share/icons/application/scalable/actions/database-lock-all.svg
share/icons/application/scalable/actions/document-close.svg
share/icons/application/scalable/actions/document-edit.svg
share/icons/application/scalable/actions/document-export.svg
diff --git a/share/icons/application/scalable/actions/database-lock-all.svg b/share/icons/application/scalable/actions/database-lock-all.svg
new file mode 100644
index 0000000000..fcd67aad18
--- /dev/null
+++ b/share/icons/application/scalable/actions/database-lock-all.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/share/icons/application/scalable/actions/database-lock.svg b/share/icons/application/scalable/actions/database-lock.svg
index 1c1c86e8db..0f59c4c37b 100644
--- a/share/icons/application/scalable/actions/database-lock.svg
+++ b/share/icons/application/scalable/actions/database-lock.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/share/icons/icons.qrc b/share/icons/icons.qrc
index b35ad77be2..a0d6905052 100644
--- a/share/icons/icons.qrc
+++ b/share/icons/icons.qrc
@@ -15,6 +15,7 @@
application/scalable/actions/configure.svg
application/scalable/actions/database-change-key.svg
application/scalable/actions/database-lock.svg
+ application/scalable/actions/database-lock-all.svg
application/scalable/actions/database-merge.svg
application/scalable/actions/dialog-close.svg
application/scalable/actions/dialog-ok.svg
diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 098d5ea153..dc58e114d3 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -5142,10 +5142,6 @@ Are you sure you want to continue with this file?
-
-
-
-
@@ -5298,6 +5294,14 @@ We recommend you use the AppImage available on our downloads page.
+
+
+
+
+
+
+
+
ManageDatabase
diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp
index bcdf8f10de..74ecc0a60e 100644
--- a/src/gui/DatabaseTabWidget.cpp
+++ b/src/gui/DatabaseTabWidget.cpp
@@ -179,6 +179,33 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath,
updateLastDatabases(filePath);
}
+/**
+ * Tries to lock the database at the given index and if
+ * it succeeds proceed to switch to the first unlocked database tab
+ */
+void DatabaseTabWidget::lockAndSwitchToFirstUnlockedDatabase(int index)
+{
+ if (index == -1) {
+ index = currentIndex();
+ }
+ auto dbWidget = databaseWidgetFromIndex(index);
+ if (!dbWidget) {
+ return;
+ }
+
+ if (dbWidget->isLocked()) {
+ // Database is already locked, act like lock all databases instead
+ lockDatabases();
+ } else if (dbWidget->lock()) {
+ for (int i = 0, c = count(); i < c; ++i) {
+ if (!databaseWidgetFromIndex(i)->isLocked()) {
+ setCurrentIndex(i);
+ return;
+ }
+ }
+ }
+}
+
/**
* Add a new database tab containing the given DatabaseWidget
* @param filePath
diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h
index faad74552f..ffcd9748f0 100644
--- a/src/gui/DatabaseTabWidget.h
+++ b/src/gui/DatabaseTabWidget.h
@@ -47,6 +47,7 @@ class DatabaseTabWidget : public QTabWidget
bool hasLockableDatabases() const;
public slots:
+ void lockAndSwitchToFirstUnlockedDatabase(int index = -1);
void addDatabaseTab(const QString& filePath,
bool inBackground = false,
const QString& password = {},
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index 5aa39ad58a..4d88b6e683 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -168,6 +168,15 @@ MainWindow::MainWindow()
autoTypeButton->setPopupMode(QToolButton::MenuButtonPopup);
}
+ auto databaseLockMenu = new QMenu({}, this);
+ databaseLockMenu->addAction(m_ui->actionLockAllDatabases);
+ m_ui->actionLockDatabaseToolbar->setMenu(databaseLockMenu);
+ auto databaseLockButton =
+ qobject_cast(m_ui->toolBar->widgetForAction(m_ui->actionLockDatabaseToolbar));
+ if (databaseLockButton) {
+ databaseLockButton->setPopupMode(QToolButton::MenuButtonPopup);
+ }
+
restoreGeometry(config()->get(Config::GUI_MainWindowGeometry).toByteArray());
restoreState(config()->get(Config::GUI_MainWindowState).toByteArray());
@@ -261,7 +270,8 @@ MainWindow::MainWindow()
setShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S);
setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs, Qt::CTRL + Qt::SHIFT + Qt::Key_S);
setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W);
- m_ui->actionLockDatabases->setShortcut(Qt::CTRL + Qt::Key_L);
+ m_ui->actionLockDatabase->setShortcut(Qt::CTRL + Qt::Key_L);
+ m_ui->actionLockAllDatabases->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_L);
setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q);
setShortcut(m_ui->actionEntryNew, QKeySequence::New, Qt::CTRL + Qt::Key_N);
m_ui->actionEntryEdit->setShortcut(Qt::CTRL + Qt::Key_E);
@@ -369,7 +379,9 @@ MainWindow::MainWindow()
m_ui->actionReports->setIcon(icons()->icon("reports"));
m_ui->actionDatabaseSettings->setIcon(icons()->icon("document-edit"));
m_ui->actionDatabaseSecurity->setIcon(icons()->icon("database-change-key"));
- m_ui->actionLockDatabases->setIcon(icons()->icon("database-lock"));
+ m_ui->actionLockDatabase->setIcon(icons()->icon("database-lock"));
+ m_ui->actionLockDatabaseToolbar->setIcon(icons()->icon("database-lock"));
+ m_ui->actionLockAllDatabases->setIcon(icons()->icon("database-lock-all"));
m_ui->actionQuit->setIcon(icons()->icon("application-exit"));
m_ui->actionDatabaseMerge->setIcon(icons()->icon("database-merge"));
m_ui->menuImport->setIcon(icons()->icon("document-import"));
@@ -460,7 +472,10 @@ MainWindow::MainWindow()
connect(m_ui->actionImportOpVault, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importOpVaultDatabase()));
connect(m_ui->actionExportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToCsv()));
connect(m_ui->actionExportHtml, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToHtml()));
- connect(m_ui->actionLockDatabases, SIGNAL(triggered()), m_ui->tabWidget, SLOT(lockDatabases()));
+ connect(
+ m_ui->actionLockDatabase, SIGNAL(triggered()), m_ui->tabWidget, SLOT(lockAndSwitchToFirstUnlockedDatabase()));
+ connect(m_ui->actionLockDatabaseToolbar, SIGNAL(triggered()), m_ui->actionLockDatabase, SIGNAL(triggered()));
+ connect(m_ui->actionLockAllDatabases, SIGNAL(triggered()), m_ui->tabWidget, SLOT(lockDatabases()));
connect(m_ui->actionQuit, SIGNAL(triggered()), SLOT(appExit()));
m_actionMultiplexer.connect(m_ui->actionEntryNew, SIGNAL(triggered()), SLOT(createEntry()));
@@ -781,7 +796,9 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->menuImport->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
- m_ui->actionLockDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases());
+ m_ui->actionLockDatabase->setEnabled(m_ui->tabWidget->hasLockableDatabases());
+ m_ui->actionLockDatabaseToolbar->setEnabled(m_ui->tabWidget->hasLockableDatabases());
+ m_ui->actionLockAllDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases());
if (inDatabaseTabWidget && m_ui->tabWidget->currentIndex() != -1) {
DatabaseWidget* dbWidget = m_ui->tabWidget->currentDatabaseWidget();
@@ -924,6 +941,9 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionExportCsv->setEnabled(false);
m_ui->actionExportHtml->setEnabled(false);
m_ui->actionDatabaseMerge->setEnabled(false);
+ // Only disable the action in the database menu so that the
+ // menu remains active in the toolbar, if necessary
+ m_ui->actionLockDatabase->setEnabled(false);
m_searchWidgetAction->setEnabled(false);
break;
@@ -1392,7 +1412,7 @@ void MainWindow::updateTrayIcon()
menu->addAction(actionToggle);
actionToggle->setIcon(icons()->icon("keepassxc-monochrome-dark"));
- menu->addAction(m_ui->actionLockDatabases);
+ menu->addAction(m_ui->actionLockAllDatabases);
#ifdef Q_OS_MACOS
auto actionQuit = new QAction(tr("Quit KeePassXC"), menu);
diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui
index f83e8077d3..c877313b92 100644
--- a/src/gui/MainWindow.ui
+++ b/src/gui/MainWindow.ui
@@ -216,7 +216,7 @@
0
0
800
- 21
+ 22
@@ -254,6 +254,9 @@
+
+
+
@@ -355,7 +358,6 @@
&Tools
-
@@ -409,6 +411,7 @@
+
@@ -419,8 +422,6 @@
-
-
@@ -773,12 +774,20 @@
Open &URL
-
+
+
+ false
+
+
+ &Lock Database
+
+
+
false
- &Lock Databases
+ Lock &All Databases
@@ -1084,6 +1093,14 @@
Ctrl+R
+
+
+ false
+
+
+ &Lock Database
+
+
diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp
index 7c672c6d3a..34b047e9ba 100644
--- a/tests/gui/TestGui.cpp
+++ b/tests/gui/TestGui.cpp
@@ -1384,7 +1384,7 @@ void TestGui::testDatabaseLocking()
QString origDbName = m_tabWidget->tabText(0);
MessageBox::setNextAnswer(MessageBox::Cancel);
- triggerAction("actionLockDatabases");
+ triggerAction("actionLockAllDatabases");
QCOMPARE(m_tabWidget->tabText(0), origDbName + " [Locked]");