Add natural sort of entry list

Introduce a third unsorted status that shows entries in the order they occur in the KDBX file.

* Add keyboard shortcut Ctrl+Alt+Up/Down to move entries up and down in sort order
* Add entry context menu icons to achieve movement up/down
* Only show menu icons when in natural sort order
* Add Material Design icons for moving up/down

* Add feature to track non-data changes and force a save on exit to ensure they are not lost when locking a database. This allows users to make entry movements and group expand/collapse operations and not lose that state.

Remove saveas
This commit is contained in:
Holger Böhnke 2020-05-21 21:43:00 -04:00 committed by Jonathan White
parent 43c82ccb09
commit eb198271ac
24 changed files with 500 additions and 11 deletions

View file

@ -30,6 +30,8 @@ EntryView::EntryView(QWidget* parent)
: QTreeView(parent)
, m_model(new EntryModel(this))
, m_sortModel(new SortFilterHideProxyModel(this))
, m_lastIndex(-1)
, m_lastOrder(Qt::AscendingOrder)
, m_inSearchMode(false)
{
m_sortModel->setSourceModel(m_model);
@ -120,7 +122,7 @@ EntryView::EntryView(QWidget* parent)
// clang-format on
// clang-format off
connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SIGNAL(viewStateChanged()));
connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(sortIndicatorChanged(int,Qt::SortOrder)));
// clang-format on
}
@ -132,6 +134,31 @@ void EntryView::contextMenuShortcutPressed()
}
}
void EntryView::sortIndicatorChanged(int logicalIndex, Qt::SortOrder order)
{
int oldIndex = m_lastIndex;
m_lastIndex = logicalIndex;
Qt::SortOrder oldOrder = m_lastOrder;
m_lastOrder = order;
if (oldIndex == logicalIndex // same index
&& oldOrder == Qt::DescendingOrder // old order is descending
&& order == Qt::AscendingOrder) // new order is ascending
{
// a change from descending to ascending on the same column occurred
// this sets the header into no sort order
header()->setSortIndicator(-1, Qt::AscendingOrder);
// do not emit any signals, header()->setSortIndicator recursively calls this
// function and the signals are emitted in the else part
} else {
// call emitEntrySelectionChanged even though the selection did not really change
// this triggers the evaluation of the menu activation and anyway, the position
// of the selected entry within the widget did change
emitEntrySelectionChanged();
emit viewStateChanged();
}
}
void EntryView::keyPressEvent(QKeyEvent* event)
{
if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) && currentIndex().isValid()) {
@ -211,6 +238,11 @@ bool EntryView::inSearchMode()
return m_inSearchMode;
}
bool EntryView::isSorted()
{
return header()->sortIndicatorSection() != -1;
}
void EntryView::emitEntryActivated(const QModelIndex& index)
{
Entry* entry = entryFromIndex(index);
@ -258,6 +290,17 @@ Entry* EntryView::entryFromIndex(const QModelIndex& index)
}
}
int EntryView::currentEntryIndex()
{
QModelIndexList list = selectionModel()->selectedRows();
if (list.size() == 1) {
auto index = m_sortModel->mapToSource(list.first());
return index.row();
} else {
return -1;
}
}
/**
* Get current state of 'Hide Usernames' setting (NOTE: just pass-through for
* m_model)