Customize buttons on MessageBox and confirm before recycling (#2376)

* Add confirmation prompt before moving groups to the recycling bin

Spawn a yes/no QMessage box when "Delete Group" is selected on a group
that is not already in the recycle bin (note: the prompt for deletion
from the recycle bin was already implemented).  This follows the same
pattern and language as entry deletion.

Fixes #2125

* Make prompts for destructive operations use action words on buttons

Replace yes/no, yes/cancel (and other such buttons on prompts that cause
data to be destroyed) use language that indicates the action that it is
going to take. This makes destructive/unsafe and/or irreversible operations
more clear to the user.

Address feedback on PR #2376

* Refactor MessageBox class to allow for custom buttons

Replaces arguments and return values of type QMessageBox::StandardButton(s)
with MessageBox::Button(s), which reimplements the entire set of
QMessageBox::StandardButton and allows for custom KeePassXC buttons,
such as "Skip". Modifies all calls to MessageBox functions to use
MessageBox::Button(s).

Addresses feedback on #2376

* Remove MessageBox::addButton in favor of map lookup

Replaced the switch statement mechanism in MessageBox::addButton with
a map lookup to address CodeFactor Complex Method issue. This has a
side-effect of a small performance/cleanliness increase, as an
extra QPushButton is no longer created/destroyed (to obtain it's label
text) everytime a MessageBox button based on QMessageBox::StandardButton
is created; now the text is obtained once, at application start up.
This commit is contained in:
Kyle Kneitinger 2018-12-19 20:14:11 -08:00 committed by Jonathan White
parent 8ac9d0a131
commit 4d4c839afa
15 changed files with 400 additions and 232 deletions

View File

@ -34,6 +34,7 @@
#include "core/Metadata.h" #include "core/Metadata.h"
#include "core/PasswordGenerator.h" #include "core/PasswordGenerator.h"
#include "gui/MainWindow.h" #include "gui/MainWindow.h"
#include "gui/MessageBox.h"
const char BrowserService::KEEPASSXCBROWSER_NAME[] = "KeePassXC-Browser Settings"; const char BrowserService::KEEPASSXCBROWSER_NAME[] = "KeePassXC-Browser Settings";
const char BrowserService::KEEPASSXCBROWSER_OLD_NAME[] = "keepassxc-browser Settings"; const char BrowserService::KEEPASSXCBROWSER_OLD_NAME[] = "keepassxc-browser Settings";
@ -157,7 +158,7 @@ QString BrowserService::storeKey(const QString& key)
} }
bool contains; bool contains;
QMessageBox::StandardButton dialogResult = QMessageBox::No; MessageBox::Button dialogResult = MessageBox::Cancel;
do { do {
QInputDialog keyDialog; QInputDialog keyDialog;
@ -180,14 +181,15 @@ QString BrowserService::storeKey(const QString& key)
contains = db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX) + id); contains = db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX) + id);
if (contains) { if (contains) {
dialogResult = QMessageBox::warning(nullptr, dialogResult = MessageBox::warning(nullptr,
tr("KeePassXC: Overwrite existing key?"), tr("KeePassXC: Overwrite existing key?"),
tr("A shared encryption key with the name \"%1\" " tr("A shared encryption key with the name \"%1\" "
"already exists.\nDo you want to overwrite it?") "already exists.\nDo you want to overwrite it?")
.arg(id), .arg(id),
QMessageBox::Yes | QMessageBox::No); MessageBox::Overwrite | MessageBox::Cancel,
MessageBox::Cancel);
} }
} while (contains && dialogResult == QMessageBox::No); } while (contains && dialogResult == MessageBox::Cancel);
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + id, key); db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + id, key);
return id; return id;
@ -367,21 +369,17 @@ void BrowserService::updateEntry(const QString& id,
if (username.compare(login, Qt::CaseSensitive) != 0 if (username.compare(login, Qt::CaseSensitive) != 0
|| entry->password().compare(password, Qt::CaseSensitive) != 0) { || entry->password().compare(password, Qt::CaseSensitive) != 0) {
int dialogResult = QMessageBox::No; MessageBox::Button dialogResult = MessageBox::No;
if (!browserSettings()->alwaysAllowUpdate()) { if (!browserSettings()->alwaysAllowUpdate()) {
QMessageBox msgBox; dialogResult = MessageBox::question(nullptr,
msgBox.setWindowTitle(tr("KeePassXC: Update Entry")); tr("KeePassXC: Update Entry"),
msgBox.setText(tr("Do you want to update the information in %1 - %2?").arg(QUrl(url).host(), username)); tr("Do you want to update the information in %1 - %2?")
msgBox.setStandardButtons(QMessageBox::Yes); .arg(QUrl(url).host(), username),
msgBox.addButton(QMessageBox::No); MessageBox::Save | MessageBox::Cancel,
msgBox.setDefaultButton(QMessageBox::No); MessageBox::Cancel);
msgBox.setWindowFlags(Qt::WindowStaysOnTopHint);
msgBox.activateWindow();
msgBox.raise();
dialogResult = msgBox.exec();
} }
if (browserSettings()->alwaysAllowUpdate() || dialogResult == QMessageBox::Yes) { if (browserSettings()->alwaysAllowUpdate() || dialogResult == MessageBox::Save) {
entry->beginUpdate(); entry->beginUpdate();
entry->setUsername(login); entry->setUsername(login);
entry->setPassword(password); entry->setPassword(password);
@ -497,24 +495,24 @@ void BrowserService::convertAttributesToCustomData(QSharedPointer<Database> curr
progress.reset(); progress.reset();
if (counter > 0) { if (counter > 0) {
QMessageBox::information(nullptr, MessageBox::information(nullptr,
tr("KeePassXC: Converted KeePassHTTP attributes"), tr("KeePassXC: Converted KeePassHTTP attributes"),
tr("Successfully converted attributes from %1 entry(s).\n" tr("Successfully converted attributes from %1 entry(s).\n"
"Moved %2 keys to custom data.", "Moved %2 keys to custom data.",
"") "")
.arg(counter) .arg(counter)
.arg(keyCounter), .arg(keyCounter),
QMessageBox::Ok); MessageBox::Ok);
} else if (counter == 0 && keyCounter > 0) { } else if (counter == 0 && keyCounter > 0) {
QMessageBox::information(nullptr, MessageBox::information(nullptr,
tr("KeePassXC: Converted KeePassHTTP attributes"), tr("KeePassXC: Converted KeePassHTTP attributes"),
tr("Successfully moved %n keys to custom data.", "", keyCounter), tr("Successfully moved %n keys to custom data.", "", keyCounter),
QMessageBox::Ok); MessageBox::Ok);
} else { } else {
QMessageBox::information(nullptr, MessageBox::information(nullptr,
tr("KeePassXC: No entry with KeePassHTTP attributes found!"), tr("KeePassXC: No entry with KeePassHTTP attributes found!"),
tr("The active database does not contain an entry with KeePassHTTP attributes."), tr("The active database does not contain an entry with KeePassHTTP attributes."),
QMessageBox::Ok); MessageBox::Ok);
} }
// Rename password groupName // Rename password groupName
@ -901,13 +899,14 @@ bool BrowserService::checkLegacySettings()
return false; return false;
} }
auto dialogResult = QMessageBox::warning(nullptr, auto dialogResult = MessageBox::warning(nullptr,
tr("KeePassXC: Legacy browser integration settings detected"), tr("KeePassXC: Legacy browser integration settings detected"),
tr("Legacy browser integration settings have been detected.\n" tr("Legacy browser integration settings have been detected.\n"
"Do you want to upgrade the settings to the latest standard?\n" "Do you want to upgrade the settings to the latest standard?\n"
"This is necessary to maintain compatibility with the browser plugin."), "This is necessary to maintain compatibility with the browser plugin."),
QMessageBox::Yes | QMessageBox::No); MessageBox::Yes | MessageBox::No);
return dialogResult == QMessageBox::Yes;
return dialogResult == MessageBox::Yes;
} }
void BrowserService::databaseLocked(DatabaseWidget* dbWidget) void BrowserService::databaseLocked(DatabaseWidget* dbWidget)

View File

@ -18,10 +18,12 @@
#include "Bootstrap.h" #include "Bootstrap.h"
#include "core/Config.h" #include "core/Config.h"
#include "core/Translator.h" #include "core/Translator.h"
#include "gui/MessageBox.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <aclapi.h> // for createWindowsDACL() #include <aclapi.h> // for createWindowsDACL()
#include <windows.h> // for Sleep(), SetDllDirectoryA(), SetSearchPathMode(), ... #include <windows.h> // for Sleep(), SetDllDirectoryA(), SetSearchPathMode(), ...
#undef MessageBox
#endif #endif
namespace Bootstrap namespace Bootstrap
@ -56,6 +58,7 @@ namespace Bootstrap
setupSearchPaths(); setupSearchPaths();
applyEarlyQNetworkAccessManagerWorkaround(); applyEarlyQNetworkAccessManagerWorkaround();
Translator::installTranslators(); Translator::installTranslators();
MessageBox::initializeButtonDefs();
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
// Don't show menu icons on OSX // Don't show menu icons on OSX

View File

@ -98,8 +98,8 @@ QSharedPointer<Database> DatabaseTabWidget::execNewDatabaseWizard()
tr("Database creation error"), tr("Database creation error"),
tr("The created database has no key or KDF, refusing to save it.\n" tr("The created database has no key or KDF, refusing to save it.\n"
"This is definitely a bug, please report it to the developers."), "This is definitely a bug, please report it to the developers."),
QMessageBox::Ok, MessageBox::Ok,
QMessageBox::Ok); MessageBox::Ok);
return {}; return {};
} }

View File

@ -445,6 +445,7 @@ void DatabaseWidget::deleteEntries()
bool inRecycleBin = recycleBin && recycleBin->findEntryByUuid(selectedEntries.first()->uuid()); bool inRecycleBin = recycleBin && recycleBin->findEntryByUuid(selectedEntries.first()->uuid());
if (inRecycleBin || !m_db->metadata()->recycleBinEnabled()) { if (inRecycleBin || !m_db->metadata()->recycleBinEnabled()) {
QString prompt; QString prompt;
refreshSearch();
if (selected.size() == 1) { if (selected.size() == 1) {
prompt = tr("Do you really want to delete the entry \"%1\" for good?") prompt = tr("Do you really want to delete the entry \"%1\" for good?")
.arg(selectedEntries.first()->title().toHtmlEscaped()); .arg(selectedEntries.first()->title().toHtmlEscaped());
@ -452,12 +453,16 @@ void DatabaseWidget::deleteEntries()
prompt = tr("Do you really want to delete %n entry(s) for good?", "", selected.size()); prompt = tr("Do you really want to delete %n entry(s) for good?", "", selected.size());
} }
QMessageBox::StandardButton result = MessageBox::question( auto answer = MessageBox::question(this,
this, tr("Delete entry(s)?", "", selected.size()), prompt, QMessageBox::Yes | QMessageBox::No); tr("Delete entry(s)?", "", selected.size()),
prompt,
MessageBox::Delete | MessageBox::Cancel,
MessageBox::Cancel);
if (result == QMessageBox::Yes) { if (answer == MessageBox::Delete) {
for (Entry* entry : asConst(selectedEntries)) { for (Entry* entry : asConst(selectedEntries)) {
delete entry; delete entry;
refreshSearch();
} }
refreshSearch(); refreshSearch();
} }
@ -470,10 +475,13 @@ void DatabaseWidget::deleteEntries()
prompt = tr("Do you really want to move %n entry(s) to the recycle bin?", "", selected.size()); prompt = tr("Do you really want to move %n entry(s) to the recycle bin?", "", selected.size());
} }
QMessageBox::StandardButton result = MessageBox::question( auto answer = MessageBox::question(this,
this, tr("Move entry(s) to recycle bin?", "", selected.size()), prompt, QMessageBox::Yes | QMessageBox::No); tr("Move entry(s) to recycle bin?", "", selected.size()),
prompt,
MessageBox::Move | MessageBox::Cancel,
MessageBox::Cancel);
if (result == QMessageBox::No) { if (answer == MessageBox::Cancel) {
return; return;
} }
@ -650,16 +658,27 @@ void DatabaseWidget::deleteGroup()
bool isRecycleBin = recycleBin && (currentGroup == recycleBin); bool isRecycleBin = recycleBin && (currentGroup == recycleBin);
bool isRecycleBinSubgroup = recycleBin && currentGroup->findGroupByUuid(recycleBin->uuid()); bool isRecycleBinSubgroup = recycleBin && currentGroup->findGroupByUuid(recycleBin->uuid());
if (inRecycleBin || isRecycleBin || isRecycleBinSubgroup || !m_db->metadata()->recycleBinEnabled()) { if (inRecycleBin || isRecycleBin || isRecycleBinSubgroup || !m_db->metadata()->recycleBinEnabled()) {
QMessageBox::StandardButton result = MessageBox::question( auto result = MessageBox::question(this,
this, tr("Delete group"),
tr("Delete group?"), tr("Do you really want to delete the group \"%1\" for good?")
tr("Do you really want to delete the group \"%1\" for good?").arg(currentGroup->name().toHtmlEscaped()), .arg(currentGroup->name().toHtmlEscaped()),
QMessageBox::Yes | QMessageBox::No); MessageBox::Delete | MessageBox::Cancel,
if (result == QMessageBox::Yes) { MessageBox::Cancel);
if (result == MessageBox::Delete) {
delete currentGroup; delete currentGroup;
} }
} else { } else {
m_db->recycleGroup(currentGroup); auto result = MessageBox::question(this,
tr("Move group to recycle bin?"),
tr("Do you really want to move the group "
"\"%1\" to the recycle bin?")
.arg(currentGroup->name().toHtmlEscaped()),
MessageBox::Move | MessageBox::Cancel,
MessageBox::Cancel);
if (result == MessageBox::Move) {
m_db->recycleGroup(currentGroup);
}
} }
} }
@ -1127,8 +1146,8 @@ bool DatabaseWidget::lock()
if (currentMode() == DatabaseWidget::Mode::EditMode) { if (currentMode() == DatabaseWidget::Mode::EditMode) {
auto result = MessageBox::question(this, tr("Lock Database?"), auto result = MessageBox::question(this, tr("Lock Database?"),
tr("You are editing an entry. Discard changes and lock anyway?"), tr("You are editing an entry. Discard changes and lock anyway?"),
QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel); MessageBox::Discard | MessageBox::Cancel, MessageBox::Cancel);
if (result == QMessageBox::Cancel) { if (result == MessageBox::Cancel) {
return false; return false;
} }
} }
@ -1146,10 +1165,10 @@ bool DatabaseWidget::lock()
msg = tr("Database was modified.\nSave changes?"); msg = tr("Database was modified.\nSave changes?");
} }
auto result = MessageBox::question(this, tr("Save changes?"), msg, auto result = MessageBox::question(this, tr("Save changes?"), msg,
QMessageBox::Yes | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Yes); MessageBox::Save | MessageBox::Discard | MessageBox::Cancel, MessageBox::Save);
if (result == QMessageBox::Yes && !m_db->save(nullptr, false, false)) { if (result == MessageBox::Save && !m_db->save(nullptr, false, false)) {
return false; return false;
} else if (result == QMessageBox::Cancel) { } else if (result == MessageBox::Cancel) {
return false; return false;
} }
} }
@ -1240,9 +1259,9 @@ void DatabaseWidget::reloadDatabaseFile()
auto result = MessageBox::question(this, auto result = MessageBox::question(this,
tr("File has changed"), tr("File has changed"),
tr("The database file has changed. Do you want to load the changes?"), tr("The database file has changed. Do you want to load the changes?"),
QMessageBox::Yes | QMessageBox::No); MessageBox::Yes | MessageBox::No);
if (result == QMessageBox::No) { if (result == MessageBox::No) {
// Notify everyone the database does not match the file // Notify everyone the database does not match the file
m_db->markAsModified(); m_db->markAsModified();
// Rewatch the database file // Rewatch the database file
@ -1259,9 +1278,10 @@ void DatabaseWidget::reloadDatabaseFile()
auto result = MessageBox::question(this, auto result = MessageBox::question(this,
tr("Merge Request"), tr("Merge Request"),
tr("The database file has changed and you have unsaved changes.\nDo you want to merge your changes?"), tr("The database file has changed and you have unsaved changes.\nDo you want to merge your changes?"),
QMessageBox::Yes | QMessageBox::No); MessageBox::Merge | MessageBox::Cancel,
MessageBox::Merge);
if (result == QMessageBox::Yes) { if (result == MessageBox::Merge) {
// Merge the old database into the new one // Merge the old database into the new one
Merger merger(m_db.data(), db.data()); Merger merger(m_db.data(), db.data());
merger.merge(); merger.merge();
@ -1447,14 +1467,14 @@ bool DatabaseWidget::save(int attempt)
if (attempt > 2 && useAtomicSaves) { if (attempt > 2 && useAtomicSaves) {
// Saving failed 3 times, issue a warning and attempt to resolve // Saving failed 3 times, issue a warning and attempt to resolve
auto choice = MessageBox::question(this, auto result = MessageBox::question(this,
tr("Disable safe saves?"), tr("Disable safe saves?"),
tr("KeePassXC has failed to save the database multiple times. " tr("KeePassXC has failed to save the database multiple times. "
"This is likely caused by file sync services holding a lock on " "This is likely caused by file sync services holding a lock on "
"the save file.\nDisable safe saves and try again?"), "the save file.\nDisable safe saves and try again?"),
QMessageBox::Yes | QMessageBox::No, MessageBox::Disable | MessageBox::Cancel,
QMessageBox::Yes); MessageBox::Disable);
if (choice == QMessageBox::Yes) { if (result == MessageBox::Disable) {
config()->set("UseAtomicSaves", false); config()->set("UseAtomicSaves", false);
return save(attempt + 1); return save(attempt + 1);
} }
@ -1529,13 +1549,13 @@ void DatabaseWidget::emptyRecycleBin()
return; return;
} }
QMessageBox::StandardButton result = auto result = MessageBox::question(this,
MessageBox::question(this, tr("Empty recycle bin?"),
tr("Empty recycle bin?"), tr("Are you sure you want to permanently delete everything from your recycle bin?"),
tr("Are you sure you want to permanently delete everything from your recycle bin?"), MessageBox::Empty | MessageBox::Cancel,
QMessageBox::Yes | QMessageBox::No); MessageBox::Cancel);
if (result == QMessageBox::Yes) { if (result == MessageBox::Empty) {
m_db->emptyRecycleBin(); m_db->emptyRecycleBin();
refreshSearch(); refreshSearch();
} }

View File

@ -416,16 +416,18 @@ void EditWidgetIcons::removeCustomIcon()
int iconUseCount = entriesWithSameIcon.size() + groupsWithSameIcon.size(); int iconUseCount = entriesWithSameIcon.size() + groupsWithSameIcon.size();
if (iconUseCount > 0) { if (iconUseCount > 0) {
QMessageBox::StandardButton ans =
MessageBox::question(this,
tr("Confirm Delete"),
tr("This icon is used by %n entry(s), and will be replaced "
"by the default icon. Are you sure you want to delete it?",
"",
iconUseCount),
QMessageBox::Yes | QMessageBox::No);
if (ans == QMessageBox::No) {
auto result = MessageBox::question(this,
tr("Confirm Delete"),
tr("This icon is used by %n entry(s), and will be replaced "
"by the default icon. Are you sure you want to delete it?",
"",
iconUseCount),
MessageBox::Delete | MessageBox::Cancel,
MessageBox::Cancel);
if (result == MessageBox::Cancel) {
// Early out, nothing is changed // Early out, nothing is changed
return; return;
} else { } else {

View File

@ -68,13 +68,14 @@ const CustomData* EditWidgetProperties::customData() const
void EditWidgetProperties::removeSelectedPluginData() void EditWidgetProperties::removeSelectedPluginData()
{ {
if (QMessageBox::Yes auto result = MessageBox::question(this,
!= MessageBox::question(this, tr("Delete plugin data?"),
tr("Delete plugin data?"), tr("Do you really want to delete the selected plugin data?\n"
tr("Do you really want to delete the selected plugin data?\n" "This may cause the affected plugins to malfunction."),
"This may cause the affected plugins to malfunction."), MessageBox::Delete | MessageBox::Cancel,
QMessageBox::Yes | QMessageBox::Cancel, MessageBox::Cancel);
QMessageBox::Cancel)) {
if (result == MessageBox::Cancel) {
return; return;
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2013 Felix Geyer <debfx@fobos.de> * Copyright (C) 2013 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,69 +18,139 @@
#include "MessageBox.h" #include "MessageBox.h"
QMessageBox::StandardButton MessageBox::m_nextAnswer(QMessageBox::NoButton); MessageBox::Button MessageBox::m_nextAnswer(MessageBox::NoButton);
QMessageBox::StandardButton MessageBox::critical(QWidget* parent, QMap<QAbstractButton*, MessageBox::Button>
const QString& title, MessageBox::m_addedButtonLookup =
const QString& text, QMap<QAbstractButton*, MessageBox::Button>();
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) QMap<MessageBox::Button, std::pair<QString, QMessageBox::ButtonRole>>
MessageBox::m_buttonDefs =
QMap<MessageBox::Button, std::pair<QString, QMessageBox::ButtonRole>>();
void MessageBox::initializeButtonDefs()
{ {
if (m_nextAnswer == QMessageBox::NoButton) { m_buttonDefs =
return QMessageBox::critical(parent, title, text, buttons, defaultButton); QMap<Button, std::pair<QString, QMessageBox::ButtonRole>>
{
// Reimplementation of Qt StandardButtons
{Ok, {stdButtonText(QMessageBox::Ok), QMessageBox::ButtonRole::AcceptRole}},
{Open, {stdButtonText(QMessageBox::Open), QMessageBox::ButtonRole::AcceptRole}},
{Save, {stdButtonText(QMessageBox::Save), QMessageBox::ButtonRole::AcceptRole}},
{Cancel, {stdButtonText(QMessageBox::Cancel), QMessageBox::ButtonRole::RejectRole}},
{Close, {stdButtonText(QMessageBox::Close), QMessageBox::ButtonRole::RejectRole}},
{Discard, {stdButtonText(QMessageBox::Discard), QMessageBox::ButtonRole::DestructiveRole}},
{Apply, {stdButtonText(QMessageBox::Apply), QMessageBox::ButtonRole::ApplyRole}},
{Reset, {stdButtonText(QMessageBox::Reset), QMessageBox::ButtonRole::ResetRole}},
{RestoreDefaults, {stdButtonText(QMessageBox::RestoreDefaults), QMessageBox::ButtonRole::ResetRole}},
{Help, {stdButtonText(QMessageBox::Help), QMessageBox::ButtonRole::HelpRole}},
{SaveAll, {stdButtonText(QMessageBox::SaveAll), QMessageBox::ButtonRole::AcceptRole}},
{Yes, {stdButtonText(QMessageBox::Yes), QMessageBox::ButtonRole::YesRole}},
{YesToAll, {stdButtonText(QMessageBox::YesToAll), QMessageBox::ButtonRole::YesRole}},
{No, {stdButtonText(QMessageBox::No), QMessageBox::ButtonRole::NoRole}},
{NoToAll, {stdButtonText(QMessageBox::NoToAll), QMessageBox::ButtonRole::NoRole}},
{Abort, {stdButtonText(QMessageBox::Abort), QMessageBox::ButtonRole::RejectRole}},
{Retry, {stdButtonText(QMessageBox::Retry), QMessageBox::ButtonRole::AcceptRole}},
{Ignore, {stdButtonText(QMessageBox::Ignore), QMessageBox::ButtonRole::AcceptRole}},
// KeePassXC Buttons
{Overwrite, {QMessageBox::tr("Overwrite"), QMessageBox::ButtonRole::AcceptRole}},
{Delete, {QMessageBox::tr("Delete"), QMessageBox::ButtonRole::AcceptRole}},
{Move, {QMessageBox::tr("Move"), QMessageBox::ButtonRole::AcceptRole}},
{Empty, {QMessageBox::tr("Empty"), QMessageBox::ButtonRole::AcceptRole}},
{Remove, {QMessageBox::tr("Remove"), QMessageBox::ButtonRole::AcceptRole}},
{Skip, {QMessageBox::tr("Skip"), QMessageBox::ButtonRole::AcceptRole}},
{Disable, {QMessageBox::tr("Disable"), QMessageBox::ButtonRole::AcceptRole}},
{Merge, {QMessageBox::tr("Merge"), QMessageBox::ButtonRole::AcceptRole}},
};
}
QString MessageBox::stdButtonText(QMessageBox::StandardButton button)
{
QMessageBox buttonHost;
return buttonHost.addButton(button)->text();
}
MessageBox::Button MessageBox::messageBox(QWidget* parent,
QMessageBox::Icon icon,
const QString& title,
const QString& text,
MessageBox::Buttons buttons,
MessageBox::Button defaultButton)
{
if (m_nextAnswer == MessageBox::NoButton) {
QMessageBox msgBox(parent);
msgBox.setIcon(icon);
msgBox.setWindowTitle(title);
msgBox.setText(text);
for (uint64_t b = First; b <= Last; b <<= 1) {
if (b & buttons) {
QString text = m_buttonDefs[static_cast<Button>(b)].first;
QMessageBox::ButtonRole role = m_buttonDefs[static_cast<Button>(b)].second;
auto buttonPtr = msgBox.addButton(text, role);
m_addedButtonLookup.insert(buttonPtr, static_cast<Button>(b));
}
}
if (defaultButton != MessageBox::NoButton) {
QList<QAbstractButton*> defPtrList = m_addedButtonLookup.keys(defaultButton);
if (defPtrList.count() > 0) {
msgBox.setDefaultButton(static_cast<QPushButton*>(defPtrList[0]));
}
}
msgBox.exec();
Button returnButton = m_addedButtonLookup[msgBox.clickedButton()];
m_addedButtonLookup.clear();
return returnButton;
} else { } else {
QMessageBox::StandardButton returnButton = m_nextAnswer; MessageBox::Button returnButton = m_nextAnswer;
m_nextAnswer = QMessageBox::NoButton; m_nextAnswer = MessageBox::NoButton;
return returnButton; return returnButton;
} }
} }
QMessageBox::StandardButton MessageBox::information(QWidget* parent, MessageBox::Button MessageBox::critical(QWidget* parent,
const QString& title, const QString& title,
const QString& text, const QString& text,
QMessageBox::StandardButtons buttons, MessageBox::Buttons buttons,
QMessageBox::StandardButton defaultButton) MessageBox::Button defaultButton)
{ {
if (m_nextAnswer == QMessageBox::NoButton) { return messageBox(parent, QMessageBox::Critical, title, text, buttons, defaultButton);
return QMessageBox::information(parent, title, text, buttons, defaultButton);
} else {
QMessageBox::StandardButton returnButton = m_nextAnswer;
m_nextAnswer = QMessageBox::NoButton;
return returnButton;
}
} }
QMessageBox::StandardButton MessageBox::question(QWidget* parent, MessageBox::Button MessageBox::information(QWidget* parent,
const QString& title, const QString& title,
const QString& text, const QString& text,
QMessageBox::StandardButtons buttons, MessageBox::Buttons buttons,
QMessageBox::StandardButton defaultButton) MessageBox::Button defaultButton)
{ {
if (m_nextAnswer == QMessageBox::NoButton) { return messageBox(parent, QMessageBox::Information, title, text, buttons, defaultButton);
return QMessageBox::question(parent, title, text, buttons, defaultButton);
} else {
QMessageBox::StandardButton returnButton = m_nextAnswer;
m_nextAnswer = QMessageBox::NoButton;
return returnButton;
}
} }
QMessageBox::StandardButton MessageBox::warning(QWidget* parent, MessageBox::Button MessageBox::question(QWidget* parent,
const QString& title, const QString& title,
const QString& text, const QString& text,
QMessageBox::StandardButtons buttons, MessageBox::Buttons buttons,
QMessageBox::StandardButton defaultButton) MessageBox::Button defaultButton)
{ {
if (m_nextAnswer == QMessageBox::NoButton) { return messageBox(parent, QMessageBox::Question, title, text, buttons, defaultButton);
return QMessageBox::warning(parent, title, text, buttons, defaultButton);
} else {
QMessageBox::StandardButton returnButton = m_nextAnswer;
m_nextAnswer = QMessageBox::NoButton;
return returnButton;
}
} }
void MessageBox::setNextAnswer(QMessageBox::StandardButton button) MessageBox::Button MessageBox::warning(QWidget* parent,
const QString& title,
const QString& text,
MessageBox::Buttons buttons,
MessageBox::Button defaultButton)
{
return messageBox(parent, QMessageBox::Warning, title, text, buttons, defaultButton);
}
void MessageBox::setNextAnswer(MessageBox::Button button)
{ {
m_nextAnswer = button; m_nextAnswer = button;
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2013 Felix Geyer <debfx@fobos.de> * Copyright (C) 2013 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,35 +20,91 @@
#define KEEPASSX_MESSAGEBOX_H #define KEEPASSX_MESSAGEBOX_H
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton>
#include <QMap>
class MessageBox class MessageBox
{ {
public: public:
static QMessageBox::StandardButton critical(QWidget* parent, enum Button : uint64_t {
const QString& title, // Reimplementation of Qt StandardButtons
const QString& text, NoButton = 0,
QMessageBox::StandardButtons buttons = QMessageBox::Ok, Ok = 1 << 1,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); Open = 1 << 2,
static QMessageBox::StandardButton information(QWidget* parent, Save = 1 << 3,
const QString& title, Cancel = 1 << 4,
const QString& text, Close = 1 << 5,
QMessageBox::StandardButtons buttons = QMessageBox::Ok, Discard = 1 << 6,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); Apply = 1 << 7,
static QMessageBox::StandardButton question(QWidget* parent, Reset = 1 << 8,
const QString& title, RestoreDefaults = 1 << 9,
const QString& text, Help = 1 << 10,
QMessageBox::StandardButtons buttons = QMessageBox::Ok, SaveAll = 1 << 11,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); Yes = 1 << 12,
static QMessageBox::StandardButton warning(QWidget* parent, YesToAll = 1 << 13,
const QString& title, No = 1 << 14,
const QString& text, NoToAll = 1 << 15,
QMessageBox::StandardButtons buttons = QMessageBox::Ok, Abort = 1 << 16,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); Retry = 1 << 17,
Ignore = 1 << 18,
static void setNextAnswer(QMessageBox::StandardButton button); // KeePassXC Buttons
Overwrite = 1 << 19,
Delete = 1 << 20,
Move = 1 << 21,
Empty = 1 << 22,
Remove = 1 << 23,
Skip = 1 << 24,
Disable = 1 << 25,
Merge = 1 << 26,
// Internal loop markers. Update Last when new KeePassXC button is added
First = Ok,
Last = Merge,
};
typedef uint64_t Buttons;
static void initializeButtonDefs();
static void setNextAnswer(Button button);
static Button critical(QWidget* parent,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
static Button information(QWidget* parent,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
static Button question(QWidget* parent,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
static Button warning(QWidget* parent,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
private: private:
static QMessageBox::StandardButton m_nextAnswer; static Button m_nextAnswer;
static QMap<QAbstractButton*, Button> m_addedButtonLookup;
static QMap<Button, std::pair<QString, QMessageBox::ButtonRole>> m_buttonDefs;
static Button messageBox(QWidget* parent,
QMessageBox::Icon icon,
const QString& title,
const QString& text,
Buttons buttons = MessageBox::Ok,
Button defaultButton = MessageBox::NoButton);
static QString stdButtonText(QMessageBox::StandardButton button);
}; };
#endif // KEEPASSX_MESSAGEBOX_H #endif // KEEPASSX_MESSAGEBOX_H

View File

@ -278,8 +278,8 @@ void CsvImportWidget::writeDatabase()
MessageBox::warning(this, MessageBox::warning(this,
tr("Error"), tr("Error"),
tr("CSV import: writer has errors:\n%1").arg(writer.errorString()), tr("CSV import: writer has errors:\n%1").arg(writer.errorString()),
QMessageBox::Ok, MessageBox::Ok,
QMessageBox::Ok); MessageBox::Ok);
} }
emit editFinished(true); emit editFinished(true);
} }

View File

@ -91,13 +91,13 @@ bool DatabaseSettingsWidgetBrowser::save()
void DatabaseSettingsWidgetBrowser::removeSelectedKey() void DatabaseSettingsWidgetBrowser::removeSelectedKey()
{ {
if (QMessageBox::Yes if (MessageBox::Yes
!= MessageBox::question(this, != MessageBox::question(this,
tr("Delete the selected key?"), tr("Delete the selected key?"),
tr("Do you really want to delete the selected key?\n" tr("Do you really want to delete the selected key?\n"
"This may prevent connection to the browser plugin."), "This may prevent connection to the browser plugin."),
QMessageBox::Yes | QMessageBox::Cancel, MessageBox::Yes | MessageBox::Cancel,
QMessageBox::Cancel)) { MessageBox::Cancel)) {
return; return;
} }
@ -156,13 +156,13 @@ void DatabaseSettingsWidgetBrowser::settingsWarning()
void DatabaseSettingsWidgetBrowser::removeSharedEncryptionKeys() void DatabaseSettingsWidgetBrowser::removeSharedEncryptionKeys()
{ {
if (QMessageBox::Yes if (MessageBox::Yes
!= MessageBox::question(this, != MessageBox::question(this,
tr("Disconnect all browsers"), tr("Disconnect all browsers"),
tr("Do you really want to disconnect all browsers?\n" tr("Do you really want to disconnect all browsers?\n"
"This may prevent connection to the browser plugin."), "This may prevent connection to the browser plugin."),
QMessageBox::Yes | QMessageBox::Cancel, MessageBox::Yes | MessageBox::Cancel,
QMessageBox::Cancel)) { MessageBox::Cancel)) {
return; return;
} }
@ -174,10 +174,10 @@ void DatabaseSettingsWidgetBrowser::removeSharedEncryptionKeys()
} }
if (keysToRemove.isEmpty()) { if (keysToRemove.isEmpty()) {
QMessageBox::information(this, MessageBox::information(this,
tr("KeePassXC: No keys found"), tr("KeePassXC: No keys found"),
tr("No shared encryption keys found in KeePassXC settings."), tr("No shared encryption keys found in KeePassXC settings."),
QMessageBox::Ok); MessageBox::Ok);
return; return;
} }
@ -186,21 +186,21 @@ void DatabaseSettingsWidgetBrowser::removeSharedEncryptionKeys()
} }
const int count = keysToRemove.count(); const int count = keysToRemove.count();
QMessageBox::information(this, MessageBox::information(this,
tr("KeePassXC: Removed keys from database"), tr("KeePassXC: Removed keys from database"),
tr("Successfully removed %n encryption key(s) from KeePassXC settings.", "", count), tr("Successfully removed %n encryption key(s) from KeePassXC settings.", "", count),
QMessageBox::Ok); MessageBox::Ok);
} }
void DatabaseSettingsWidgetBrowser::removeStoredPermissions() void DatabaseSettingsWidgetBrowser::removeStoredPermissions()
{ {
if (QMessageBox::Yes if (MessageBox::Yes
!= MessageBox::question(this, != MessageBox::question(this,
tr("Forget all site-specific settings on entries"), tr("Forget all site-specific settings on entries"),
tr("Do you really want forget all site-specific settings on every entry?\n" tr("Do you really want forget all site-specific settings on every entry?\n"
"Permissions to access entries will be revoked."), "Permissions to access entries will be revoked."),
QMessageBox::Yes | QMessageBox::Cancel, MessageBox::Yes | MessageBox::Cancel,
QMessageBox::Cancel)) { MessageBox::Cancel)) {
return; return;
} }
@ -226,28 +226,28 @@ void DatabaseSettingsWidgetBrowser::removeStoredPermissions()
progress.reset(); progress.reset();
if (counter > 0) { if (counter > 0) {
QMessageBox::information(this, MessageBox::information(this,
tr("KeePassXC: Removed permissions"), tr("KeePassXC: Removed permissions"),
tr("Successfully removed permissions from %n entry(s).", "", counter), tr("Successfully removed permissions from %n entry(s).", "", counter),
QMessageBox::Ok); MessageBox::Ok);
} else { } else {
QMessageBox::information(this, MessageBox::information(this,
tr("KeePassXC: No entry with permissions found!"), tr("KeePassXC: No entry with permissions found!"),
tr("The active database does not contain an entry with permissions."), tr("The active database does not contain an entry with permissions."),
QMessageBox::Ok); MessageBox::Ok);
} }
} }
void DatabaseSettingsWidgetBrowser::convertAttributesToCustomData() void DatabaseSettingsWidgetBrowser::convertAttributesToCustomData()
{ {
if (QMessageBox::Yes if (MessageBox::Yes
!= MessageBox::question( != MessageBox::question(
this, this,
tr("Move KeePassHTTP attributes to custom data"), tr("Move KeePassHTTP attributes to custom data"),
tr("Do you really want to move all legacy browser integration data to the latest standard?\n" tr("Do you really want to move all legacy browser integration data to the latest standard?\n"
"This is necessary to maintain compatibility with the browser plugin."), "This is necessary to maintain compatibility with the browser plugin."),
QMessageBox::Yes | QMessageBox::Cancel, MessageBox::Yes | MessageBox::Cancel,
QMessageBox::Cancel)) { MessageBox::Cancel)) {
return; return;
} }

View File

@ -172,8 +172,8 @@ bool DatabaseSettingsWidgetMasterKey::save()
MessageBox::critical(this, MessageBox::critical(this,
tr("No encryption key added"), tr("No encryption key added"),
tr("You must add at least one encryption key to secure your database!"), tr("You must add at least one encryption key to secure your database!"),
QMessageBox::Ok, MessageBox::Ok,
QMessageBox::Ok); MessageBox::Ok);
return false; return false;
} }
@ -183,9 +183,9 @@ bool DatabaseSettingsWidgetMasterKey::save()
tr("WARNING! You have not set a password. Using a database without " tr("WARNING! You have not set a password. Using a database without "
"a password is strongly discouraged!\n\n" "a password is strongly discouraged!\n\n"
"Are you sure you want to continue without a password?"), "Are you sure you want to continue without a password?"),
QMessageBox::Yes | QMessageBox::Cancel, MessageBox::Yes | MessageBox::Cancel,
QMessageBox::Cancel); MessageBox::Cancel);
if (answer != QMessageBox::Yes) { if (answer != MessageBox::Yes) {
return false; return false;
} }
} }
@ -221,7 +221,7 @@ bool DatabaseSettingsWidgetMasterKey::addToCompositeKey(KeyComponentWidget* widg
if (widget->visiblePage() == KeyComponentWidget::Edit) { if (widget->visiblePage() == KeyComponentWidget::Edit) {
QString error = tr("Unknown error"); QString error = tr("Unknown error");
if (!widget->validate(error) || !widget->addToCompositeKey(newKey)) { if (!widget->validate(error) || !widget->addToCompositeKey(newKey)) {
QMessageBox::critical(this, tr("Failed to change master key"), error, QMessageBox::Ok); MessageBox::critical(this, tr("Failed to change master key"), error, MessageBox::Ok);
return false; return false;
} }
} else if (widget->visiblePage() == KeyComponentWidget::LeaveOrRemove) { } else if (widget->visiblePage() == KeyComponentWidget::LeaveOrRemove) {
@ -238,7 +238,7 @@ bool DatabaseSettingsWidgetMasterKey::addToCompositeKey(KeyComponentWidget* widg
if (widget->visiblePage() == KeyComponentWidget::Edit) { if (widget->visiblePage() == KeyComponentWidget::Edit) {
QString error = tr("Unknown error"); QString error = tr("Unknown error");
if (!widget->validate(error) || !widget->addToCompositeKey(newKey)) { if (!widget->validate(error) || !widget->addToCompositeKey(newKey)) {
QMessageBox::critical(this, tr("Failed to change master key"), error, QMessageBox::Ok); MessageBox::critical(this, tr("Failed to change master key"), error, MessageBox::Ok);
return false; return false;
} }
} else if (widget->visiblePage() == KeyComponentWidget::LeaveOrRemove) { } else if (widget->visiblePage() == KeyComponentWidget::LeaveOrRemove) {

View File

@ -821,9 +821,9 @@ bool EditEntryWidget::commitEntry()
auto answer = MessageBox::question(this, auto answer = MessageBox::question(this,
tr("Apply generated password?"), tr("Apply generated password?"),
tr("Do you want to apply the generated password to this entry?"), tr("Do you want to apply the generated password to this entry?"),
QMessageBox::Yes | QMessageBox::No, MessageBox::Yes | MessageBox::No,
QMessageBox::Yes); MessageBox::Yes);
if (answer == QMessageBox::Yes) { if (answer == MessageBox::Yes) {
m_mainUi->passwordGenerator->applyPassword(); m_mainUi->passwordGenerator->applyPassword();
} }
} }
@ -947,13 +947,13 @@ void EditEntryWidget::cancel()
auto result = MessageBox::question(this, auto result = MessageBox::question(this,
QString(), QString(),
tr("Entry has unsaved changes"), tr("Entry has unsaved changes"),
QMessageBox::Cancel | QMessageBox::Save | QMessageBox::Discard, MessageBox::Cancel | MessageBox::Save | MessageBox::Discard,
QMessageBox::Cancel); MessageBox::Cancel);
if (result == QMessageBox::Cancel) { if (result == MessageBox::Cancel) {
m_mainUi->passwordGenerator->reset(); m_mainUi->passwordGenerator->reset();
return; return;
} }
if (result == QMessageBox::Save) { if (result == MessageBox::Save) {
commitEntry(); commitEntry();
m_saved = true; m_saved = true;
} }
@ -1058,11 +1058,14 @@ void EditEntryWidget::removeCurrentAttribute()
QModelIndex index = m_advancedUi->attributesView->currentIndex(); QModelIndex index = m_advancedUi->attributesView->currentIndex();
if (index.isValid()) { if (index.isValid()) {
if (MessageBox::question(this,
tr("Confirm Remove"), auto result = MessageBox::question(this,
tr("Are you sure you want to remove this attribute?"), tr("Confirm Removal"),
QMessageBox::Yes | QMessageBox::No) tr("Are you sure you want to remove this attribute?"),
== QMessageBox::Yes) { MessageBox::Remove | MessageBox::Cancel,
MessageBox::Cancel);
if (result == MessageBox::Remove) {
m_entryAttributes->remove(m_attributesModel->keyByIndex(index)); m_entryAttributes->remove(m_attributesModel->keyByIndex(index));
setUnsavedChanges(true); setUnsavedChanges(true);
} }

View File

@ -165,10 +165,13 @@ void EntryAttachmentsWidget::removeSelectedAttachments()
return; return;
} }
const QString question = tr("Are you sure you want to remove %n attachment(s)?", "", indexes.count()); auto result = MessageBox::question(this,
QMessageBox::StandardButton answer = tr("Confirm remove"),
MessageBox::question(this, tr("Confirm remove"), question, QMessageBox::Yes | QMessageBox::No); tr("Are you sure you want to remove %n attachment(s)?", "", indexes.count()),
if (answer == QMessageBox::Yes) { MessageBox::Remove | MessageBox::Cancel,
MessageBox::Cancel);
if (result == MessageBox::Remove) {
QStringList keys; QStringList keys;
for (const QModelIndex& index : indexes) { for (const QModelIndex& index : indexes) {
keys.append(m_attachmentsModel->keyByIndex(index)); keys.append(m_attachmentsModel->keyByIndex(index));
@ -211,15 +214,24 @@ void EntryAttachmentsWidget::saveSelectedAttachments()
const QString attachmentPath = saveDir.absoluteFilePath(filename); const QString attachmentPath = saveDir.absoluteFilePath(filename);
if (QFileInfo::exists(attachmentPath)) { if (QFileInfo::exists(attachmentPath)) {
const QString question(
MessageBox::Buttons buttons = MessageBox::Overwrite | MessageBox::Cancel;
if (indexes.length() > 1) {
buttons |= MessageBox::Skip;
}
const QString questionText(
tr("Are you sure you want to overwrite the existing file \"%1\" with the attachment?")); tr("Are you sure you want to overwrite the existing file \"%1\" with the attachment?"));
auto answer = MessageBox::question(this,
auto result = MessageBox::question(this,
tr("Confirm overwrite"), tr("Confirm overwrite"),
question.arg(filename), questionText.arg(filename),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); buttons,
if (answer == QMessageBox::No) { MessageBox::Cancel);
if (result == MessageBox::Skip) {
continue; continue;
} else if (answer == QMessageBox::Cancel) { } else if (result == MessageBox::Cancel) {
return; return;
} }
} }

View File

@ -148,7 +148,7 @@ void TestAutoType::testSingleAutoType()
void TestAutoType::testGlobalAutoTypeWithNoMatch() void TestAutoType::testGlobalAutoTypeWithNoMatch()
{ {
m_test->setActiveWindowTitle("nomatch"); m_test->setActiveWindowTitle("nomatch");
MessageBox::setNextAnswer(QMessageBox::Ok); MessageBox::setNextAnswer(MessageBox::Ok);
m_autoType->performGlobalAutoType(m_dbList); m_autoType->performGlobalAutoType(m_dbList);
QCOMPARE(m_test->actionChars(), QString()); QCOMPARE(m_test->actionChars(), QString());
@ -195,7 +195,7 @@ void TestAutoType::testGlobalAutoTypeUrlSubdomainMatch()
void TestAutoType::testGlobalAutoTypeTitleMatchDisabled() void TestAutoType::testGlobalAutoTypeTitleMatchDisabled()
{ {
m_test->setActiveWindowTitle("An Entry Title!"); m_test->setActiveWindowTitle("An Entry Title!");
MessageBox::setNextAnswer(QMessageBox::Ok); MessageBox::setNextAnswer(MessageBox::Ok);
m_autoType->performGlobalAutoType(m_dbList); m_autoType->performGlobalAutoType(m_dbList);
QCOMPARE(m_test->actionChars(), QString()); QCOMPARE(m_test->actionChars(), QString());
@ -379,4 +379,4 @@ void TestAutoType::testAutoTypeEffectiveSequences()
QCOMPARE(entry5->effectiveAutoTypeSequence(), QString()); QCOMPARE(entry5->effectiveAutoTypeSequence(), QString());
QCOMPARE(entry6->defaultAutoTypeSequence(), sequenceOrphan); QCOMPARE(entry6->defaultAutoTypeSequence(), sequenceOrphan);
QCOMPARE(entry6->effectiveAutoTypeSequence(), QString()); QCOMPARE(entry6->effectiveAutoTypeSequence(), QString());
} }

View File

@ -134,10 +134,10 @@ void TestGui::cleanup()
{ {
// DO NOT save the database // DO NOT save the database
m_db->markAsClean(); m_db->markAsClean();
MessageBox::setNextAnswer(QMessageBox::No); MessageBox::setNextAnswer(MessageBox::No);
triggerAction("actionDatabaseClose"); triggerAction("actionDatabaseClose");
QApplication::processEvents(); QApplication::processEvents();
MessageBox::setNextAnswer(QMessageBox::NoButton); MessageBox::setNextAnswer(MessageBox::NoButton);
if (m_dbWidget) { if (m_dbWidget) {
delete m_dbWidget; delete m_dbWidget;
@ -204,7 +204,7 @@ void TestGui::testCreateDatabase()
QCOMPARE(m_db->key()->rawKey(), compositeKey->rawKey()); QCOMPARE(m_db->key()->rawKey(), compositeKey->rawKey());
// close the new database // close the new database
MessageBox::setNextAnswer(QMessageBox::No); MessageBox::setNextAnswer(MessageBox::No);
triggerAction("actionDatabaseClose"); triggerAction("actionDatabaseClose");
} }
@ -338,7 +338,7 @@ void TestGui::testAutoreloadDatabase()
mergeDbFile.close(); mergeDbFile.close();
// Test accepting new file in autoreload // Test accepting new file in autoreload
MessageBox::setNextAnswer(QMessageBox::Yes); MessageBox::setNextAnswer(MessageBox::Yes);
// Overwrite the current database with the temp data // Overwrite the current database with the temp data
QVERIFY(m_dbFile->open()); QVERIFY(m_dbFile->open());
QVERIFY(m_dbFile->write(unmodifiedMergeDatabase, static_cast<qint64>(unmodifiedMergeDatabase.size()))); QVERIFY(m_dbFile->write(unmodifiedMergeDatabase, static_cast<qint64>(unmodifiedMergeDatabase.size())));
@ -356,7 +356,7 @@ void TestGui::testAutoreloadDatabase()
init(); init();
// Test rejecting new file in autoreload // Test rejecting new file in autoreload
MessageBox::setNextAnswer(QMessageBox::No); MessageBox::setNextAnswer(MessageBox::No);
// Overwrite the current temp database with a new file // Overwrite the current temp database with a new file
m_dbFile->open(); m_dbFile->open();
QVERIFY(m_dbFile->write(unmodifiedMergeDatabase, static_cast<qint64>(unmodifiedMergeDatabase.size()))); QVERIFY(m_dbFile->write(unmodifiedMergeDatabase, static_cast<qint64>(unmodifiedMergeDatabase.size())));
@ -380,7 +380,7 @@ void TestGui::testAutoreloadDatabase()
testEditEntry(); testEditEntry();
// This is saying yes to merging the entries // This is saying yes to merging the entries
MessageBox::setNextAnswer(QMessageBox::Yes); MessageBox::setNextAnswer(MessageBox::Yes);
// Overwrite the current database with the temp data // Overwrite the current database with the temp data
QVERIFY(m_dbFile->open()); QVERIFY(m_dbFile->open());
QVERIFY(m_dbFile->write(unmodifiedMergeDatabase, static_cast<qint64>(unmodifiedMergeDatabase.size()))); QVERIFY(m_dbFile->write(unmodifiedMergeDatabase, static_cast<qint64>(unmodifiedMergeDatabase.size())));
@ -604,7 +604,7 @@ void TestGui::testAddEntry()
// Add entry "something 5" but click cancel button (does NOT add entry) // Add entry "something 5" but click cancel button (does NOT add entry)
QTest::mouseClick(entryNewWidget, Qt::LeftButton); QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QTest::keyClicks(titleEdit, "something 5"); QTest::keyClicks(titleEdit, "something 5");
MessageBox::setNextAnswer(QMessageBox::Discard); MessageBox::setNextAnswer(MessageBox::Discard);
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Cancel), Qt::LeftButton); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Cancel), Qt::LeftButton);
QApplication::processEvents(); QApplication::processEvents();
@ -944,7 +944,7 @@ void TestGui::testDeleteEntry()
QVERIFY(entryDeleteWidget->isEnabled()); QVERIFY(entryDeleteWidget->isEnabled());
QVERIFY(!m_db->metadata()->recycleBin()); QVERIFY(!m_db->metadata()->recycleBin());
MessageBox::setNextAnswer(QMessageBox::Yes); MessageBox::setNextAnswer(MessageBox::Move);
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton); QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
QCOMPARE(entryView->model()->rowCount(), 3); QCOMPARE(entryView->model()->rowCount(), 3);
@ -954,12 +954,12 @@ void TestGui::testDeleteEntry()
clickIndex(entryView->model()->index(2, 1), entryView, Qt::LeftButton, Qt::ControlModifier); clickIndex(entryView->model()->index(2, 1), entryView, Qt::LeftButton, Qt::ControlModifier);
QCOMPARE(entryView->selectionModel()->selectedRows().size(), 2); QCOMPARE(entryView->selectionModel()->selectedRows().size(), 2);
MessageBox::setNextAnswer(QMessageBox::No); MessageBox::setNextAnswer(MessageBox::Cancel);
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton); QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
QCOMPARE(entryView->model()->rowCount(), 3); QCOMPARE(entryView->model()->rowCount(), 3);
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 1); QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 1);
MessageBox::setNextAnswer(QMessageBox::Yes); MessageBox::setNextAnswer(MessageBox::Move);
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton); QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
QCOMPARE(entryView->model()->rowCount(), 1); QCOMPARE(entryView->model()->rowCount(), 1);
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 3); QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 3);
@ -972,19 +972,19 @@ void TestGui::testDeleteEntry()
QCOMPARE(groupView->currentGroup()->name(), m_db->metadata()->recycleBin()->name()); QCOMPARE(groupView->currentGroup()->name(), m_db->metadata()->recycleBin()->name());
clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton); clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton);
MessageBox::setNextAnswer(QMessageBox::No); MessageBox::setNextAnswer(MessageBox::Cancel);
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton); QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
QCOMPARE(entryView->model()->rowCount(), 3); QCOMPARE(entryView->model()->rowCount(), 3);
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 3); QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 3);
MessageBox::setNextAnswer(QMessageBox::Yes); MessageBox::setNextAnswer(MessageBox::Delete);
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton); QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
QCOMPARE(entryView->model()->rowCount(), 2); QCOMPARE(entryView->model()->rowCount(), 2);
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 2); QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 2);
clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton); clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton);
clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton, Qt::ControlModifier); clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton, Qt::ControlModifier);
MessageBox::setNextAnswer(QMessageBox::Yes); MessageBox::setNextAnswer(MessageBox::Delete);
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton); QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
QCOMPARE(entryView->model()->rowCount(), 0); QCOMPARE(entryView->model()->rowCount(), 0);
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 0); QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 0);
@ -1183,7 +1183,7 @@ void TestGui::testKeePass1Import()
QTRY_COMPARE(m_tabWidget->tabName(m_tabWidget->currentIndex()), QString("basic [New Database]*")); QTRY_COMPARE(m_tabWidget->tabName(m_tabWidget->currentIndex()), QString("basic [New Database]*"));
// Close the KeePass1 Database // Close the KeePass1 Database
MessageBox::setNextAnswer(QMessageBox::No); MessageBox::setNextAnswer(MessageBox::No);
triggerAction("actionDatabaseClose"); triggerAction("actionDatabaseClose");
QApplication::processEvents(); QApplication::processEvents();
} }
@ -1192,7 +1192,7 @@ void TestGui::testDatabaseLocking()
{ {
QString origDbName = m_tabWidget->tabText(0); QString origDbName = m_tabWidget->tabText(0);
MessageBox::setNextAnswer(QMessageBox::Cancel); MessageBox::setNextAnswer(MessageBox::Cancel);
triggerAction("actionLockDatabases"); triggerAction("actionLockDatabases");
QCOMPARE(m_tabWidget->tabName(0), origDbName + " [Locked]"); QCOMPARE(m_tabWidget->tabName(0), origDbName + " [Locked]");
@ -1248,7 +1248,7 @@ void TestGui::testDragAndDropKdbxFiles()
QCOMPARE(m_tabWidget->count(), openedDatabasesCount + 1); QCOMPARE(m_tabWidget->count(), openedDatabasesCount + 1);
MessageBox::setNextAnswer(QMessageBox::No); MessageBox::setNextAnswer(MessageBox::No);
triggerAction("actionDatabaseClose"); triggerAction("actionDatabaseClose");
QTRY_COMPARE(m_tabWidget->count(), openedDatabasesCount); QTRY_COMPARE(m_tabWidget->count(), openedDatabasesCount);