mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-12 15:59:58 -05:00
Add untracked move action
This commit is contained in:
parent
22a1a82e5b
commit
86c6f684b2
@ -447,7 +447,7 @@ Qt::DropActions EntryModel::supportedDropActions() const
|
||||
|
||||
Qt::DropActions EntryModel::supportedDragActions() const
|
||||
{
|
||||
return (Qt::MoveAction | Qt::CopyAction);
|
||||
return Qt::MoveAction | Qt::CopyAction | Qt::LinkAction;
|
||||
}
|
||||
|
||||
Qt::ItemFlags EntryModel::flags(const QModelIndex& modelIndex) const
|
||||
|
@ -180,7 +180,7 @@ Group* GroupModel::groupFromIndex(const QModelIndex& index) const
|
||||
|
||||
Qt::DropActions GroupModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::MoveAction | Qt::CopyAction;
|
||||
return Qt::MoveAction | Qt::CopyAction | Qt::LinkAction;
|
||||
}
|
||||
|
||||
Qt::ItemFlags GroupModel::flags(const QModelIndex& modelIndex) const
|
||||
@ -206,7 +206,7 @@ bool GroupModel::dropMimeData(const QMimeData* data,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!data || (action != Qt::MoveAction && action != Qt::CopyAction) || !parent.isValid()) {
|
||||
if (!data || !(action & (Qt::MoveAction | Qt::CopyAction | Qt::LinkAction)) || !parent.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -261,11 +261,20 @@ bool GroupModel::dropMimeData(const QMimeData* data,
|
||||
targetDb->metadata()->copyCustomIcons(group->customIconsRecursive(), sourceDb->metadata());
|
||||
|
||||
if (action == Qt::MoveAction) {
|
||||
// For cross-db moves use a clone with new UUID but original CreationTime
|
||||
// -- 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));
|
||||
// Remove the original from the sourceDb to allow this change to sync to other dbs
|
||||
// Original UUID is marked as deleted to remove it from dbs that merge with this one
|
||||
delete dragGroup;
|
||||
} 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
|
||||
sourceDb->setDeletedObjects(deletedObjects);
|
||||
} else {
|
||||
group = dragGroup->clone(Entry::CloneCopy);
|
||||
}
|
||||
@ -302,12 +311,20 @@ bool GroupModel::dropMimeData(const QMimeData* data,
|
||||
if (sourceDb != targetDb) {
|
||||
targetDb->metadata()->copyCustomIcon(entry->iconUuid(), sourceDb->metadata());
|
||||
|
||||
// Reset the UUID when moving across db boundary
|
||||
if (action == Qt::MoveAction) {
|
||||
// For cross-db moves use a clone with new UUID but original CreationTime
|
||||
// -- Tracked move
|
||||
// A clone with new UUID but original CreationTime
|
||||
entry = dragEntry->clone(Entry::CloneFlags(Entry::CloneCopy & ~Entry::CloneResetCreationTime));
|
||||
// Remove the original from the sourceDb to allow this change to sync to other dbs
|
||||
// Original UUID is marked as deleted to remove it from dbs that merge with this one
|
||||
delete dragEntry;
|
||||
} 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
|
||||
sourceDb->setDeletedObjects(deletedObjects);
|
||||
} else {
|
||||
entry = dragEntry->clone(Entry::CloneCopy);
|
||||
}
|
||||
|
@ -24,11 +24,15 @@
|
||||
#include "core/Config.h"
|
||||
#include "core/Group.h"
|
||||
#include "gui/group/GroupModel.h"
|
||||
#include "gui/entry/EntryView.h"
|
||||
#include "gui/DatabaseWidget.h"
|
||||
|
||||
GroupView::GroupView(Database* db, QWidget* parent)
|
||||
: QTreeView(parent)
|
||||
, m_model(new GroupModel(db, this))
|
||||
, m_updatingExpanded(false)
|
||||
, m_isDragEventSrcFromOtherDb(false)
|
||||
, m_lastAcceptedDropAction(Qt::IgnoreAction)
|
||||
{
|
||||
QTreeView::setModel(m_model);
|
||||
setHeaderHidden(true);
|
||||
@ -73,20 +77,83 @@ void GroupView::changeDatabase(const QSharedPointer<Database>& newDb)
|
||||
m_model->changeDatabase(newDb.data());
|
||||
}
|
||||
|
||||
void GroupView::dragMoveEvent(QDragMoveEvent* event)
|
||||
void GroupView::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->keyboardModifiers() & Qt::ControlModifier) {
|
||||
event->setDropAction(Qt::CopyAction);
|
||||
} else {
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->ignore(); // default to ignore
|
||||
|
||||
auto const eventSource = event->source();
|
||||
// ignore events from other processes
|
||||
if (!eventSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore events with unsupported mime-types
|
||||
auto supportedFormats = m_model->mimeTypes().toSet();
|
||||
if (!supportedFormats.intersects(event->mimeData()->formats().toSet())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto firstAncestorOfTypeDatabaseWidget = [](QObject* object) -> DatabaseWidget* {
|
||||
if (object) {
|
||||
for (auto parent = object->parent(); parent; parent = parent->parent()) {
|
||||
if (auto dbWidget = qobject_cast<DatabaseWidget*>(parent)) {
|
||||
return dbWidget;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
m_isDragEventSrcFromOtherDb = false;
|
||||
if (GroupView* view = qobject_cast<GroupView*>(eventSource)) {
|
||||
m_isDragEventSrcFromOtherDb = view != this;
|
||||
} else if (EntryView* view = qobject_cast<EntryView*>(eventSource)) {
|
||||
auto targetDbWidget = firstAncestorOfTypeDatabaseWidget(this);
|
||||
auto sourceDbWidget = firstAncestorOfTypeDatabaseWidget(view);
|
||||
m_isDragEventSrcFromOtherDb = sourceDbWidget != targetDbWidget;
|
||||
}
|
||||
|
||||
QTreeView::dragEnterEvent(event);
|
||||
}
|
||||
|
||||
void GroupView::dragMoveEvent(QDragMoveEvent* event)
|
||||
{
|
||||
QTreeView::dragMoveEvent(event);
|
||||
|
||||
if (!event->isAccepted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// entries may only be dropped on groups
|
||||
if (event->isAccepted() && event->mimeData()->hasFormat("application/x-keepassx-entry")
|
||||
if (event->mimeData()->hasFormat("application/x-keepassx-entry")
|
||||
&& (dropIndicatorPosition() == AboveItem || dropIndicatorPosition() == BelowItem)) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
// figure out which dropaction should be used
|
||||
Qt::DropAction dropAction = Qt::MoveAction;
|
||||
if (event->keyboardModifiers() & Qt::ControlModifier) {
|
||||
dropAction = Qt::CopyAction;
|
||||
} else if (event->keyboardModifiers() & Qt::AltModifier) {
|
||||
dropAction = m_isDragEventSrcFromOtherDb ? Qt::LinkAction : Qt::IgnoreAction;
|
||||
}
|
||||
|
||||
if (dropAction != Qt::IgnoreAction && event->possibleActions() & dropAction) {
|
||||
event->setDropAction(dropAction);
|
||||
m_lastAcceptedDropAction = event->dropAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupView::dropEvent(QDropEvent* event)
|
||||
{
|
||||
if (m_lastAcceptedDropAction != Qt::IgnoreAction) {
|
||||
event->setDropAction(m_lastAcceptedDropAction);
|
||||
QTreeView::dropEvent(event);
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,9 @@ private slots:
|
||||
void contextMenuShortcutPressed();
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent* event) override;
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
void focusInEvent(QFocusEvent* event) override;
|
||||
|
||||
private:
|
||||
@ -56,6 +58,8 @@ private:
|
||||
|
||||
GroupModel* const m_model;
|
||||
bool m_updatingExpanded;
|
||||
bool m_isDragEventSrcFromOtherDb;
|
||||
Qt::DropAction m_lastAcceptedDropAction;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_GROUPVIEW_H
|
||||
|
Loading…
Reference in New Issue
Block a user