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

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