mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-04-06 05:57:37 +03:00
Merge branch 'develop'
Conflicts: src/core/Tools.cpp src/sshagent/SSHAgent.cpp
This commit is contained in:
commit
21de6f6163
57 changed files with 1296 additions and 395 deletions
|
@ -131,7 +131,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent)
|
|||
m_searchingLabel->setStyleSheet("color: rgb(0, 0, 0);"
|
||||
"background-color: rgb(255, 253, 160);"
|
||||
"border: 2px solid rgb(190, 190, 190);"
|
||||
"border-radius: 2px;");
|
||||
"border-radius: 4px;");
|
||||
m_searchingLabel->setVisible(false);
|
||||
|
||||
m_previewView->hide();
|
||||
|
@ -425,61 +425,117 @@ void DatabaseWidget::setupTotp()
|
|||
setupTotpDialog->open();
|
||||
}
|
||||
|
||||
void DatabaseWidget::deleteEntries()
|
||||
void DatabaseWidget::deleteSelectedEntries()
|
||||
{
|
||||
const QModelIndexList selected = m_entryView->selectionModel()->selectedRows();
|
||||
|
||||
Q_ASSERT(!selected.isEmpty());
|
||||
if (selected.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get all entry pointers as the indexes change when removing multiple entries
|
||||
// Resolve entries from the selection model
|
||||
QList<Entry*> selectedEntries;
|
||||
for (const QModelIndex& index : selected) {
|
||||
selectedEntries.append(m_entryView->entryFromIndex(index));
|
||||
}
|
||||
|
||||
// Confirm entry removal before moving forward
|
||||
auto* recycleBin = m_db->metadata()->recycleBin();
|
||||
bool inRecycleBin = recycleBin && recycleBin->findEntryByUuid(selectedEntries.first()->uuid());
|
||||
if (inRecycleBin || !m_db->metadata()->recycleBinEnabled()) {
|
||||
QString prompt;
|
||||
if (selected.size() == 1) {
|
||||
prompt = tr("Do you really want to delete the entry \"%1\" for good?")
|
||||
.arg(selectedEntries.first()->title().toHtmlEscaped());
|
||||
} else {
|
||||
prompt = tr("Do you really want to delete %n entry(s) for good?", "", selected.size());
|
||||
bool permanent = (recycleBin && recycleBin->findEntryByUuid(selectedEntries.first()->uuid()))
|
||||
|| !m_db->metadata()->recycleBinEnabled();
|
||||
|
||||
if (!confirmDeleteEntries(selectedEntries, permanent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find references to selected entries and prompt for direction if necessary
|
||||
auto it = selectedEntries.begin();
|
||||
while (it != selectedEntries.end()) {
|
||||
auto references = m_db->rootGroup()->referencesRecursive(*it);
|
||||
if (!references.isEmpty()) {
|
||||
// Ignore references that are selected for deletion
|
||||
for (auto* entry : selectedEntries) {
|
||||
references.removeAll(entry);
|
||||
}
|
||||
|
||||
if (!references.isEmpty()) {
|
||||
// Prompt for reference handling
|
||||
auto result = MessageBox::question(
|
||||
this,
|
||||
tr("Replace references to entry?"),
|
||||
tr("Entry \"%1\" has %2 reference(s). "
|
||||
"Do you want to overwrite references with values, skip this entry, or delete anyway?", "",
|
||||
references.size())
|
||||
.arg((*it)->title().toHtmlEscaped())
|
||||
.arg(references.size()),
|
||||
MessageBox::Overwrite | MessageBox::Skip | MessageBox::Delete,
|
||||
MessageBox::Overwrite);
|
||||
|
||||
if (result == MessageBox::Overwrite) {
|
||||
for (auto* entry : references) {
|
||||
entry->replaceReferencesWithValues(*it);
|
||||
}
|
||||
} else if (result == MessageBox::Skip) {
|
||||
it = selectedEntries.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton result = MessageBox::question(
|
||||
this, tr("Delete entry(s)?", "", selected.size()), prompt, QMessageBox::Yes | QMessageBox::No);
|
||||
it++;
|
||||
}
|
||||
|
||||
if (result == QMessageBox::Yes) {
|
||||
for (Entry* entry : asConst(selectedEntries)) {
|
||||
delete entry;
|
||||
}
|
||||
refreshSearch();
|
||||
if (permanent) {
|
||||
for (auto* entry : asConst(selectedEntries)) {
|
||||
delete entry;
|
||||
}
|
||||
} else {
|
||||
QString prompt;
|
||||
if (selected.size() == 1) {
|
||||
prompt = tr("Do you really want to move entry \"%1\" to the recycle bin?")
|
||||
.arg(selectedEntries.first()->title().toHtmlEscaped());
|
||||
} else {
|
||||
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);
|
||||
|
||||
if (result == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Entry* entry : asConst(selectedEntries)) {
|
||||
for (auto* entry : asConst(selectedEntries)) {
|
||||
m_db->recycleEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
refreshSearch();
|
||||
}
|
||||
|
||||
bool DatabaseWidget::confirmDeleteEntries(QList<Entry*> entries, bool permanent)
|
||||
{
|
||||
if (entries.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permanent) {
|
||||
QString prompt;
|
||||
if (entries.size() == 1) {
|
||||
prompt = tr("Do you really want to delete the entry \"%1\" for good?")
|
||||
.arg(entries.first()->title().toHtmlEscaped());
|
||||
} else {
|
||||
prompt = tr("Do you really want to delete %n entry(s) for good?", "", entries.size());
|
||||
}
|
||||
|
||||
auto answer = MessageBox::question(this,
|
||||
tr("Delete entry(s)?", "", entries.size()),
|
||||
prompt,
|
||||
MessageBox::Delete | MessageBox::Cancel,
|
||||
MessageBox::Cancel);
|
||||
|
||||
return answer == MessageBox::Delete;
|
||||
} else {
|
||||
QString prompt;
|
||||
if (entries.size() == 1) {
|
||||
prompt = tr("Do you really want to move entry \"%1\" to the recycle bin?")
|
||||
.arg(entries.first()->title().toHtmlEscaped());
|
||||
} else {
|
||||
prompt = tr("Do you really want to move %n entry(s) to the recycle bin?", "", entries.size());
|
||||
}
|
||||
|
||||
auto answer = MessageBox::question(this,
|
||||
tr("Move entry(s) to recycle bin?", "", entries.size()),
|
||||
prompt,
|
||||
MessageBox::Move | MessageBox::Cancel,
|
||||
MessageBox::Cancel);
|
||||
|
||||
return answer == MessageBox::Move;
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWidget::setFocus()
|
||||
|
@ -649,16 +705,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1126,8 +1193,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;
|
||||
}
|
||||
}
|
||||
|
@ -1145,10 +1212,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;
|
||||
}
|
||||
}
|
||||
|
@ -1202,9 +1269,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
|
||||
|
@ -1221,9 +1288,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();
|
||||
|
@ -1409,14 +1477,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);
|
||||
}
|
||||
|
@ -1491,13 +1559,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();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue