diff --git a/.gitignore b/.gitignore
index 9ab62e1908..9ffa696ff8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,5 +24,6 @@ desktop.ini
# MSVC Files
CMakeSettings.json
CMakePresets.json
+CMakeUserPresets.json
.vs/
-out/
\ No newline at end of file
+out/
diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 82963af445..04ce9a499e 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -3840,6 +3840,10 @@ Error: %1
+
+
+
+
EntryPreviewWidget
diff --git a/src/gui/entry/EntryModel.cpp b/src/gui/entry/EntryModel.cpp
index 877efe9d2b..234a08ba7e 100644
--- a/src/gui/entry/EntryModel.cpp
+++ b/src/gui/entry/EntryModel.cpp
@@ -116,7 +116,7 @@ int EntryModel::columnCount(const QModelIndex& parent) const
return 0;
}
- return 15;
+ return 16;
}
QVariant EntryModel::data(const QModelIndex& index, int role) const
@@ -230,6 +230,13 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
return result;
}
+ case Color:
+ QColor backgroundColor;
+ backgroundColor.setNamedColor(entry->backgroundColor());
+ if (backgroundColor.isValid()) {
+ result = "▍";
+ return result;
+ }
}
} else if (role == Qt::UserRole) { // Qt::UserRole is used as sort role, see EntryView::EntryView()
switch (index.column()) {
@@ -314,6 +321,15 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
}
return font;
} else if (role == Qt::ForegroundRole) {
+
+ if (index.column() == Color) {
+ QColor backgroundColor;
+ backgroundColor.setNamedColor(entry->backgroundColor());
+ if (backgroundColor.isValid()) {
+ return backgroundColor;
+ }
+ }
+
QColor foregroundColor;
foregroundColor.setNamedColor(entry->foregroundColor());
if (entry->hasReferences()) {
@@ -327,10 +343,12 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
return QVariant(foregroundColor);
}
} else if (role == Qt::BackgroundRole) {
- QColor backgroundColor;
- backgroundColor.setNamedColor(entry->backgroundColor());
- if (backgroundColor.isValid()) {
- return QVariant(backgroundColor);
+ if (m_backgroundColorVisible) {
+ QColor backgroundColor;
+ backgroundColor.setNamedColor(entry->backgroundColor());
+ if (backgroundColor.isValid()) {
+ return QVariant(backgroundColor);
+ }
}
} else if (role == Qt::ToolTipRole) {
if (index.column() == PasswordStrength && !entry->password().isEmpty() && !entry->excludeFromReports()) {
@@ -414,6 +432,8 @@ QVariant EntryModel::headerData(int section, Qt::Orientation orientation, int ro
return tr("Has attachments");
case Totp:
return tr("Has TOTP");
+ case Color:
+ return tr("Background Color");
}
}
@@ -596,3 +616,7 @@ void EntryModel::makeConnections(const Group* group)
connect(group, SIGNAL(entryMovedDown()), SLOT(entryMovedDown()));
connect(group, SIGNAL(entryDataChanged(Entry*)), SLOT(entryDataChanged(Entry*)));
}
+void EntryModel::setBackgroundColorVisible(bool visible)
+{
+ m_backgroundColorVisible = visible;
+}
diff --git a/src/gui/entry/EntryModel.h b/src/gui/entry/EntryModel.h
index 8e79be3841..4ad81f4c48 100644
--- a/src/gui/entry/EntryModel.h
+++ b/src/gui/entry/EntryModel.h
@@ -48,7 +48,8 @@ class EntryModel : public QAbstractTableModel
Attachments = 11,
Totp = 12,
Size = 13,
- PasswordStrength = 14
+ PasswordStrength = 14,
+ Color = 15
};
explicit EntryModel(QObject* parent = nullptr);
@@ -67,6 +68,7 @@ class EntryModel : public QAbstractTableModel
void setGroup(Group* group);
void setEntries(const QList& entries);
+ void setBackgroundColorVisible(bool visible);
private slots:
void entryAboutToAdd(Entry* entry);
@@ -85,6 +87,7 @@ private slots:
void severConnections();
void makeConnections(const Group* group);
+ bool m_backgroundColorVisible = true;
Group* m_group;
QList m_entries;
QList m_orgEntries;
diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp
index 868250a666..c587f7c1ea 100644
--- a/src/gui/entry/EntryView.cpp
+++ b/src/gui/entry/EntryView.cpp
@@ -219,11 +219,12 @@ void EntryView::displaySearch(const QList& entries)
m_model->setEntries(entries);
header()->showSection(EntryModel::ParentGroup);
+ setFirstEntryActive();
+
// Reset sort column to 'Group', overrides DatabaseWidgetStateSync
m_sortModel->sort(EntryModel::ParentGroup, Qt::AscendingOrder);
sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
- setFirstEntryActive();
m_inSearchMode = true;
}
@@ -335,6 +336,7 @@ bool EntryView::setViewState(const QByteArray& state)
bool status = header()->restoreState(state);
resetFixedColumns();
m_columnsNeedRelayout = state.isEmpty();
+ onHeaderChanged();
return status;
}
@@ -375,6 +377,9 @@ void EntryView::toggleColumnVisibility(QAction* action)
// least one visible column remains, as the table header will disappear
// entirely when all columns are hidden
int columnIndex = action->data().toInt();
+ if (columnIndex == EntryModel::Color) {
+ m_model->setBackgroundColorVisible(!action->isChecked());
+ }
if (action->isChecked()) {
header()->showSection(columnIndex);
if (header()->sectionSize(columnIndex) == 0) {
@@ -446,6 +451,8 @@ void EntryView::resetFixedColumns()
header()->resizeSection(col, width);
}
}
+ header()->setMinimumSectionSize(1);
+ header()->resizeSection(EntryModel::Color, ICON_ONLY_SECTION_SIZE);
}
/**
@@ -474,6 +481,8 @@ void EntryView::resetViewToDefaults()
header()->hideSection(EntryModel::Attachments);
header()->hideSection(EntryModel::Size);
header()->hideSection(EntryModel::PasswordStrength);
+ header()->hideSection(EntryModel::Color);
+ onHeaderChanged();
// Reset column order to logical indices
for (int i = 0; i < header()->count(); ++i) {
@@ -501,6 +510,11 @@ void EntryView::resetViewToDefaults()
}
}
+void EntryView::onHeaderChanged()
+{
+ m_model->setBackgroundColorVisible(isColumnHidden(EntryModel::Color));
+}
+
void EntryView::showEvent(QShowEvent* event)
{
QTreeView::showEvent(event);
diff --git a/src/gui/entry/EntryView.h b/src/gui/entry/EntryView.h
index 3a0cc1d60d..759097b346 100644
--- a/src/gui/entry/EntryView.h
+++ b/src/gui/entry/EntryView.h
@@ -76,6 +76,7 @@ private slots:
private:
void resetFixedColumns();
bool isColumnHidden(int logicalIndex);
+ void onHeaderChanged();
EntryModel* const m_model;
SortFilterHideProxyModel* const m_sortModel;
diff --git a/tests/TestEntryModel.cpp b/tests/TestEntryModel.cpp
index b7b3473d78..3506426184 100644
--- a/tests/TestEntryModel.cpp
+++ b/tests/TestEntryModel.cpp
@@ -313,15 +313,11 @@ void TestEntryModel::testProxyModel()
modelSource->setGroup(db->rootGroup());
- /**
- * @author Fonic
- * Update comparison value of modelProxy->columnCount() to account for
- * additional columns 'Password', 'Notes', 'Expires', 'Created', 'Modified',
- * 'Accessed', 'Paperclip', 'Attachments', and TOTP
- */
+ // Test hiding and showing a column
+ auto columnCount = modelProxy->columnCount();
QSignalSpy spyColumnRemove(modelProxy, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)));
modelProxy->hideColumn(0, true);
- QCOMPARE(modelProxy->columnCount(), 14);
+ QCOMPARE(modelProxy->columnCount(), columnCount - 1);
QVERIFY(!spyColumnRemove.isEmpty());
int oldSpyColumnRemoveSize = spyColumnRemove.size();
@@ -335,15 +331,9 @@ void TestEntryModel::testProxyModel()
entryList << entry;
modelSource->setEntries(entryList);
- /**
- * @author Fonic
- * Update comparison value of modelProxy->columnCount() to account for
- * additional columns 'Password', 'Notes', 'Expires', 'Created', 'Modified',
- * 'Accessed', 'Paperclip', 'Attachments', and TOTP
- */
QSignalSpy spyColumnInsert(modelProxy, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)));
modelProxy->hideColumn(0, false);
- QCOMPARE(modelProxy->columnCount(), 15);
+ QCOMPARE(modelProxy->columnCount(), columnCount);
QVERIFY(!spyColumnInsert.isEmpty());
int oldSpyColumnInsertSize = spyColumnInsert.size();
diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp
index 170bf3a175..4840092ea6 100644
--- a/tests/gui/TestGui.cpp
+++ b/tests/gui/TestGui.cpp
@@ -1082,6 +1082,13 @@ void TestGui::testSearch()
QCOMPARE(groupView->currentGroup(), m_db->rootGroup());
QVERIFY(!m_dbWidget->isSearchActive());
+ // check if first entry is selected after search
+ QTest::keyClicks(searchTextEdit, "some");
+ QTRY_VERIFY(m_dbWidget->isSearchActive());
+ QTRY_COMPARE(entryView->selectedEntries().length(), 1);
+ QModelIndex index_current = entryView->indexFromEntry(entryView->currentEntry());
+ QTRY_COMPARE(index_current.row(), 0);
+
// Try to edit the first entry from the search view
// Refocus back to search edit
QTest::mouseClick(searchTextEdit, Qt::LeftButton);