Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/entry/EntryView.cpp')
-rw-r--r--src/gui/entry/EntryView.cpp194
1 files changed, 126 insertions, 68 deletions
diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp
index bff11e124..18a69687d 100644
--- a/src/gui/entry/EntryView.cpp
+++ b/src/gui/entry/EntryView.cpp
@@ -24,13 +24,14 @@
#include <QMenu>
#include <QShortcut>
-#include "core/FilePath.h"
#include "gui/SortFilterHideProxyModel.h"
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);
@@ -70,22 +71,31 @@ EntryView::EntryView(QWidget* parent)
m_hidePasswordsAction->setCheckable(true);
m_headerMenu->addSeparator();
+ resetViewToDefaults();
+
// Actions to toggle column visibility, each carrying the corresponding
- // colummn index as data
+ // column index as data
m_columnActions = new QActionGroup(this);
m_columnActions->setExclusive(false);
- for (int columnIndex = 1; columnIndex < header()->count(); ++columnIndex) {
- QString caption = m_model->headerData(columnIndex, Qt::Horizontal, Qt::DisplayRole).toString();
- if (columnIndex == EntryModel::Paperclip) {
- caption = tr("Attachments (icon)");
+ for (int visualIndex = 1; visualIndex < header()->count(); ++visualIndex) {
+ int logicalIndex = header()->logicalIndex(visualIndex);
+ QString caption = m_model->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString();
+ if (logicalIndex == EntryModel::Paperclip) {
+ caption = tr("Has attachments", "Entry attachment icon toggle");
+ } else if (logicalIndex == EntryModel::Totp) {
+ caption = tr("Has TOTP", "Entry TOTP icon toggle");
}
QAction* action = m_headerMenu->addAction(caption);
action->setCheckable(true);
- action->setData(columnIndex);
+ action->setData(logicalIndex);
m_columnActions->addAction(action);
}
connect(m_columnActions, SIGNAL(triggered(QAction*)), this, SLOT(toggleColumnVisibility(QAction*)));
+ connect(header(), &QHeaderView::sortIndicatorChanged, [this](int index, Qt::SortOrder order) {
+ Q_UNUSED(order)
+ header()->setSortIndicatorShown(index != EntryModel::Paperclip && index != EntryModel::Totp);
+ });
m_headerMenu->addSeparator();
m_headerMenu->addAction(tr("Fit to window"), this, SLOT(fitColumnsToWindow()));
@@ -112,24 +122,8 @@ 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
-
- resetFixedColumns();
-
- // Configure default search view state and save for later use
- header()->showSection(EntryModel::ParentGroup);
- m_sortModel->sort(EntryModel::ParentGroup, Qt::AscendingOrder);
- sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
- m_defaultSearchViewState = header()->saveState();
-
- // Configure default list view state and save for later use
- header()->hideSection(EntryModel::ParentGroup);
- m_sortModel->sort(EntryModel::Title, Qt::AscendingOrder);
- sortByColumn(EntryModel::Title, Qt::AscendingOrder);
- m_defaultListViewState = header()->saveState();
-
- m_model->setPaperClipPixmap(filePath()->icon("actions", "paperclip").pixmap(16));
}
void EntryView::contextMenuShortcutPressed()
@@ -140,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()) {
@@ -219,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);
@@ -266,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)
@@ -325,6 +360,7 @@ bool EntryView::setViewState(const QByteArray& state)
{
bool status = header()->restoreState(state);
resetFixedColumns();
+ m_columnsNeedRelayout = state.isEmpty();
return status;
}
@@ -397,9 +433,11 @@ void EntryView::toggleColumnVisibility(QAction* action)
*/
void EntryView::fitColumnsToWindow()
{
- header()->resizeSections(QHeaderView::Stretch);
+ header()->setSectionResizeMode(QHeaderView::Stretch);
+ resetFixedColumns();
+ QCoreApplication::processEvents();
+ header()->setSectionResizeMode(QHeaderView::Interactive);
resetFixedColumns();
- fillRemainingWidth(true);
emit viewStateChanged();
}
@@ -409,69 +447,89 @@ void EntryView::fitColumnsToWindow()
*/
void EntryView::fitColumnsToContents()
{
- // Resize columns to fit contents
- header()->resizeSections(QHeaderView::ResizeToContents);
+ header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ resetFixedColumns();
+ QCoreApplication::processEvents();
+ header()->setSectionResizeMode(QHeaderView::Interactive);
resetFixedColumns();
- fillRemainingWidth(false);
emit viewStateChanged();
}
/**
- * Reset view to defaults
+ * Mark icon-only columns as fixed and resize them to their minimum section size.
+ */
+void EntryView::resetFixedColumns()
+{
+ header()->setSectionResizeMode(EntryModel::Paperclip, QHeaderView::Fixed);
+ header()->resizeSection(EntryModel::Paperclip, header()->minimumSectionSize());
+
+ header()->setSectionResizeMode(EntryModel::Totp, QHeaderView::Fixed);
+ header()->resizeSection(EntryModel::Totp, header()->minimumSectionSize());
+}
+
+/**
+ * Reset item view to defaults.
*/
void EntryView::resetViewToDefaults()
{
m_model->setUsernamesHidden(false);
m_model->setPasswordsHidden(true);
+ // Reduce number of columns that are shown by default
if (m_inSearchMode) {
- header()->restoreState(m_defaultSearchViewState);
+ header()->showSection(EntryModel::ParentGroup);
} else {
- header()->restoreState(m_defaultListViewState);
+ header()->hideSection(EntryModel::ParentGroup);
+ }
+ header()->showSection(EntryModel::Title);
+ header()->showSection(EntryModel::Username);
+ header()->showSection(EntryModel::Url);
+ header()->showSection(EntryModel::Notes);
+ header()->showSection(EntryModel::Modified);
+ header()->showSection(EntryModel::Paperclip);
+ header()->showSection(EntryModel::Totp);
+
+ header()->hideSection(EntryModel::Password);
+ header()->hideSection(EntryModel::Expires);
+ header()->hideSection(EntryModel::Created);
+ header()->hideSection(EntryModel::Accessed);
+ header()->hideSection(EntryModel::Attachments);
+ header()->hideSection(EntryModel::Size);
+
+ // Reset column order to logical indices
+ for (int i = 0; i < header()->count(); ++i) {
+ header()->moveSection(header()->visualIndex(i), i);
}
- fitColumnsToWindow();
-}
+ // Reorder some columns
+ header()->moveSection(header()->visualIndex(EntryModel::Paperclip), 1);
+ header()->moveSection(header()->visualIndex(EntryModel::Totp), 2);
-void EntryView::fillRemainingWidth(bool lastColumnOnly)
-{
- // Determine total width of currently visible columns
- int width = 0;
- int lastColumnIndex = 0;
- for (int columnIndex = 0; columnIndex < header()->count(); ++columnIndex) {
- if (!header()->isSectionHidden(columnIndex)) {
- width += header()->sectionSize(columnIndex);
- }
- if (header()->visualIndex(columnIndex) > lastColumnIndex) {
- lastColumnIndex = header()->visualIndex(columnIndex);
- }
- }
+ // Sort by title or group (depending on the mode)
+ m_sortModel->sort(EntryModel::Title, Qt::AscendingOrder);
+ sortByColumn(EntryModel::Title, Qt::AscendingOrder);
- int numColumns = header()->count() - header()->hiddenSectionCount();
- int availWidth = header()->width() - width;
- if ((numColumns <= 0) || (availWidth <= 0)) {
- return;
+ if (m_inSearchMode) {
+ m_sortModel->sort(EntryModel::ParentGroup, Qt::AscendingOrder);
+ sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
}
- if (!lastColumnOnly) {
- // Equally distribute remaining width to visible columns
- int add = availWidth / numColumns;
- width = 0;
- for (int columnIndex = 0; columnIndex < header()->count(); ++columnIndex) {
- if (!header()->isSectionHidden(columnIndex)) {
- header()->resizeSection(columnIndex, header()->sectionSize(columnIndex) + add);
- width += header()->sectionSize(columnIndex);
- }
- }
+ // The following call only relayouts reliably if the widget has been shown
+ // already, so only do it if the widget is visible and let showEvent() handle
+ // the initial default layout.
+ if (isVisible()) {
+ fitColumnsToWindow();
}
-
- // Add remaining width to last column
- header()->resizeSection(header()->logicalIndex(lastColumnIndex),
- header()->sectionSize(lastColumnIndex) + (header()->width() - width));
}
-void EntryView::resetFixedColumns()
+void EntryView::showEvent(QShowEvent* event)
{
- header()->setSectionResizeMode(EntryModel::Paperclip, QHeaderView::Fixed);
- header()->resizeSection(EntryModel::Paperclip, header()->minimumSectionSize());
+ QTreeView::showEvent(event);
+
+ // Check if header columns need to be resized to sensible defaults.
+ // This is only needed if no previous view state has been loaded.
+ if (m_columnsNeedRelayout) {
+ fitColumnsToWindow();
+ m_columnsNeedRelayout = false;
+ }
}