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-lock-all.svg
share/icons/application/scalable/actions/database-merge.svg share/icons/application/scalable/actions/database-merge.svg
share/icons/application/scalable/actions/database-search.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-close.svg
share/icons/application/scalable/actions/dialog-ok.svg share/icons/application/scalable/actions/dialog-ok.svg
share/icons/application/scalable/actions/document-close.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-alert.svg
share/icons/application/scalable/actions/lock-open.svg share/icons/application/scalable/actions/lock-open.svg
share/icons/application/scalable/actions/lock.svg share/icons/application/scalable/actions/lock.svg
Copyright: 2019 Austin Andrews <http://templarian.com/> Copyright: 2023 Pictogrammers <https://pictogrammers.com/docs/general/about/>
License: SIL OPEN FONT LICENSE Version 1.1 License: Apache-2.0
Comment: Taken from Material Design icon set (https://github.com/templarian/MaterialDesign/) Comment: Some icons are modified to fit KeePassXC design (https://pictogrammers.com/library/mdi/)
Files: src/streams/qtiocompressor.* Files: src/streams/qtiocompressor.*
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-lock-all.svg</file>
<file>application/scalable/actions/database-merge.svg</file> <file>application/scalable/actions/database-merge.svg</file>
<file>application/scalable/actions/database-search.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-close.svg</file>
<file>application/scalable/actions/dialog-ok.svg</file> <file>application/scalable/actions/dialog-ok.svg</file>
<file>application/scalable/actions/document-close.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> <source>Remote Sync</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Database Settings: %1</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>DatabaseSettingsWidgetBrowser</name> <name>DatabaseSettingsWidgetBrowser</name>

View File

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

View File

@ -537,21 +537,29 @@ bool DatabaseTabWidget::warnOnExport()
return ans == MessageBox::Yes; 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() void DatabaseTabWidget::showDatabaseSecurity()
{ {
currentDatabaseWidget()->switchToDatabaseSecurity(); currentDatabaseWidget()->switchToDatabaseSecurity();
} }
void DatabaseTabWidget::showDatabaseReports()
{
currentDatabaseWidget()->switchToDatabaseReports();
}
void DatabaseTabWidget::showDatabaseSettings()
{
currentDatabaseWidget()->switchToDatabaseSettings();
}
#ifdef WITH_XC_BROWSER_PASSKEYS #ifdef WITH_XC_BROWSER_PASSKEYS
void DatabaseTabWidget::showPasskeys() void DatabaseTabWidget::showPasskeys()
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -128,14 +128,23 @@ void ReportsDialog::addPage(QSharedPointer<IReportsPage> page)
m_ui->categoryList->setCurrentCategory(category); m_ui->categoryList->setCurrentCategory(category);
} }
#ifdef WITH_XC_BROWSER_PASSKEYS
void ReportsDialog::activatePasskeysPage() void ReportsDialog::activatePasskeysPage()
{ {
#ifdef WITH_XC_BROWSER_PASSKEYS
m_ui->stackedWidget->setCurrentWidget(m_passkeysPage->m_passkeysWidget); m_ui->stackedWidget->setCurrentWidget(m_passkeysPage->m_passkeysWidget);
auto index = m_ui->stackedWidget->currentIndex(); auto index = m_ui->stackedWidget->currentIndex();
m_ui->categoryList->setCurrentCategory(index); m_ui->categoryList->setCurrentCategory(index);
}
#endif #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() void ReportsDialog::reject()
{ {
@ -144,7 +153,7 @@ void ReportsDialog::reject()
void ReportsDialog::entryActivationSignalReceived(Entry* entry) 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_editEntryWidget->loadEntry(entry, false, false, entry->group()->hierarchy().join(" > "), m_db);
m_ui->stackedWidget->setCurrentWidget(m_editEntryWidget); m_ui->stackedWidget->setCurrentWidget(m_editEntryWidget);
} }

View File

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

View File

@ -161,14 +161,13 @@ void TestGui::init()
// Every test ends with closing the temp database without saving // Every test ends with closing the temp database without saving
void TestGui::cleanup() void TestGui::cleanup()
{ {
// DO NOT save the database if (m_tabWidget->isVisible()) {
m_db->markAsClean(); // DO NOT save the database
MessageBox::setNextAnswer(MessageBox::No); m_db->markAsClean();
triggerAction("actionDatabaseClose"); MessageBox::setNextAnswer(MessageBox::No);
QApplication::processEvents(); triggerAction("actionDatabaseClose");
MessageBox::setNextAnswer(MessageBox::NoButton); QApplication::processEvents();
MessageBox::setNextAnswer(MessageBox::NoButton);
if (m_dbWidget) {
delete m_dbWidget; delete m_dbWidget;
} }
} }
@ -561,7 +560,7 @@ void TestGui::testEditEntry()
// Edit the first entry ("Sample Entry") // Edit the first entry ("Sample Entry")
QTest::mouseClick(entryEditWidget, Qt::LeftButton); 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* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
auto* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit"); auto* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
QTest::keyClicks(titleEdit, "_test"); QTest::keyClicks(titleEdit, "_test");
@ -576,7 +575,7 @@ void TestGui::testEditEntry()
// Apply the edit // Apply the edit
QTRY_VERIFY(applyButton->isEnabled()); QTRY_VERIFY(applyButton->isEnabled());
QTest::mouseClick(applyButton, Qt::LeftButton); 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->title(), QString("Sample Entry_test"));
QCOMPARE(entry->historyItems().size(), ++editCount); QCOMPARE(entry->historyItems().size(), ++editCount);
QVERIFY(!applyButton->isEnabled()); QVERIFY(!applyButton->isEnabled());
@ -654,7 +653,7 @@ void TestGui::testEditEntry()
QTest::mouseClick(entryEditWidget, Qt::LeftButton); QTest::mouseClick(entryEditWidget, Qt::LeftButton);
okButton = editEntryWidgetButtonBox->button(QDialogButtonBox::Ok); okButton = editEntryWidgetButtonBox->button(QDialogButtonBox::Ok);
QVERIFY(okButton); QVERIFY(okButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode);
titleEdit->setText("multiline\ntitle"); titleEdit->setText("multiline\ntitle");
editEntryWidget->findChild<QComboBox*>("usernameComboBox")->lineEdit()->setText("multiline\nusername"); editEntryWidget->findChild<QComboBox*>("usernameComboBox")->lineEdit()->setText("multiline\nusername");
editEntryWidget->findChild<PasswordWidget*>("passwordEdit")->setText("multiline\npassword"); editEntryWidget->findChild<PasswordWidget*>("passwordEdit")->setText("multiline\npassword");
@ -713,7 +712,7 @@ void TestGui::testSearchEditEntry()
// Goto "Doggy"'s edit view // Goto "Doggy"'s edit view
QTest::keyClick(searchTextEdit, Qt::Key_Return); 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" // Check the path in header is "parent-group > entry"
QCOMPARE(m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget")->findChild<QLabel*>("headerLabel")->text(), 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 // Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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 // Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget"); 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 // Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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 // Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget"); 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 // Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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 // Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget"); auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
@ -1008,7 +1007,7 @@ void TestGui::testTotp()
QVERIFY(entryEditWidget->isVisible()); QVERIFY(entryEditWidget->isVisible());
QVERIFY(entryEditWidget->isEnabled()); QVERIFY(entryEditWidget->isEnabled());
QTest::mouseClick(entryEditWidget, Qt::LeftButton); 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* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
editEntryWidget->setCurrentPage(1); editEntryWidget->setCurrentPage(1);
@ -1212,7 +1211,7 @@ void TestGui::testSearch()
QModelIndex item = entryView->model()->index(0, 1); QModelIndex item = entryView->model()->index(0, 1);
Entry* entry = entryView->entryFromIndex(item); Entry* entry = entryView->entryFromIndex(item);
QTest::keyClick(searchTextEdit, Qt::Key_Return); 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 // Perform the edit and save it
EditEntryWidget* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget"); 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 // Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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 // Add entry "test" and confirm added
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget"); auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
@ -1723,7 +1722,7 @@ void TestGui::testDatabaseSettings()
QWidget* entryNewWidget = toolBar->widgetForAction(entryNewAction); QWidget* entryNewWidget = toolBar->widgetForAction(entryNewAction);
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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"); auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
QVERIFY(editEntryWidget); QVERIFY(editEntryWidget);
@ -1743,7 +1742,7 @@ void TestGui::testDatabaseSettings()
// 2.d) Create second entry to test delay timer reset // 2.d) Create second entry to test delay timer reset
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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"); QTest::keyClicks(titleEdit, "Test autosaveDelay 2");
// 2.e) Save changes // 2.e) Save changes
@ -1763,7 +1762,7 @@ void TestGui::testDatabaseSettings()
// 4 Test no delay when disabled autosave or autosaveDelay // 4 Test no delay when disabled autosave or autosaveDelay
// 4.a) create new entry // 4.a) create new entry
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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"); QTest::keyClicks(titleEdit, "Test autosaveDelay 3");
// 4.b) Save changes // 4.b) Save changes
@ -1784,7 +1783,7 @@ void TestGui::testDatabaseSettings()
// 4.f) Repeat for autosaveDelay // 4.f) Repeat for autosaveDelay
config()->set(Config::AutoSaveAfterEveryChange, true); config()->set(Config::AutoSaveAfterEveryChange, true);
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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"); QTest::keyClicks(titleEdit, "Test autosaveDelay 4");
editEntryWidget->setCurrentPage(0); editEntryWidget->setCurrentPage(0);
editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox"); editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
@ -2061,7 +2060,7 @@ void TestGui::testAutoType()
QVERIFY(entryNewWidget->isEnabled()); QVERIFY(entryNewWidget->isEnabled());
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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"); auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
QVERIFY(editEntryWidget); QVERIFY(editEntryWidget);
@ -2096,7 +2095,7 @@ void TestGui::testAutoType()
// 2.a) Click the new entry button and set the title // 2.a) Click the new entry button and set the title
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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::keyClicks(titleEdit, "2. Entry With Default Auto-Type Sequence");
QTest::mouseClick(usernameComboBox, Qt::LeftButton); QTest::mouseClick(usernameComboBox, Qt::LeftButton);
QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); QTest::keyClicks(usernameComboBox, "AutocompletionUsername");
@ -2115,7 +2114,7 @@ void TestGui::testAutoType()
// 3.a) Click the new entry button and set the title // 3.a) Click the new entry button and set the title
QTest::mouseClick(entryNewWidget, Qt::LeftButton); 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::keyClicks(titleEdit, "3. Entry With Custom Auto-Type Sequence");
QTest::mouseClick(usernameComboBox, Qt::LeftButton); QTest::mouseClick(usernameComboBox, Qt::LeftButton);
QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); QTest::keyClicks(usernameComboBox, "AutocompletionUsername");
@ -2192,6 +2191,155 @@ void TestGui::testAutoType()
entryView->selectionModel()->clearSelection(); 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() void TestGui::addCannedEntries()
{ {
// Find buttons // Find buttons
@ -2266,8 +2414,8 @@ void TestGui::checkStatusBarText(const QString& textFragment)
void TestGui::triggerAction(const QString& name) void TestGui::triggerAction(const QString& name)
{ {
auto* action = m_mainWindow->findChild<QAction*>(name); auto* action = m_mainWindow->findChild<QAction*>(name);
QVERIFY(action); QVERIFY2(action, qPrintable(QString("Action doesn't exist: %1").arg(name)));
QVERIFY(action->isEnabled()); QVERIFY2(action->isEnabled(), qPrintable(QString("Action is disabled: %1").arg(name)));
action->trigger(); action->trigger();
QApplication::processEvents(); QApplication::processEvents();
} }

View File

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

View File

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