Overhaul action states and add icons to toolbar

* Fixes #10981
This commit is contained in:
Jonathan White 2023-10-28 14:13:44 -04:00
parent c8fc25ea5c
commit e591dbcf10
No known key found for this signature in database
GPG Key ID: 440FC65F2E0C6E01
21 changed files with 428 additions and 438 deletions

View File

@ -155,6 +155,7 @@ Files: share/icons/application/scalable/actions/application-exit.svg
share/icons/application/scalable/actions/database-lock-all.svg
share/icons/application/scalable/actions/database-merge.svg
share/icons/application/scalable/actions/database-search.svg
share/icons/application/scalable/actions/database-settings.svg
share/icons/application/scalable/actions/dialog-close.svg
share/icons/application/scalable/actions/dialog-ok.svg
share/icons/application/scalable/actions/document-close.svg
@ -243,9 +244,9 @@ Files: share/icons/application/scalable/actions/application-exit.svg
share/icons/application/scalable/actions/lock-open-alert.svg
share/icons/application/scalable/actions/lock-open.svg
share/icons/application/scalable/actions/lock.svg
Copyright: 2019 Austin Andrews <http://templarian.com/>
License: SIL OPEN FONT LICENSE Version 1.1
Comment: Taken from Material Design icon set (https://github.com/templarian/MaterialDesign/)
Copyright: 2023 Pictogrammers <https://pictogrammers.com/docs/general/about/>
License: Apache-2.0
Comment: Some icons are modified to fit KeePassXC design (https://pictogrammers.com/library/mdi/)
Files: src/streams/qtiocompressor.*
src/streams/QtIOCompressor

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 14C9.58 14 7.3 13.4 6 12.45V9.64C7.47 10.47 9.61 11 12 11S16.53 10.47 18 9.64V12.08C18.33 12.03 18.66 12 19 12C19.34 12 19.67 12.03 20 12.08V7C20 4.79 16.42 3 12 3S4 4.79 4 7V17C4 19.21 7.59 21 12 21C12.1 21 12.2 21 12.29 21C12.11 20.36 12 19.69 12 19C8.13 19 6 17.5 6 17V14.77C7.61 15.55 9.72 16 12 16C12.24 16 12.47 16 12.7 15.97C13.1 15.14 13.65 14.41 14.32 13.81C13.58 13.93 12.8 14 12 14M12 5C15.87 5 18 6.5 18 7S15.87 9 12 9 6 7.5 6 7 8.13 5 12 5M22.7 19.6V18.6L23.8 17.8C23.9 17.7 24 17.6 23.9 17.5L22.9 15.8C22.9 15.7 22.7 15.7 22.6 15.7L21.4 16.2C21.1 16 20.8 15.8 20.5 15.7L20.3 14.4C20.3 14.3 20.2 14.2 20.1 14.2H18.1C17.9 14.2 17.8 14.3 17.8 14.4L17.6 15.7C17.3 15.9 17.1 16 16.8 16.2L15.6 15.7C15.5 15.7 15.4 15.7 15.3 15.8L14.3 17.5C14.3 17.6 14.3 17.7 14.4 17.8L15.5 18.6V19.6L14.4 20.4C14.3 20.5 14.2 20.6 14.3 20.7L15.3 22.4C15.4 22.5 15.5 22.5 15.6 22.5L16.8 22C17 22.2 17.3 22.4 17.6 22.5L17.8 23.8C17.9 23.9 18 24 18.1 24H20.1C20.2 24 20.3 23.9 20.3 23.8L20.5 22.5C20.8 22.3 21 22.2 21.3 22L22.5 22.4C22.6 22.4 22.7 22.4 22.8 22.3L23.8 20.6C23.9 20.5 23.9 20.4 23.8 20.4L22.7 19.6M19 20.5C18.2 20.5 17.5 19.8 17.5 19S18.2 17.5 19 17.5 20.5 18.2 20.5 19 19.8 20.5 19 20.5Z" /></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="mdi-close-circle-outline" width="24" height="24" viewBox="0 0 24 24"><path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M16,10V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V10H16M13.5,6L14.5,7H17V9H7V7H9.5L10.5,6H13.5Z" /></svg>

Before

Width:  |  Height:  |  Size: 617 B

After

Width:  |  Height:  |  Size: 309 B

View File

@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="mdi-lightbulb-on-outline" width="24" height="24" viewBox="0 0 24 24"><path d="M20,11H23V13H20V11M1,11H4V13H1V11M13,1V4H11V1H13M4.92,3.5L7.05,5.64L5.63,7.05L3.5,4.93L4.92,3.5M16.95,5.63L19.07,3.5L20.5,4.93L18.37,7.05L16.95,5.63M12,6A6,6 0 0,1 18,12C18,14.22 16.79,16.16 15,17.2V19A1,1 0 0,1 14,20H10A1,1 0 0,1 9,19V17.2C7.21,16.16 6,14.22 6,12A6,6 0 0,1 12,6M14,21V22A1,1 0 0,1 13,23H11A1,1 0 0,1 10,22V21H14M11,18H13V15.87C14.73,15.43 16,13.86 16,12A4,4 0 0,0 12,8A4,4 0 0,0 8,12C8,13.86 9.27,15.43 11,15.87V18Z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 16V4H8V16M22 16C22 17.1 21.1 18 20 18H8C6.9 18 6 17.1 6 16V4C6 2.9 6.9 2 8 2H20C21.1 2 22 2.9 22 4M16 20V22H4C2.9 22 2 21.1 2 20V7H4V20M16 11H18V14H16M13 6H15V14H13M10 8H12V14H10Z" /></svg>

Before

Width:  |  Height:  |  Size: 758 B

After

Width:  |  Height:  |  Size: 262 B

View File

@ -20,6 +20,7 @@
<file>application/scalable/actions/database-lock-all.svg</file>
<file>application/scalable/actions/database-merge.svg</file>
<file>application/scalable/actions/database-search.svg</file>
<file>application/scalable/actions/database-settings.svg</file>
<file>application/scalable/actions/dialog-close.svg</file>
<file>application/scalable/actions/dialog-ok.svg</file>
<file>application/scalable/actions/document-close.svg</file>

View File

@ -1689,6 +1689,10 @@ Are you sure you want to continue with this file?.</source>
<source>Remote Sync</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Database Settings: %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DatabaseSettingsWidgetBrowser</name>

View File

@ -543,7 +543,7 @@ namespace FdoSecrets
}
// switch selected to current
m_databases->setCurrentWidget(dbWidget);
m_databases->showDatabaseSettings();
m_databases->showDatabaseSettings(true);
// open settings (switch from app settings to m_dbTabs)
m_plugin->emitRequestSwitchToDatabases();

View File

@ -537,21 +537,29 @@ bool DatabaseTabWidget::warnOnExport()
return ans == MessageBox::Yes;
}
void DatabaseTabWidget::showDatabaseReports(bool state)
{
if (state) {
currentDatabaseWidget()->switchToDatabaseReports();
} else {
currentDatabaseWidget()->switchToMainView();
}
}
void DatabaseTabWidget::showDatabaseSettings(bool state)
{
if (state) {
currentDatabaseWidget()->switchToDatabaseSettings();
} else {
currentDatabaseWidget()->switchToMainView();
}
}
void DatabaseTabWidget::showDatabaseSecurity()
{
currentDatabaseWidget()->switchToDatabaseSecurity();
}
void DatabaseTabWidget::showDatabaseReports()
{
currentDatabaseWidget()->switchToDatabaseReports();
}
void DatabaseTabWidget::showDatabaseSettings()
{
currentDatabaseWidget()->switchToDatabaseSettings();
}
#ifdef WITH_XC_BROWSER_PASSKEYS
void DatabaseTabWidget::showPasskeys()
{

View File

@ -82,9 +82,9 @@ public slots:
void unlockAnyDatabaseInDialog(DatabaseOpenDialog::Intent intent);
void relockPendingDatabase();
void showDatabaseReports(bool state);
void showDatabaseSettings(bool state);
void showDatabaseSecurity();
void showDatabaseReports();
void showDatabaseSettings();
#ifdef WITH_XC_BROWSER_PASSKEYS
void showPasskeys();
void importPasskey();

View File

@ -265,15 +265,26 @@ QSharedPointer<Database> DatabaseWidget::database() const
DatabaseWidget::Mode DatabaseWidget::currentMode() const
{
if (currentWidget() == nullptr) {
return Mode::None;
} else if (currentWidget() == m_mainWidget) {
return Mode::ViewMode;
} else if (currentWidget() == m_databaseOpenWidget) {
return Mode::LockedMode;
auto mode = Mode::None;
auto widget = currentWidget();
if (widget == m_mainWidget) {
mode = Mode::ViewMode;
} else if (widget == m_databaseOpenWidget) {
mode = Mode::LockedMode;
} else if (widget == m_reportsDialog) {
mode = Mode::ReportsMode;
} else if (widget == m_databaseSettingDialog) {
mode = Mode::DatabaseSettingsMode;
} else if (widget == m_editEntryWidget) {
mode = Mode::EditEntryMode;
} else if (widget == m_editGroupWidget) {
mode = Mode::EditGroupMode;
} else {
return Mode::EditMode;
// We are missing a condition if we reach here
Q_ASSERT(false);
}
return mode;
}
bool DatabaseWidget::isLocked() const
@ -1014,7 +1025,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
}
}
Entry* DatabaseWidget::currentSelectedEntry()
Entry* DatabaseWidget::currentSelectedEntry() const
{
if (currentWidget() == m_editEntryWidget) {
return m_editEntryWidget->currentEntry();
@ -1516,14 +1527,18 @@ void DatabaseWidget::entryActivationSignalReceived(Entry* entry, EntryModel::Mod
void DatabaseWidget::switchToDatabaseReports()
{
m_reportsDialog->load(m_db);
setCurrentWidget(m_reportsDialog);
if (currentMode() != Mode::ReportsMode) {
m_reportsDialog->load(m_db);
setCurrentWidget(m_reportsDialog);
}
}
void DatabaseWidget::switchToDatabaseSettings()
{
m_databaseSettingDialog->load(m_db);
setCurrentWidget(m_databaseSettingDialog);
if (currentMode() != Mode::DatabaseSettingsMode) {
m_databaseSettingDialog->load(m_db);
setCurrentWidget(m_databaseSettingDialog);
}
}
void DatabaseWidget::switchToOpenDatabase()
@ -1865,16 +1880,13 @@ void DatabaseWidget::onEntryChanged(Entry* entry)
bool DatabaseWidget::canCloneCurrentGroup() const
{
bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup();
// bool isRecycleBin = isRecycleBinSelected();
return !isRootGroup;
auto currentGroup = m_groupView->currentGroup();
return currentGroup != m_db->rootGroup() && currentGroup != m_db->metadata()->recycleBin();
}
bool DatabaseWidget::canDeleteCurrentGroup() const
{
bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup();
return !isRootGroup;
return currentGroup() != m_db->rootGroup();
}
Group* DatabaseWidget::currentGroup() const
@ -2483,7 +2495,9 @@ void DatabaseWidget::hideMessage()
bool DatabaseWidget::isRecycleBinSelected() const
{
return m_groupView->currentGroup() && m_groupView->currentGroup() == m_db->metadata()->recycleBin();
auto group = currentGroup();
auto entry = currentSelectedEntry();
return (group && group->isRecycled()) || (entry && entry->isRecycled());
}
void DatabaseWidget::emptyRecycleBin()

View File

@ -64,8 +64,11 @@ public:
{
None,
ViewMode,
EditMode,
LockedMode
EditEntryMode,
EditGroupMode,
LockedMode,
ReportsMode,
DatabaseSettingsMode
};
explicit DatabaseWidget(QSharedPointer<Database> db, QWidget* parent = nullptr);
@ -106,7 +109,7 @@ public:
QStringList customEntryAttributes() const;
bool isEditWidgetModified() const;
void clearAllWidgets();
Entry* currentSelectedEntry();
Entry* currentSelectedEntry() const;
bool currentEntryHasTitle();
bool currentEntryHasUsername();
bool currentEntryHasPassword();

View File

@ -31,6 +31,7 @@ EditWidget::EditWidget(QWidget* parent)
setModified(false);
m_ui->messageWidget->setHidden(true);
m_ui->headerLabel->setHidden(true);
QFont headerLabelFont = m_ui->headerLabel->font();
headerLabelFont.setBold(true);
@ -118,6 +119,7 @@ void EditWidget::setCurrentPage(int index)
void EditWidget::setHeadline(const QString& text)
{
m_ui->headerLabel->setHidden(text.isEmpty());
m_ui->headerLabel->setText(text);
}

View File

@ -127,6 +127,8 @@ MainWindow::MainWindow()
m_entryContextMenu = new QMenu(this);
m_entryContextMenu->setSeparatorsCollapsible(true);
m_entryContextMenu->addAction(m_ui->actionEntryRestore);
m_entryContextMenu->addSeparator();
m_entryContextMenu->addAction(m_ui->actionEntryCopyUsername);
m_entryContextMenu->addAction(m_ui->actionEntryCopyPassword);
m_entryContextMenu->addAction(m_ui->actionEntryCopyURL);
@ -154,8 +156,6 @@ MainWindow::MainWindow()
m_entryContextMenu->addSeparator();
m_entryContextMenu->addAction(m_ui->actionEntryAddToAgent);
m_entryContextMenu->addAction(m_ui->actionEntryRemoveFromAgent);
m_entryContextMenu->addSeparator();
m_entryContextMenu->addAction(m_ui->actionEntryRestore);
m_entryNewContextMenu = new QMenu(this);
m_entryNewContextMenu->addAction(m_ui->actionEntryNew);
@ -346,8 +346,10 @@ MainWindow::MainWindow()
m_ui->actionDatabaseSaveBackup->setIcon(icons()->icon("document-save-copy"));
m_ui->actionDatabaseClose->setIcon(icons()->icon("document-close"));
m_ui->actionReports->setIcon(icons()->icon("reports"));
m_ui->actionDatabaseSettings->setIcon(icons()->icon("document-edit"));
m_ui->actionDatabaseSettings->setIcon(icons()->icon("database-settings"));
m_ui->actionDatabaseSecurity->setIcon(icons()->icon("database-change-key"));
m_ui->actionPasskeys->setIcon(icons()->icon("passkey"));
m_ui->actionImportPasskey->setIcon(icons()->icon("document-import"));
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"));
@ -357,6 +359,12 @@ MainWindow::MainWindow()
m_ui->actionImport->setIcon(icons()->icon("document-import"));
m_ui->menuExport->setIcon(icons()->icon("document-export"));
#ifndef WITH_XC_BROWSER_PASSKEYS
m_ui->actionPasskeys->setVisible(false);
m_ui->actionImportPasskey->setVisible(false);
m_ui->actionEntryImportPasskey->setVisible(false);
#endif
m_ui->actionEntryNew->setIcon(icons()->icon("entry-new"));
m_ui->actionEntryClone->setIcon(icons()->icon("entry-clone"));
m_ui->actionEntryEdit->setIcon(icons()->icon("entry-edit"));
@ -381,6 +389,7 @@ MainWindow::MainWindow()
m_ui->actionEntryCopyPasswordTotp->setIcon(icons()->icon("totp-copy-password"));
m_ui->actionEntryTotpQRCode->setIcon(icons()->icon("qrcode"));
m_ui->actionEntrySetupTotp->setIcon(icons()->icon("totp-edit"));
m_ui->actionEntryImportPasskey->setIcon(icons()->icon("document-import"));
m_ui->actionEntryAddToAgent->setIcon(icons()->icon("utilities-terminal"));
m_ui->actionEntryRemoveFromAgent->setIcon(icons()->icon("utilities-terminal"));
m_ui->menuTags->setIcon(icons()->icon("tag-multiple"));
@ -415,11 +424,10 @@ MainWindow::MainWindow()
m_ui->actionEntryRemovePasskey->setIcon(icons()->icon("document-close"));
#endif
m_actionMultiplexer.connect(
SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(setMenuActionState(DatabaseWidget::Mode)));
m_actionMultiplexer.connect(SIGNAL(groupChanged()), this, SLOT(setMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(entrySelectionChanged()), this, SLOT(setMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(databaseNonDataChanged()), this, SLOT(setMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(updateMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(groupChanged()), this, SLOT(updateMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(entrySelectionChanged()), this, SLOT(updateMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(databaseNonDataChanged()), this, SLOT(updateMenuActionState()));
m_actionMultiplexer.connect(SIGNAL(groupContextMenuRequested(QPoint)), this, SLOT(showGroupContextMenu(QPoint)));
m_actionMultiplexer.connect(SIGNAL(entryContextMenuRequested(QPoint)), this, SLOT(showEntryContextMenu(QPoint)));
m_actionMultiplexer.connect(SIGNAL(groupChanged()), this, SLOT(updateEntryCountLabel()));
@ -438,11 +446,11 @@ MainWindow::MainWindow()
connect(m_ui->tabWidget, SIGNAL(tabNameChanged()), SLOT(updateWindowTitle()));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(updateWindowTitle()));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(databaseTabChanged(int)));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(setMenuActionState()));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(updateMenuActionState()));
connect(m_ui->tabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), SLOT(databaseStatusChanged(DatabaseWidget*)));
connect(m_ui->tabWidget, SIGNAL(databaseUnlocked(DatabaseWidget*)), SLOT(databaseStatusChanged(DatabaseWidget*)));
connect(m_ui->tabWidget, SIGNAL(tabVisibilityChanged(bool)), SLOT(updateToolbarSeparatorVisibility()));
connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(setMenuActionState()));
connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(updateMenuActionState()));
connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(updateWindowTitle()));
connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(updateToolbarSeparatorVisibility()));
connect(m_ui->settingsWidget, SIGNAL(accepted()), SLOT(applySettingsChanges()));
@ -457,9 +465,9 @@ MainWindow::MainWindow()
connect(m_ui->actionDatabaseSaveBackup, SIGNAL(triggered()), m_ui->tabWidget, SLOT(saveDatabaseBackup()));
connect(m_ui->actionDatabaseClose, SIGNAL(triggered()), m_ui->tabWidget, SLOT(closeCurrentDatabaseTab()));
connect(m_ui->actionDatabaseMerge, SIGNAL(triggered()), m_ui->tabWidget, SLOT(mergeDatabase()));
connect(m_ui->actionDatabaseSettings, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(showDatabaseSettings(bool)));
connect(m_ui->actionDatabaseSecurity, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showDatabaseSecurity()));
connect(m_ui->actionReports, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showDatabaseReports()));
connect(m_ui->actionDatabaseSettings, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showDatabaseSettings()));
connect(m_ui->actionReports, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(showDatabaseReports(bool)));
#ifdef WITH_XC_BROWSER_PASSKEYS
connect(m_ui->actionPasskeys, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showPasskeys()));
connect(m_ui->actionImportPasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importPasskey()));
@ -668,7 +676,7 @@ MainWindow::MainWindow()
statusBar()->addPermanentWidget(m_statusBarLabel);
restoreConfigState();
setMenuActionState();
updateMenuActionState();
}
MainWindow::~MainWindow()
@ -844,251 +852,149 @@ void MainWindow::openDatabase(const QString& filePath, const QString& password,
m_ui->tabWidget->addDatabaseTab(filePath, false, password, keyfile);
}
void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
void MainWindow::updateMenuActionState()
{
// MainWindow State
int currentIndex = m_ui->stackedWidget->currentIndex();
bool hasLockableDatabase = m_ui->tabWidget->hasLockableDatabases();
bool inAppSettings = (currentIndex == SettingsScreen);
bool inPasswordGenerator = (currentIndex == PasswordGeneratorScreen);
bool inDatabaseTabWidget = (currentIndex == DatabaseTabScreen);
bool inWelcomeWidget = (currentIndex == WelcomeScreen);
bool inDatabaseTabWidgetOrWelcomeWidget = inDatabaseTabWidget || inWelcomeWidget;
auto dbWidget = (currentIndex == DatabaseTabScreen ? m_ui->tabWidget->currentDatabaseWidget() : nullptr);
auto dbMode = (dbWidget ? dbWidget->currentMode() : DatabaseWidget::Mode::None);
m_ui->actionDatabaseClose->setEnabled(true);
m_ui->actionDatabaseMerge->setEnabled(inDatabaseTabWidget);
m_ui->menuRemoteSync->setEnabled(inDatabaseTabWidget);
m_ui->actionDatabaseNew->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionImport->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionLockDatabase->setEnabled(m_ui->tabWidget->hasLockableDatabases());
m_ui->actionLockDatabaseToolbar->setEnabled(m_ui->tabWidget->hasLockableDatabases());
m_ui->actionLockAllDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases());
// Database State
bool databaseUnlocked = (dbWidget && !dbWidget->isLocked());
bool inDatabase = (dbMode == DatabaseWidget::Mode::ViewMode);
bool inDatabaseSettings = (dbMode == DatabaseWidget::Mode::DatabaseSettingsMode);
bool inReports = (dbMode == DatabaseWidget::Mode::ReportsMode);
bool editingEntry = (dbMode == DatabaseWidget::Mode::EditEntryMode);
if (inDatabaseTabWidget && m_ui->tabWidget->currentIndex() != -1) {
DatabaseWidget* dbWidget = m_ui->tabWidget->currentDatabaseWidget();
Q_ASSERT(dbWidget);
// Synchronize toggle buttons
m_ui->actionDatabaseSettings->blockSignals(true);
m_ui->actionPasswordGenerator->blockSignals(true);
m_ui->actionReports->blockSignals(true);
m_ui->actionSettings->blockSignals(true);
if (mode == DatabaseWidget::Mode::None) {
mode = dbWidget->currentMode();
}
m_ui->actionDatabaseSettings->setChecked(inDatabaseSettings);
m_ui->actionPasswordGenerator->setChecked(inPasswordGenerator);
m_ui->actionReports->setChecked(inReports);
m_ui->actionSettings->setChecked(inAppSettings);
switch (mode) {
case DatabaseWidget::Mode::ViewMode: {
bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1;
bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0;
bool groupSelected = dbWidget->isGroupSelected();
bool currentGroupHasChildren = dbWidget->currentGroup()->hasChildren();
bool currentGroupHasEntries = !dbWidget->currentGroup()->entries().isEmpty();
bool recycleBinSelected = dbWidget->isRecycleBinSelected();
bool sorted = dbWidget->isSorted();
int entryIndex = dbWidget->currentEntryIndex();
int numEntries = dbWidget->currentGroup()->entries().size();
m_ui->actionDatabaseSettings->blockSignals(false);
m_ui->actionPasswordGenerator->blockSignals(false);
m_ui->actionReports->blockSignals(false);
m_ui->actionSettings->blockSignals(false);
m_ui->actionEntryNew->setEnabled(true);
m_ui->actionEntryClone->setEnabled(singleEntrySelected);
m_ui->actionEntryEdit->setEnabled(singleEntrySelected);
m_ui->actionEntryDelete->setEnabled(entriesSelected);
m_ui->actionEntryRestore->setVisible(entriesSelected && recycleBinSelected);
m_ui->actionEntryRestore->setEnabled(entriesSelected && recycleBinSelected);
m_ui->actionEntryRestore->setText(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries()));
m_ui->actionEntryRestore->setToolTip(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries()));
m_ui->actionEntryMoveUp->setVisible(!sorted);
m_ui->actionEntryMoveDown->setVisible(!sorted);
m_ui->actionEntryMoveUp->setEnabled(singleEntrySelected && !sorted && entryIndex > 0);
m_ui->actionEntryMoveDown->setEnabled(singleEntrySelected && !sorted && entryIndex >= 0
&& entryIndex < numEntries - 1);
m_ui->actionEntryCopyTitle->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTitle());
m_ui->actionEntryCopyUsername->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername());
// NOTE: Copy password is enabled even if the selected entry's password is blank to prevent Ctrl+C
// from copying information from the currently selected cell in the entry view table.
m_ui->actionEntryCopyPassword->setEnabled(singleEntrySelected);
m_ui->actionEntryCopyURL->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl());
m_ui->actionEntryCopyNotes->setEnabled(singleEntrySelected && dbWidget->currentEntryHasNotes());
m_ui->menuEntryCopyAttribute->setEnabled(singleEntrySelected);
m_ui->menuEntryTotp->setEnabled(singleEntrySelected);
m_ui->menuTags->setEnabled(entriesSelected);
m_ui->actionEntryAutoType->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled());
m_ui->actionEntryAutoType->menu()->setEnabled(singleEntrySelected
&& dbWidget->currentEntryHasAutoTypeEnabled());
m_ui->actionEntryAutoTypeSequence->setText(
singleEntrySelected ? dbWidget->currentSelectedEntry()->effectiveAutoTypeSequence()
: Group::RootAutoTypeSequence);
m_ui->actionEntryAutoTypeSequence->setEnabled(singleEntrySelected);
m_ui->actionEntryAutoTypeUsername->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername());
m_ui->actionEntryAutoTypeUsernameEnter->setEnabled(singleEntrySelected
&& dbWidget->currentEntryHasUsername());
m_ui->actionEntryAutoTypePassword->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword());
m_ui->actionEntryAutoTypePasswordEnter->setEnabled(singleEntrySelected
&& dbWidget->currentEntryHasPassword());
m_ui->actionEntryAutoTypeTOTP->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryAutoTypeTOTP->setVisible(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryOpenUrl->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl());
m_ui->actionEntryTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryCopyTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryCopyPasswordTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntrySetupTotp->setEnabled(singleEntrySelected);
m_ui->actionEntryTotpQRCode->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryDownloadIcon->setEnabled((entriesSelected && !singleEntrySelected)
|| (singleEntrySelected && dbWidget->currentEntryHasUrl()));
m_ui->actionGroupNew->setEnabled(groupSelected);
m_ui->actionGroupEdit->setEnabled(groupSelected);
m_ui->actionGroupClone->setEnabled(groupSelected && dbWidget->canCloneCurrentGroup());
m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup());
m_ui->actionGroupSortAsc->setEnabled(groupSelected && currentGroupHasChildren);
m_ui->actionGroupSortDesc->setEnabled(groupSelected && currentGroupHasChildren);
m_ui->actionGroupEmptyRecycleBin->setVisible(recycleBinSelected);
m_ui->actionGroupEmptyRecycleBin->setEnabled(recycleBinSelected);
#ifdef WITH_XC_NETWORKING
m_ui->actionGroupDownloadFavicons->setVisible(!recycleBinSelected);
#endif
m_ui->actionGroupDownloadFavicons->setEnabled(groupSelected && currentGroupHasEntries
&& !recycleBinSelected);
m_ui->actionDatabaseSecurity->setEnabled(true);
m_ui->actionReports->setEnabled(true);
m_ui->actionDatabaseSettings->setEnabled(true);
m_ui->actionDatabaseSave->setEnabled(m_ui->tabWidget->canSave());
m_ui->actionDatabaseSaveAs->setEnabled(true);
m_ui->actionDatabaseSaveBackup->setEnabled(true);
m_ui->menuExport->setEnabled(true);
m_ui->actionExportCsv->setEnabled(true);
m_ui->actionExportHtml->setEnabled(true);
m_ui->actionExportXML->setEnabled(true);
m_ui->actionDatabaseMerge->setEnabled(m_ui->tabWidget->currentIndex() != -1);
// Entry State
bool singleEntrySelected = (inDatabase && dbWidget->numberOfSelectedEntries() == 1);
bool singleEntryOrEditing = (singleEntrySelected || editingEntry);
bool multiEntrySelected = (inDatabase && dbWidget->numberOfSelectedEntries() > 0);
// Group State
bool groupSelected = (inDatabase && dbWidget->isGroupSelected());
bool groupHasChildren = (groupSelected && dbWidget->currentGroup()->hasChildren());
bool groupHasEntries = (groupSelected && !dbWidget->currentGroup()->entries().isEmpty());
bool inRecycleBin = (inDatabase && dbWidget->isRecycleBinSelected());
bool entryViewSorted = (inDatabase && dbWidget->isSorted());
bool entryViewAtTop = (inDatabase && dbWidget->currentEntryIndex() == 0);
bool entryViewAtBottom =
(groupSelected && dbWidget->currentEntryIndex() == dbWidget->currentGroup()->entries().size() - 1);
m_ui->actionEntryNew->setEnabled(inDatabase && !inRecycleBin);
m_ui->actionEntryClone->setEnabled(singleEntrySelected && !inRecycleBin);
m_ui->actionEntryEdit->setEnabled(singleEntrySelected);
m_ui->actionEntryDelete->setEnabled(multiEntrySelected);
m_ui->actionEntryRestore->setVisible(multiEntrySelected && inRecycleBin);
m_ui->actionEntryRestore->setEnabled(multiEntrySelected && inRecycleBin);
if (dbWidget) {
m_ui->actionEntryRestore->setText(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries()));
m_ui->actionEntryRestore->setToolTip(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries()));
}
m_ui->actionEntryMoveUp->setVisible(inDatabase && !entryViewSorted);
m_ui->actionEntryMoveDown->setVisible(inDatabase && !entryViewSorted);
m_ui->actionEntryMoveUp->setEnabled(singleEntrySelected && !entryViewSorted && !entryViewAtTop);
m_ui->actionEntryMoveDown->setEnabled(singleEntrySelected && !entryViewSorted && !entryViewAtBottom);
m_ui->actionEntryCopyTitle->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasTitle());
m_ui->actionEntryCopyUsername->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasUsername());
// NOTE: Copy password is enabled even if the selected entry's password is blank to prevent Ctrl+C
// from copying information from the currently selected cell in the entry view table.
m_ui->actionEntryCopyPassword->setEnabled(singleEntryOrEditing);
m_ui->actionEntryCopyURL->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasUrl());
m_ui->actionEntryCopyNotes->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasNotes());
m_ui->menuEntryCopyAttribute->setEnabled(singleEntryOrEditing);
m_ui->menuEntryTotp->setEnabled(singleEntrySelected);
m_ui->menuTags->setEnabled(multiEntrySelected);
m_ui->actionEntryAutoType->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled());
m_ui->actionEntryAutoType->menu()->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled());
m_ui->actionEntryAutoTypeSequence->setText(singleEntrySelected
? dbWidget->currentSelectedEntry()->effectiveAutoTypeSequence()
: Group::RootAutoTypeSequence);
m_ui->actionEntryAutoTypeSequence->setEnabled(singleEntrySelected);
m_ui->actionEntryAutoTypeUsername->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername());
m_ui->actionEntryAutoTypeUsernameEnter->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername());
m_ui->actionEntryAutoTypePassword->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword());
m_ui->actionEntryAutoTypePasswordEnter->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword());
m_ui->actionEntryAutoTypeTOTP->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryAutoTypeTOTP->setVisible(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryOpenUrl->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasUrl());
m_ui->actionEntryTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryCopyTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryCopyPasswordTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntrySetupTotp->setEnabled(singleEntrySelected);
m_ui->actionEntryTotpQRCode->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
m_ui->actionEntryDownloadIcon->setEnabled((multiEntrySelected && !singleEntrySelected)
|| (singleEntrySelected && dbWidget->currentEntryHasUrl()));
#ifdef WITH_XC_BROWSER_PASSKEYS
bool singleEntryHasPasskey = singleEntrySelected && dbWidget->currentEntryHasPasskey();
m_ui->actionPasskeys->setEnabled(true);
m_ui->actionImportPasskey->setEnabled(true);
m_ui->actionEntryImportPasskey->setEnabled(singleEntrySelected);
m_ui->actionEntryRemovePasskey->setEnabled(singleEntryHasPasskey);
m_ui->actionEntryImportPasskey->setVisible(singleEntrySelected);
m_ui->actionEntryImportPasskey->setEnabled(singleEntrySelected);
m_ui->actionEntryRemovePasskey->setVisible(singleEntrySelected && dbWidget->currentEntryHasPasskey());
m_ui->actionEntryRemovePasskey->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPasskey());
#endif
m_ui->menuRemoteSync->setEnabled(true);
#ifdef WITH_XC_SSHAGENT
bool singleEntryHasSshKey =
singleEntrySelected && sshAgent()->isEnabled() && dbWidget->currentEntryHasSshKey();
m_ui->actionEntryAddToAgent->setVisible(singleEntryHasSshKey);
m_ui->actionEntryAddToAgent->setEnabled(singleEntryHasSshKey);
m_ui->actionEntryRemoveFromAgent->setVisible(singleEntryHasSshKey);
m_ui->actionEntryRemoveFromAgent->setEnabled(singleEntryHasSshKey);
bool hasSSHKey = singleEntrySelected && sshAgent()->isEnabled() && dbWidget->currentEntryHasSshKey();
m_ui->actionEntryAddToAgent->setVisible(hasSSHKey);
m_ui->actionEntryAddToAgent->setEnabled(hasSSHKey);
m_ui->actionEntryRemoveFromAgent->setVisible(hasSSHKey);
m_ui->actionEntryRemoveFromAgent->setEnabled(hasSSHKey);
#endif
m_searchWidgetAction->setEnabled(true);
break;
}
case DatabaseWidget::Mode::EditMode:
case DatabaseWidget::Mode::LockedMode: {
// Enable select actions when editing an entry
bool editEntryActive = dbWidget->isEntryEditActive();
const QList<QAction*> editEntryActionsMask{m_ui->actionEntryCopyUsername,
m_ui->actionEntryCopyPassword,
m_ui->actionEntryCopyURL,
m_ui->actionEntryOpenUrl,
m_ui->actionEntryAutoType,
m_ui->actionEntryDownloadIcon,
m_ui->actionEntryCopyNotes,
m_ui->actionEntryCopyTitle,
m_ui->menuEntryCopyAttribute->menuAction(),
m_ui->menuEntryTotp->menuAction(),
m_ui->actionEntrySetupTotp};
auto entryActions = m_ui->menuEntries->actions();
entryActions << m_ui->menuEntryCopyAttribute->actions();
entryActions << m_ui->menuEntryTotp->actions();
for (auto action : entryActions) {
bool enabled = editEntryActive && editEntryActionsMask.contains(action);
if (action->menu()) {
action->menu()->setEnabled(enabled);
}
action->setEnabled(enabled);
}
const auto groupActions = m_ui->menuGroups->actions();
for (auto action : groupActions) {
action->setEnabled(false);
}
m_ui->actionDatabaseSecurity->setEnabled(false);
m_ui->actionReports->setEnabled(false);
m_ui->actionDatabaseSettings->setEnabled(false);
m_ui->actionDatabaseSave->setEnabled(false);
m_ui->actionDatabaseSaveAs->setEnabled(false);
m_ui->actionDatabaseSaveBackup->setEnabled(false);
m_ui->menuExport->setEnabled(false);
m_ui->actionExportCsv->setEnabled(false);
m_ui->actionExportHtml->setEnabled(false);
m_ui->actionDatabaseMerge->setEnabled(false);
m_ui->menuRemoteSync->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);
// Never show in these modes
m_ui->actionEntryMoveUp->setVisible(false);
m_ui->actionEntryMoveDown->setVisible(false);
m_ui->actionEntryRestore->setVisible(false);
m_ui->actionEntryAddToAgent->setVisible(false);
m_ui->actionEntryRemoveFromAgent->setVisible(false);
m_ui->actionGroupEmptyRecycleBin->setVisible(false);
m_ui->actionGroupNew->setEnabled(groupSelected && !inRecycleBin);
m_ui->actionGroupEdit->setEnabled(groupSelected);
m_ui->actionGroupClone->setEnabled(groupSelected && dbWidget->canCloneCurrentGroup());
m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup());
m_ui->actionGroupSortAsc->setVisible(groupHasChildren);
m_ui->actionGroupSortAsc->setEnabled(groupHasChildren);
m_ui->actionGroupSortDesc->setVisible(groupHasChildren);
m_ui->actionGroupSortDesc->setEnabled(groupHasChildren);
m_ui->actionGroupEmptyRecycleBin->setVisible(inRecycleBin);
m_ui->actionGroupEmptyRecycleBin->setEnabled(inRecycleBin);
#ifdef WITH_XC_NETWORKING
m_ui->actionGroupDownloadFavicons->setVisible(!inRecycleBin);
#endif
m_ui->actionGroupDownloadFavicons->setEnabled(groupSelected && groupHasEntries && !inRecycleBin);
// Database Menu
m_ui->actionDatabaseSave->setEnabled(m_ui->tabWidget->canSave());
m_ui->actionDatabaseSaveAs->setEnabled(databaseUnlocked);
m_ui->actionDatabaseSaveBackup->setEnabled(databaseUnlocked);
m_ui->actionDatabaseClose->setEnabled(dbWidget);
m_ui->actionLockDatabase->setEnabled(databaseUnlocked);
m_ui->actionLockAllDatabases->setEnabled(hasLockableDatabase);
m_ui->actionLockDatabaseToolbar->setEnabled(hasLockableDatabase);
m_ui->actionDatabaseSettings->setEnabled(inDatabase || inDatabaseSettings);
m_ui->actionDatabaseSecurity->setEnabled(inDatabase || inDatabaseSettings);
m_ui->actionReports->setEnabled(inDatabase || inReports);
m_ui->menuRemoteSync->setEnabled(inDatabase || inDatabaseSettings);
m_ui->menuExport->setEnabled(inDatabase);
m_ui->actionDatabaseMerge->setEnabled(inDatabase);
#ifdef WITH_XC_BROWSER_PASSKEYS
m_ui->actionPasskeys->setEnabled(false);
m_ui->actionImportPasskey->setEnabled(false);
m_ui->actionEntryImportPasskey->setEnabled(false);
m_ui->actionEntryRemovePasskey->setEnabled(false);
#else
m_ui->actionPasskeys->setVisible(false);
m_ui->actionImportPasskey->setVisible(false);
m_ui->actionEntryImportPasskey->setVisible(false);
m_ui->actionEntryRemovePasskey->setVisible(false);
m_ui->actionPasskeys->setEnabled(inDatabase || inReports);
m_ui->actionImportPasskey->setEnabled(inDatabase);
#endif
m_searchWidgetAction->setEnabled(false);
break;
}
default:
Q_ASSERT(false);
}
} else {
const auto entryActions = m_ui->menuEntries->actions();
for (auto action : entryActions) {
action->setEnabled(false);
}
const auto groupActions = m_ui->menuGroups->actions();
for (auto action : groupActions) {
action->setEnabled(false);
}
m_ui->actionDatabaseSecurity->setEnabled(false);
m_ui->actionReports->setEnabled(false);
m_ui->actionDatabaseSettings->setEnabled(false);
m_ui->actionDatabaseSave->setEnabled(false);
m_ui->actionDatabaseSaveAs->setEnabled(false);
m_ui->actionDatabaseSaveBackup->setEnabled(false);
m_ui->actionDatabaseClose->setEnabled(false);
m_ui->menuExport->setEnabled(false);
m_ui->actionExportCsv->setEnabled(false);
m_ui->actionExportHtml->setEnabled(false);
m_ui->actionDatabaseMerge->setEnabled(false);
m_ui->menuRemoteSync->setEnabled(false);
// Hide entry-specific actions
m_ui->actionEntryMoveUp->setVisible(false);
m_ui->actionEntryMoveDown->setVisible(false);
m_ui->actionEntryRestore->setVisible(false);
m_ui->actionEntryAddToAgent->setVisible(false);
m_ui->actionEntryRemoveFromAgent->setVisible(false);
m_ui->actionGroupEmptyRecycleBin->setVisible(false);
m_searchWidgetAction->setEnabled(false);
}
if ((currentIndex == PasswordGeneratorScreen) != m_ui->actionPasswordGenerator->isChecked()) {
bool blocked = m_ui->actionPasswordGenerator->blockSignals(true);
m_ui->actionPasswordGenerator->toggle();
m_ui->actionPasswordGenerator->blockSignals(blocked);
} else if ((currentIndex == SettingsScreen) != m_ui->actionSettings->isChecked()) {
bool blocked = m_ui->actionSettings->blockSignals(true);
m_ui->actionSettings->toggle();
m_ui->actionSettings->blockSignals(blocked);
}
m_searchWidgetAction->setEnabled(inDatabase);
}
void MainWindow::updateToolbarSeparatorVisibility()

View File

@ -106,7 +106,7 @@ protected:
bool focusNextPrevChild(bool next) override;
private slots:
void setMenuActionState(DatabaseWidget::Mode mode = DatabaseWidget::Mode::None);
void updateMenuActionState();
void updateToolbarSeparatorVisibility();
void updateWindowTitle();
void showAboutDialog();

View File

@ -256,9 +256,9 @@
<addaction name="actionLockDatabase"/>
<addaction name="actionLockAllDatabases"/>
<addaction name="separator"/>
<addaction name="actionReports"/>
<addaction name="actionDatabaseSettings"/>
<addaction name="actionDatabaseSecurity"/>
<addaction name="actionReports"/>
<addaction name="separator"/>
<addaction name="actionPasskeys"/>
<addaction name="actionImportPasskey"/>
@ -293,9 +293,6 @@
<bool>true</bool>
</property>
<widget class="QMenu" name="menuEntryCopyAttribute">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string/>
</property>
@ -307,9 +304,6 @@
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuEntryTotp">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>TOTP</string>
</property>
@ -324,6 +318,7 @@
<string>Tags</string>
</property>
</widget>
<addaction name="separator"/>
<addaction name="actionEntryNew"/>
<addaction name="actionEntryEdit"/>
<addaction name="actionEntryClone"/>
@ -356,16 +351,17 @@
<property name="title">
<string>&amp;Groups</string>
</property>
<addaction name="actionGroupEmptyRecycleBin"/>
<addaction name="separator"/>
<addaction name="actionGroupNew"/>
<addaction name="actionGroupEdit"/>
<addaction name="actionGroupClone"/>
<addaction name="actionGroupDelete"/>
<addaction name="actionGroupEmptyRecycleBin"/>
<addaction name="separator"/>
<addaction name="actionGroupDownloadFavicons"/>
<addaction name="separator"/>
<addaction name="actionGroupSortAsc"/>
<addaction name="actionGroupSortDesc"/>
<addaction name="separator"/>
<addaction name="actionGroupDownloadFavicons"/>
</widget>
<widget class="QMenu" name="menuTools">
<property name="title">
@ -436,6 +432,9 @@
<addaction name="actionEntryCopyURL"/>
<addaction name="actionEntryAutoType"/>
<addaction name="separator"/>
<addaction name="actionDatabaseSettings"/>
<addaction name="actionReports"/>
<addaction name="separator"/>
<addaction name="actionPasswordGenerator"/>
<addaction name="actionSettings"/>
<addaction name="separator"/>
@ -485,9 +484,6 @@
</property>
</action>
<action name="actionDatabaseSave">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Save Database</string>
</property>
@ -496,9 +492,6 @@
</property>
</action>
<action name="actionDatabaseClose">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Close Database</string>
</property>
@ -526,9 +519,6 @@
</property>
</action>
<action name="actionEntryNew">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;New Entry…</string>
</property>
@ -540,9 +530,6 @@
</property>
</action>
<action name="actionEntryEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Edit Entry…</string>
</property>
@ -554,9 +541,6 @@
</property>
</action>
<action name="actionEntryDelete">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Delete Entry…</string>
</property>
@ -568,9 +552,6 @@
</property>
</action>
<action name="actionGroupNew">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;New Group…</string>
</property>
@ -579,9 +560,6 @@
</property>
</action>
<action name="actionGroupEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Edit Group…</string>
</property>
@ -590,9 +568,6 @@
</property>
</action>
<action name="actionGroupDelete">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Delete Group…</string>
</property>
@ -601,9 +576,6 @@
</property>
</action>
<action name="actionGroupDownloadFavicons">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Download All &amp;Favicons…</string>
</property>
@ -612,9 +584,6 @@
</property>
</action>
<action name="actionGroupSortAsc">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Sort &amp;A-Z</string>
</property>
@ -623,9 +592,6 @@
</property>
</action>
<action name="actionGroupSortDesc">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Sort &amp;Z-A</string>
</property>
@ -634,9 +600,6 @@
</property>
</action>
<action name="actionDatabaseSaveAs">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Sa&amp;ve Database As…</string>
</property>
@ -648,9 +611,6 @@
</property>
</action>
<action name="actionDatabaseSecurity">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Database &amp;Security…</string>
</property>
@ -659,8 +619,8 @@
</property>
</action>
<action name="actionReports">
<property name="enabled">
<bool>false</bool>
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Database &amp;Reports…</string>
@ -676,8 +636,8 @@
</property>
</action>
<action name="actionDatabaseSettings">
<property name="enabled">
<bool>false</bool>
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Database Settings…</string>
@ -693,9 +653,6 @@
</property>
</action>
<action name="actionPasskeys">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Passkeys…</string>
</property>
@ -707,9 +664,6 @@
</property>
</action>
<action name="actionImportPasskey">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Import Passkey</string>
</property>
@ -721,9 +675,6 @@
</property>
</action>
<action name="actionEntryClone">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Clone Entry…</string>
</property>
@ -735,9 +686,6 @@
</property>
</action>
<action name="actionEntryMoveUp">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Move u&amp;p</string>
</property>
@ -749,9 +697,6 @@
</property>
</action>
<action name="actionEntryMoveDown">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Move do&amp;wn</string>
</property>
@ -763,9 +708,6 @@
</property>
</action>
<action name="actionEntryCopyUsername">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Copy &amp;Username</string>
</property>
@ -777,9 +719,6 @@
</property>
</action>
<action name="actionEntryCopyPassword">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Copy &amp;Password</string>
</property>
@ -819,25 +758,16 @@
</property>
</action>
<action name="actionEntryAutoType">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Perform &amp;Auto-Type</string>
</property>
</action>
<action name="actionEntryImportPasskey">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Import Passkey</string>
</property>
</action>
<action name="actionEntryRemovePasskey">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Remove Passkey From Entry</string>
</property>
@ -921,9 +851,6 @@
</property>
</action>
<action name="actionEntryOpenUrl">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Open &amp;URL</string>
</property>
@ -932,9 +859,6 @@
</property>
</action>
<action name="actionLockDatabase">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Lock Database</string>
</property>
@ -943,9 +867,6 @@
</property>
</action>
<action name="actionLockAllDatabases">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Lock &amp;All Databases</string>
</property>
@ -954,9 +875,6 @@
</property>
</action>
<action name="actionEntryCopyTitle">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Title</string>
</property>
@ -968,9 +886,6 @@
</property>
</action>
<action name="actionEntryCopyURL">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Copy &amp;URL</string>
</property>
@ -982,9 +897,6 @@
</property>
</action>
<action name="actionEntryCopyNotes">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Notes</string>
</property>
@ -993,9 +905,6 @@
</property>
</action>
<action name="actionExportCsv">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;CSV File…</string>
</property>
@ -1004,9 +913,6 @@
</property>
</action>
<action name="actionExportHtml">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;HTML File…</string>
</property>
@ -1085,9 +991,6 @@
<property name="toolTip">
<string>Empty Recycle Bin</string>
</property>
<property name="visible">
<bool>false</bool>
</property>
</action>
<action name="actionDonate">
<property name="text">
@ -1141,9 +1044,6 @@
</property>
</action>
<action name="actionDatabaseSaveBackup">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Save Database Backup…</string>
</property>
@ -1333,9 +1233,6 @@
</property>
</action>
<action name="actionGroupClone">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Clone Group...</string>
</property>
@ -1352,17 +1249,11 @@
</property>
</action>
<action name="actionLockDatabaseToolbar">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Lock Database</string>
</property>
</action>
<action name="actionExportXML">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;XML File…</string>
</property>

View File

@ -99,6 +99,8 @@ DatabaseSettingsDialog::~DatabaseSettingsDialog() = default;
void DatabaseSettingsDialog::load(const QSharedPointer<Database>& db)
{
setHeadline(tr("Database Settings: %1").arg(db->canonicalFilePath()));
m_generalWidget->loadSettings(db);
m_databaseKeyWidget->loadSettings(db);
m_encryptionWidget->loadSettings(db);

View File

@ -128,14 +128,23 @@ void ReportsDialog::addPage(QSharedPointer<IReportsPage> page)
m_ui->categoryList->setCurrentCategory(category);
}
#ifdef WITH_XC_BROWSER_PASSKEYS
void ReportsDialog::activatePasskeysPage()
{
#ifdef WITH_XC_BROWSER_PASSKEYS
m_ui->stackedWidget->setCurrentWidget(m_passkeysPage->m_passkeysWidget);
auto index = m_ui->stackedWidget->currentIndex();
m_ui->categoryList->setCurrentCategory(index);
}
#endif
}
bool ReportsDialog::onPassKeysPage()
{
#ifdef WITH_XC_BROWSER_PASSKEYS
return m_ui->stackedWidget->currentWidget() == m_passkeysPage->m_passkeysWidget;
#else
return false;
#endif
}
void ReportsDialog::reject()
{
@ -144,7 +153,7 @@ void ReportsDialog::reject()
void ReportsDialog::entryActivationSignalReceived(Entry* entry)
{
m_sender = static_cast<QWidget*>(sender());
m_sender = qobject_cast<QWidget*>(sender());
m_editEntryWidget->loadEntry(entry, false, false, entry->group()->hierarchy().join(" > "), m_db);
m_ui->stackedWidget->setCurrentWidget(m_editEntryWidget);
}

View File

@ -63,9 +63,8 @@ public:
void load(const QSharedPointer<Database>& db);
void addPage(QSharedPointer<IReportsPage> page);
#ifdef WITH_XC_BROWSER_PASSKEYS
void activatePasskeysPage();
#endif
bool onPassKeysPage();
signals:
void editFinished(bool accepted);

View File

@ -161,14 +161,13 @@ void TestGui::init()
// Every test ends with closing the temp database without saving
void TestGui::cleanup()
{
// DO NOT save the database
m_db->markAsClean();
MessageBox::setNextAnswer(MessageBox::No);
triggerAction("actionDatabaseClose");
QApplication::processEvents();
MessageBox::setNextAnswer(MessageBox::NoButton);
if (m_dbWidget) {
if (m_tabWidget->isVisible()) {
// DO NOT save the database
m_db->markAsClean();
MessageBox::setNextAnswer(MessageBox::No);
triggerAction("actionDatabaseClose");
QApplication::processEvents();
MessageBox::setNextAnswer(MessageBox::NoButton);
delete m_dbWidget;
}
}
@ -561,7 +560,7 @@ void TestGui::testEditEntry()
// Edit the first entry ("Sample Entry")
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
auto* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
QTest::keyClicks(titleEdit, "_test");
@ -576,7 +575,7 @@ void TestGui::testEditEntry()
// Apply the edit
QTRY_VERIFY(applyButton->isEnabled());
QTest::mouseClick(applyButton, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
QCOMPARE(entry->title(), QString("Sample Entry_test"));
QCOMPARE(entry->historyItems().size(), ++editCount);
QVERIFY(!applyButton->isEnabled());
@ -654,7 +653,7 @@ void TestGui::testEditEntry()
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
okButton = editEntryWidgetButtonBox->button(QDialogButtonBox::Ok);
QVERIFY(okButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
titleEdit->setText("multiline\ntitle");
editEntryWidget->findChild<QComboBox*>("usernameComboBox")->lineEdit()->setText("multiline\nusername");
editEntryWidget->findChild<PasswordWidget*>("passwordEdit")->setText("multiline\npassword");
@ -713,7 +712,7 @@ void TestGui::testSearchEditEntry()
// Goto "Doggy"'s edit view
QTest::keyClick(searchTextEdit, Qt::Key_Return);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
// Check the path in header is "parent-group > entry"
QCOMPARE(m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget")->findChild<QLabel*>("headerLabel")->text(),
@ -739,7 +738,7 @@ void TestGui::testAddEntry()
// Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
// Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
@ -859,7 +858,7 @@ void TestGui::testPasswordEntryEntropy()
// Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
// Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
@ -921,7 +920,7 @@ void TestGui::testDicewareEntryEntropy()
// Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
// Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
@ -1008,7 +1007,7 @@ void TestGui::testTotp()
QVERIFY(entryEditWidget->isVisible());
QVERIFY(entryEditWidget->isEnabled());
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
editEntryWidget->setCurrentPage(1);
@ -1212,7 +1211,7 @@ void TestGui::testSearch()
QModelIndex item = entryView->model()->index(0, 1);
Entry* entry = entryView->entryFromIndex(item);
QTest::keyClick(searchTextEdit, Qt::Key_Return);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
// Perform the edit and save it
EditEntryWidget* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
@ -1370,7 +1369,7 @@ void TestGui::testEntryPlaceholders()
// Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
// Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
@ -1723,7 +1722,7 @@ void TestGui::testDatabaseSettings()
QWidget* entryNewWidget = toolBar->widgetForAction(entryNewAction);
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
QVERIFY(editEntryWidget);
@ -1743,7 +1742,7 @@ void TestGui::testDatabaseSettings()
// 2.d) Create second entry to test delay timer reset
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
QTest::keyClicks(titleEdit, "Test autosaveDelay 2");
// 2.e) Save changes
@ -1763,7 +1762,7 @@ void TestGui::testDatabaseSettings()
// 4 Test no delay when disabled autosave or autosaveDelay
// 4.a) create new entry
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
QTest::keyClicks(titleEdit, "Test autosaveDelay 3");
// 4.b) Save changes
@ -1784,7 +1783,7 @@ void TestGui::testDatabaseSettings()
// 4.f) Repeat for autosaveDelay
config()->set(Config::AutoSaveAfterEveryChange, true);
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
QTest::keyClicks(titleEdit, "Test autosaveDelay 4");
editEntryWidget->setCurrentPage(0);
editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
@ -2061,7 +2060,7 @@ void TestGui::testAutoType()
QVERIFY(entryNewWidget->isEnabled());
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
QVERIFY(editEntryWidget);
@ -2096,7 +2095,7 @@ void TestGui::testAutoType()
// 2.a) Click the new entry button and set the title
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
QTest::keyClicks(titleEdit, "2. Entry With Default Auto-Type Sequence");
QTest::mouseClick(usernameComboBox, Qt::LeftButton);
QTest::keyClicks(usernameComboBox, "AutocompletionUsername");
@ -2115,7 +2114,7 @@ void TestGui::testAutoType()
// 3.a) Click the new entry button and set the title
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
QTest::keyClicks(titleEdit, "3. Entry With Custom Auto-Type Sequence");
QTest::mouseClick(usernameComboBox, Qt::LeftButton);
QTest::keyClicks(usernameComboBox, "AutocompletionUsername");
@ -2192,6 +2191,155 @@ void TestGui::testAutoType()
entryView->selectionModel()->clearSelection();
}
void TestGui::testMenuActionStates()
{
auto isActionEnabled = [this](const QString& actionName) -> bool {
auto action = m_mainWindow->findChild<QAction*>(actionName);
if (!action) {
QTest::qFail(qPrintable(QString("Invalid action specified: %1").arg(actionName)), __FILE__, __LINE__);
return false;
}
return action->isEnabled();
};
// Start with database open and unlocked
qInfo("Actions Test: Database open and unlocked");
QVERIFY(isActionEnabled("actionEntryNew"));
QVERIFY(isActionEnabled("actionGroupNew"));
QVERIFY(isActionEnabled("actionDatabaseSaveAs"));
QVERIFY(isActionEnabled("actionDatabaseClose"));
QVERIFY(isActionEnabled("actionDatabaseMerge"));
QVERIFY(isActionEnabled("actionDatabaseSettings"));
QVERIFY(isActionEnabled("actionReports"));
QVERIFY(isActionEnabled("actionLockDatabase"));
QVERIFY(isActionEnabled("actionLockAllDatabases"));
QVERIFY(isActionEnabled("actionImport"));
QVERIFY(isActionEnabled("actionExportCsv"));
QVERIFY(isActionEnabled("actionSettings"));
QVERIFY(isActionEnabled("actionPasswordGenerator"));
// Edit entry actions
qInfo("Actions Test: Editing an entry");
triggerAction("actionEntryEdit");
QVERIFY(!isActionEnabled("actionEntryNew"));
QVERIFY(isActionEnabled("actionEntryCopyUsername"));
QVERIFY(!isActionEnabled("actionEntrySetupTotp"));
QVERIFY(!isActionEnabled("actionGroupNew"));
QVERIFY(isActionEnabled("actionDatabaseSaveAs"));
QVERIFY(isActionEnabled("actionDatabaseClose"));
QVERIFY(!isActionEnabled("actionDatabaseMerge"));
QVERIFY(!isActionEnabled("actionDatabaseSettings"));
QVERIFY(!isActionEnabled("actionReports"));
QVERIFY(isActionEnabled("actionLockDatabase"));
QVERIFY(isActionEnabled("actionLockAllDatabases"));
QVERIFY(isActionEnabled("actionSettings"));
QVERIFY(isActionEnabled("actionPasswordGenerator"));
// Special Case - Recycle Bin
qInfo("Actions Test: Special case - Recycle Bin");
m_dbWidget->switchToMainView();
QApplication::processEvents();
QVERIFY(m_db->metadata()->recycleBinEnabled());
triggerAction("actionEntryDelete");
m_dbWidget->groupView()->setCurrentGroup(m_db->metadata()->recycleBin());
QVERIFY(m_dbWidget->isRecycleBinSelected());
QVERIFY(isActionEnabled("actionEntryRestore"));
QVERIFY(isActionEnabled("actionGroupEmptyRecycleBin"));
QVERIFY(!isActionEnabled("actionEntryNew"));
QVERIFY(!isActionEnabled("actionEntryClone"));
QVERIFY(!isActionEnabled("actionGroupNew"));
QVERIFY(!isActionEnabled("actionGroupClone"));
// Database Settings
qInfo("Actions Test: Database settings");
triggerAction("actionDatabaseSettings");
QVERIFY(!isActionEnabled("actionEntryNew"));
QVERIFY(!isActionEnabled("actionEntrySetupTotp"));
QVERIFY(!isActionEnabled("actionGroupNew"));
QVERIFY(isActionEnabled("actionDatabaseSaveAs"));
QVERIFY(isActionEnabled("actionDatabaseClose"));
QVERIFY(!isActionEnabled("actionDatabaseMerge"));
QVERIFY(isActionEnabled("actionDatabaseSettings"));
QVERIFY(isActionEnabled("actionDatabaseSecurity"));
QVERIFY(!isActionEnabled("actionReports"));
QVERIFY(isActionEnabled("actionLockDatabase"));
QVERIFY(isActionEnabled("actionSettings"));
QVERIFY(isActionEnabled("actionPasswordGenerator"));
// Database Reports
qInfo("Actions Test: Database reports");
triggerAction("actionDatabaseSettings");
triggerAction("actionReports");
QVERIFY(!isActionEnabled("actionEntryNew"));
QVERIFY(!isActionEnabled("actionEntrySetupTotp"));
QVERIFY(!isActionEnabled("actionGroupNew"));
QVERIFY(isActionEnabled("actionDatabaseSaveAs"));
QVERIFY(isActionEnabled("actionDatabaseClose"));
QVERIFY(!isActionEnabled("actionDatabaseMerge"));
QVERIFY(!isActionEnabled("actionDatabaseSettings"));
QVERIFY(!isActionEnabled("actionDatabaseSecurity"));
QVERIFY(isActionEnabled("actionReports"));
QVERIFY(isActionEnabled("actionLockDatabase"));
QVERIFY(isActionEnabled("actionSettings"));
QVERIFY(isActionEnabled("actionPasswordGenerator"));
// Application Settings
qInfo("Actions Test: Application settings");
triggerAction("actionSettings");
QVERIFY(!isActionEnabled("actionDatabaseSettings"));
QVERIFY(!isActionEnabled("actionDatabaseSecurity"));
QVERIFY(!isActionEnabled("actionReports"));
QVERIFY(isActionEnabled("actionSettings"));
QVERIFY(isActionEnabled("actionPasswordGenerator"));
// Locked Database
qInfo("Actions Test: Database locked");
triggerAction("actionSettings");
MessageBox::setNextAnswer(MessageBox::Discard);
triggerAction("actionLockDatabase");
QVERIFY(!isActionEnabled("actionEntryNew"));
QVERIFY(!isActionEnabled("actionGroupNew"));
QVERIFY(!isActionEnabled("actionDatabaseSaveAs"));
QVERIFY(isActionEnabled("actionDatabaseClose"));
QVERIFY(!isActionEnabled("actionDatabaseMerge"));
QVERIFY(!isActionEnabled("actionDatabaseSettings"));
QVERIFY(!isActionEnabled("actionReports"));
QVERIFY(!isActionEnabled("actionLockDatabase"));
QVERIFY(!isActionEnabled("actionLockAllDatabases"));
QVERIFY(isActionEnabled("actionSettings"));
QVERIFY(isActionEnabled("actionPasswordGenerator"));
// Welcome Screen
qInfo("Actions Test: Welcome screen");
triggerAction("actionDatabaseClose");
QVERIFY(!isActionEnabled("actionEntryNew"));
QVERIFY(!isActionEnabled("actionGroupNew"));
QVERIFY(!isActionEnabled("actionDatabaseSaveAs"));
QVERIFY(!isActionEnabled("actionDatabaseClose"));
QVERIFY(!isActionEnabled("actionDatabaseMerge"));
QVERIFY(!isActionEnabled("actionDatabaseSettings"));
QVERIFY(!isActionEnabled("actionReports"));
QVERIFY(!isActionEnabled("actionLockDatabase"));
QVERIFY(!isActionEnabled("actionLockAllDatabases"));
QVERIFY(isActionEnabled("actionImport"));
QVERIFY(isActionEnabled("actionSettings"));
QVERIFY(isActionEnabled("actionPasswordGenerator"));
}
void TestGui::addCannedEntries()
{
// Find buttons
@ -2266,8 +2414,8 @@ void TestGui::checkStatusBarText(const QString& textFragment)
void TestGui::triggerAction(const QString& name)
{
auto* action = m_mainWindow->findChild<QAction*>(name);
QVERIFY(action);
QVERIFY(action->isEnabled());
QVERIFY2(action, qPrintable(QString("Action doesn't exist: %1").arg(name)));
QVERIFY2(action->isEnabled(), qPrintable(QString("Action is disabled: %1").arg(name)));
action->trigger();
QApplication::processEvents();
}

View File

@ -69,6 +69,7 @@ private slots:
void testAutoType();
void testTrayRestoreHide();
void testShortcutConfig();
void testMenuActionStates();
private:
void addCannedEntries();

View File

@ -142,7 +142,7 @@ void TestGuiBrowser::testEntrySettings()
auto* entryEditAction = m_mainWindow->findChild<QAction*>("actionEntryEdit");
QWidget* entryEditWidget = toolBar->widgetForAction(entryEditAction);
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
// Switch to Properties page and select all rows from the custom data table
@ -186,7 +186,7 @@ void TestGuiBrowser::testAdditionalURLs()
auto* entryEditAction = m_mainWindow->findChild<QAction*>("actionEntryEdit");
QWidget* entryEditWidget = toolBar->widgetForAction(entryEditAction);
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
// Switch to Browser Integration page and add three URL's