Prevent moving items that exist in the targetDb

- The user is presented with an in error message if it is the case.
- The recycler is prevented from being moved away.
This commit is contained in:
vuurvlieg 2024-04-02 17:14:43 +02:00
parent cacc63ef0f
commit 58197ab4b5
3 changed files with 91 additions and 28 deletions

View File

@ -708,6 +708,10 @@ QList<DatabaseWidget*> MainWindow::getOpenDatabases()
return dbWidgets;
}
DatabaseWidget* MainWindow::currentDatabaseWidget() {
return m_ui->tabWidget->currentDatabaseWidget();
}
void MainWindow::showErrorMessage(const QString& message)
{
m_ui->globalMessageWidget->showMessage(message, MessageWidget::Error);

View File

@ -52,6 +52,7 @@ public:
~MainWindow() override;
QList<DatabaseWidget*> getOpenDatabases();
DatabaseWidget* currentDatabaseWidget();
void restoreConfigState();
void setAllowScreenCapture(bool state);

View File

@ -25,6 +25,7 @@
#include "core/Tools.h"
#include "gui/DatabaseIcons.h"
#include "gui/Icons.h"
#include "gui/MainWindow.h"
#include "keeshare/KeeShare.h"
GroupModel::GroupModel(Database* db, QObject* parent)
@ -204,9 +205,11 @@ bool GroupModel::dropMimeData(const QMimeData* data,
if (action == Qt::IgnoreAction) {
return true;
} else if (action != Qt::MoveAction && action != Qt::CopyAction && action != ::Qt::LinkAction) {
return false;
}
if (!data || !(action & (Qt::MoveAction | Qt::CopyAction | Qt::LinkAction)) || !parent.isValid()) {
if (!data || !parent.isValid()) {
return false;
}
@ -223,6 +226,12 @@ bool GroupModel::dropMimeData(const QMimeData* data,
row = rowCount(parent);
}
auto showErrorMessage = [](const QString& errorMessage){
if(auto dbWidget = getMainWindow()->currentDatabaseWidget()) {
dbWidget->showErrorMessage(errorMessage);
}
};
// decode and insert
QByteArray encoded = data->data(isGroup ? types.at(0) : types.at(1));
QDataStream stream(&encoded, QIODevice::ReadOnly);
@ -234,17 +243,17 @@ bool GroupModel::dropMimeData(const QMimeData* data,
QUuid groupUuid;
stream >> dbUuid >> groupUuid;
Database* db = Database::databaseByUuid(dbUuid);
if (!db) {
Database* sourceDb = Database::databaseByUuid(dbUuid);
if (!sourceDb) {
return false;
}
Group* dragGroup = db->rootGroup()->findGroupByUuid(groupUuid);
if (!dragGroup || !db->rootGroup()->findGroupByUuid(dragGroup->uuid()) || dragGroup == db->rootGroup()) {
Group* dragGroup = sourceDb->rootGroup()->findGroupByUuid(groupUuid);
if (!dragGroup || dragGroup == sourceDb->rootGroup()) {
return false;
}
if (dragGroup == parentGroup || dragGroup->findGroupByUuid(parentGroup->uuid())) {
if (dragGroup == parentGroup || parentGroup->isDescendantOf(dragGroup)) {
return false;
}
@ -252,25 +261,55 @@ bool GroupModel::dropMimeData(const QMimeData* data,
row--;
}
Database* sourceDb = dragGroup->database();
Database* targetDb = parentGroup->database();
Group* group = dragGroup;
if (sourceDb != targetDb) {
targetDb->metadata()->copyCustomIcons(group->customIconsRecursive(), sourceDb->metadata());
if (action == Qt::MoveAction || action == Qt::LinkAction) { // clang-format off
Group* binGroup = sourceDb->metadata()->recycleBin();
if(binGroup && binGroup->uuid() == dragGroup->uuid()) {
showErrorMessage(tr("Move error: \"%1\" group cannot be moved").arg(binGroup->name()));
return true;
}
// Collect all UUID(s) or short-circuit when UUID is deleted in targetDb
QSet<QUuid> uuidSet;
bool complexMove = group->walk(true,
[&](const Group* group) {
uuidSet.insert(group->uuid());
return targetDb->containsDeletedObject(group->uuid());
},
[&](const Entry* entry) {
uuidSet.insert(entry->uuid());
return targetDb->containsDeletedObject(entry->uuid());
}
);
// Unable to handle complex moves until the Merger interface supports single group/entry merging
if (complexMove || targetDb->rootGroup()->walk(true,
[&](const Group* group)-> bool {
return uuidSet.contains(group->uuid());
},
[&](const Entry* entry) -> bool {
return uuidSet.contains(entry->uuid());
}
)) {
showErrorMessage(tr("Move error: the group or one of it's descendants is already present in this database"));
return true;
}
} // clang-format on
if (action == Qt::MoveAction) { // -- Tracked move
if (action == Qt::MoveAction) {
// -- Tracked move
// A clone with new UUID but original CreationTime
group = dragGroup->clone(Entry::CloneFlags(Entry::CloneCopy & ~Entry::CloneResetCreationTime),
Group::CloneFlags(Group::CloneCopy & ~Group::CloneResetCreationTime));
// Original UUID is marked as deleted to remove it from dbs that merge with this one
// Original UUID is marked as deleted to propagate the move to dbs that merge with this one
delete dragGroup;
} else if (action == Qt::LinkAction) {
// -- Untracked move
} else if (action == Qt::LinkAction) { // -- Untracked move
QList<DeletedObject> deletedObjects(sourceDb->deletedObjects());
// Exact copy of original
group = dragGroup->clone(Entry::CloneExactCopy, Group::CloneExactCopy);
delete dragGroup;
// Unmark UUID(s) as deleted by restoring the previous list
@ -278,6 +317,8 @@ bool GroupModel::dropMimeData(const QMimeData* data,
} else {
group = dragGroup->clone(Entry::CloneCopy);
}
targetDb->metadata()->copyCustomIcons(group->customIconsRecursive(), sourceDb->metadata());
} else if (action == Qt::CopyAction) {
group = dragGroup->clone(Entry::CloneCopy);
}
@ -288,39 +329,49 @@ bool GroupModel::dropMimeData(const QMimeData* data,
return false;
}
int entries{0}, entriesNotMoved{0};
while (!stream.atEnd()) {
QUuid dbUuid;
QUuid entryUuid;
stream >> dbUuid >> entryUuid;
++entries;
Database* db = Database::databaseByUuid(dbUuid);
if (!db) {
Database* sourceDb = Database::databaseByUuid(dbUuid);
if (!sourceDb) {
continue;
}
Entry* dragEntry = db->rootGroup()->findEntryByUuid(entryUuid);
if (!dragEntry || !db->rootGroup()->findEntryByUuid(dragEntry->uuid())) {
Entry* dragEntry = sourceDb->rootGroup()->findEntryByUuid(entryUuid);
if (!dragEntry) {
continue;
}
Database* sourceDb = dragEntry->group()->database();
Database* targetDb = parentGroup->database();
Entry* entry = dragEntry;
if (sourceDb != targetDb) {
targetDb->metadata()->copyCustomIcon(entry->iconUuid(), sourceDb->metadata());
if (action == Qt::MoveAction || action == Qt::LinkAction) { // clang-format off
// Unable to handle complex moves until the Merger interface supports single group/entry merging
if (targetDb->containsDeletedObject(dragEntry->uuid()) ||
targetDb->rootGroup()->walkEntries([=](const Entry* entry) {
return dragEntry->uuid() == entry->uuid();
}
)) {
++entriesNotMoved;
continue;
}
} // clang-format on
if (action == Qt::MoveAction) { // -- Tracked move
if (action == Qt::MoveAction) {
// -- Tracked move
// A clone with new UUID but original CreationTime
entry = dragEntry->clone(Entry::CloneFlags(Entry::CloneCopy & ~Entry::CloneResetCreationTime));
// Original UUID is marked as deleted to remove it from dbs that merge with this one
// Original UUID is marked as deleted to propagate the move to dbs that merge with this one
delete dragEntry;
} else if (action == Qt::LinkAction) {
// -- Untracked move
} else if (action == Qt::LinkAction) { // -- Untracked move
QList<DeletedObject> deletedObjects(sourceDb->deletedObjects());
// Exact copy of original
entry = dragEntry->clone(Entry::CloneExactCopy);
delete dragEntry;
// Unmark UUID as deleted by restoring the previous list
@ -328,12 +379,19 @@ bool GroupModel::dropMimeData(const QMimeData* data,
} else {
entry = dragEntry->clone(Entry::CloneCopy);
}
targetDb->metadata()->copyCustomIcon(entry->iconUuid(), sourceDb->metadata());
} else if (action == Qt::CopyAction) {
entry = dragEntry->clone(Entry::CloneCopy);
}
entry->setGroup(parentGroup);
}
if (entriesNotMoved) {
showErrorMessage(
tr("Move error: %1 of %2 entry(s) are already present in this database").arg(entriesNotMoved).arg(entries));
}
}
return true;