This commit is contained in:
Juzu-O 2026-03-10 22:28:57 +01:00 committed by GitHub
commit a3e27c5964
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 168 additions and 17 deletions

View file

@ -5997,6 +5997,10 @@ Are you sure you want to continue with this file?</source>
<source>Show Toolbar</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show Entries of Subgroups</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show Preview Panel</source>
<translation type="unfinished"></translation>
@ -6350,6 +6354,10 @@ Expect some bugs and minor issues, this version is meant for testing purposes.</
<source>Toggle Show Toolbar</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggle Show Entries of Subgroups</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggle Show Preview Panel</source>
<translation type="unfinished"></translation>

View file

@ -122,6 +122,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::GUI_SearchWaitForEnter, {QS("GUI/SearchWaitForEnter"), Roaming, false}},
{Config::GUI_ShowExpiredEntriesOnDatabaseUnlock, {QS("GUI/ShowExpiredEntriesOnDatabaseUnlock"), Roaming, true}},
{Config::GUI_ShowExpiredEntriesOnDatabaseUnlockOffsetDays, {QS("GUI/ShowExpiredEntriesOnDatabaseUnlockOffsetDays"), Roaming, 3}},
{Config::GUI_ShowSubgroupEntries, {QS("GUI/ShowSubgroupEntries"), Roaming, false}},
{Config::GUI_FontSizeOffset, {QS("GUI/FontSizeOffset"), Local, 0}},
{Config::GUI_MainWindowGeometry, {QS("GUI/MainWindowGeometry"), Local, {}}},

View file

@ -103,6 +103,7 @@ public:
GUI_SearchWaitForEnter,
GUI_ShowExpiredEntriesOnDatabaseUnlock,
GUI_ShowExpiredEntriesOnDatabaseUnlockOffsetDays,
GUI_ShowSubgroupEntries,
GUI_FontSizeOffset,
GUI_MainWindowGeometry,

View file

@ -2059,6 +2059,11 @@ void MainWindow::initViewMenu()
applySettingsChanges();
});
m_ui->actionShowEntriesOfSubgroups->setChecked(config()->get(Config::GUI_ShowSubgroupEntries).toBool());
connect(m_ui->actionShowEntriesOfSubgroups, &QAction::toggled, this, [](bool checked) {
config()->set(Config::GUI_ShowSubgroupEntries, checked);
});
m_ui->actionShowGroupPanel->setChecked(!config()->get(Config::GUI_HideGroupPanel).toBool());
connect(m_ui->actionShowGroupPanel, &QAction::toggled, this, [](bool checked) {
config()->set(Config::GUI_HideGroupPanel, !checked);

View file

@ -399,6 +399,8 @@
<addaction name="actionShowMenubar"/>
<addaction name="actionShowToolbar"/>
<addaction name="separator"/>
<addaction name="actionShowEntriesOfSubgroups"/>
<addaction name="separator"/>
<addaction name="actionHideUsernames"/>
<addaction name="actionHidePasswords"/>
</widget>
@ -1244,6 +1246,17 @@
<string notr="true">Ctrl+Shift+A</string>
</property>
</action>
<action name="actionShowEntriesOfSubgroups">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show Entries of Subgroups</string>
</property>
<property name="toolTip">
<string>Toggle Show Entries of Subgroups</string>
</property>
</action>
<action name="actionHideUsernames">
<property name="checkable">
<bool>true</bool>

View file

@ -68,10 +68,38 @@ void EntryModel::setGroup(Group* group)
m_group = group;
m_allGroups.clear();
m_entries = group->entries();
m_orgEntries.clear();
makeConnections(group);
// Check if we should show subgroup entries
if (config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
m_entries = group->entriesRecursive();
// When showing subgroup entries, we need to connect to all groups
// that contain the entries being displayed
for (const auto& entry : asConst(m_entries)) {
if (entry->group() && !m_allGroups.contains(entry->group())) {
m_allGroups.append(entry->group());
}
}
// Always include the current group itself to handle new entries added directly to it
if (!m_allGroups.contains(group)) {
m_allGroups.append(group);
}
// Connect to all groups that have entries in the view (or could have entries)
for (const auto& groupToConnect : m_allGroups) {
if (groupToConnect) {
makeConnections(groupToConnect);
}
}
// Also connect to groupAdded signal from the main group to detect new subgroups
connect(group, SIGNAL(groupAdded()), SLOT(groupAdded()));
} else {
m_entries = group->entries();
makeConnections(group);
}
m_orgEntries.clear();
endResetModel();
}
@ -88,13 +116,15 @@ void EntryModel::setEntries(const QList<Entry*>& entries)
m_orgEntries = entries;
for (const auto entry : asConst(m_entries)) {
if (entry->group()) {
m_allGroups.insert(entry->group());
if (entry->group() && !m_allGroups.contains(entry->group())) {
m_allGroups.append(entry->group());
}
}
for (const auto group : m_allGroups) {
makeConnections(group);
if (group) {
makeConnections(group);
}
}
endResetModel();
@ -530,7 +560,12 @@ void EntryModel::entryAdded(Entry* entry)
}
if (m_group) {
m_entries = m_group->entries();
// Check if we should show subgroup entries
if (config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
m_entries = m_group->entriesRecursive();
} else {
m_entries = m_group->entries();
}
}
endInsertRows();
}
@ -546,7 +581,12 @@ void EntryModel::entryAboutToRemove(Entry* entry)
void EntryModel::entryRemoved()
{
if (m_group) {
m_entries = m_group->entries();
// Check if we should show subgroup entries
if (config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
m_entries = m_group->entriesRecursive();
} else {
m_entries = m_group->entries();
}
}
endRemoveRows();
}
@ -562,7 +602,12 @@ void EntryModel::entryAboutToMoveUp(int row)
void EntryModel::entryMovedUp()
{
if (m_group) {
m_entries = m_group->entries();
// Check if we should show subgroup entries
if (config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
m_entries = m_group->entriesRecursive();
} else {
m_entries = m_group->entries();
}
}
endMoveRows();
}
@ -578,11 +623,26 @@ void EntryModel::entryAboutToMoveDown(int row)
void EntryModel::entryMovedDown()
{
if (m_group) {
m_entries = m_group->entries();
// Check if we should show subgroup entries
if (config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
m_entries = m_group->entriesRecursive();
} else {
m_entries = m_group->entries();
}
}
endMoveRows();
}
void EntryModel::groupAdded()
{
// When a new subgroup is added to the current group and we're showing subgroup entries,
// we need to refresh our connections to include the new subgroup
if (m_group && config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
// Refresh the entry list and connections to include new subgroups
setGroup(m_group);
}
}
void EntryModel::entryDataChanged(Entry* entry)
{
int row = m_entries.indexOf(entry);
@ -598,6 +658,12 @@ void EntryModel::onConfigChanged(Config::ConfigKey key)
case Config::GUI_HidePasswords:
emit dataChanged(index(0, Password), index(rowCount() - 1, Password), {Qt::DisplayRole});
break;
case Config::GUI_ShowSubgroupEntries:
// Refresh the entry list when the subgroup setting changes
if (m_group) {
setGroup(m_group);
}
break;
default:
break;
}
@ -609,8 +675,17 @@ void EntryModel::severConnections()
disconnect(m_group, nullptr, this, nullptr);
}
for (const Group* group : asConst(m_allGroups)) {
disconnect(group, nullptr, this, nullptr);
// Use an iterator to safely remove null pointers while iterating
auto it = m_allGroups.begin();
while (it != m_allGroups.end()) {
if (*it) {
// Group is still valid, disconnect from it
disconnect(*it, nullptr, this, nullptr);
++it;
} else {
// Group has been deleted, remove the null pointer
it = m_allGroups.erase(it);
}
}
}

View file

@ -19,7 +19,9 @@
#define KEEPASSX_ENTRYMODEL_H
#include <QAbstractTableModel>
#include <QList>
#include <QPixmap>
#include <QPointer>
#include <QSet>
#include "core/Config.h"
@ -81,6 +83,7 @@ private slots:
void entryAboutToMoveDown(int row);
void entryMovedDown();
void entryDataChanged(Entry* entry);
void groupAdded();
void onConfigChanged(Config::ConfigKey key);
@ -89,10 +92,10 @@ private:
void makeConnections(const Group* group);
bool m_backgroundColorVisible = true;
Group* m_group;
QPointer<Group> m_group;
QList<Entry*> m_entries;
QList<Entry*> m_orgEntries;
QSet<const Group*> m_allGroups;
QList<QPointer<const Group>> m_allGroups;
const QString HiddenContentDisplay;
};

View file

@ -33,6 +33,8 @@
#include "gui/Icons.h"
#include "gui/SortFilterHideProxyModel.h"
#include "core/Config.h"
#define ICON_ONLY_SECTION_SIZE 26
class PasswordStrengthItemDelegate : public QStyledItemDelegate
@ -94,6 +96,9 @@ EntryView::EntryView(QWidget* parent)
emit entrySelectionChanged(currentEntry());
});
// Listen for config changes to update Group column visibility
connect(config(), &Config::changed, this, &EntryView::onConfigChanged);
new QShortcut(Qt::CTRL + Qt::Key_F10, this, SLOT(contextMenuShortcutPressed()), nullptr, Qt::WidgetShortcut);
new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_J, this, SLOT(jumpToGroupShortcut()), nullptr, Qt::WidgetShortcut);
@ -214,7 +219,16 @@ void EntryView::focusInEvent(QFocusEvent* event)
void EntryView::displayGroup(Group* group)
{
m_model->setGroup(group);
header()->hideSection(EntryModel::ParentGroup);
// Show Group column when subgroup entries are enabled, since entries from different groups will be shown
// But respect user's preference if they've manually hidden it
if (config()->get(Config::GUI_ShowSubgroupEntries).toBool() && !m_userHidGroupColumnInSubgroupMode) {
header()->showSection(EntryModel::ParentGroup);
} else if (!config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
header()->hideSection(EntryModel::ParentGroup);
}
// If user has hidden the column in subgroup mode, don't force it to show
setFirstEntryActive();
m_inSearchMode = false;
}
@ -360,7 +374,8 @@ void EntryView::showHeaderMenu(const QPoint& position)
int columnIndex = action->data().toInt();
action->setChecked(!isColumnHidden(columnIndex));
}
actions[EntryModel::ParentGroup]->setVisible(inSearchMode());
actions[EntryModel::ParentGroup]->setVisible(inSearchMode()
|| config()->get(Config::GUI_ShowSubgroupEntries).toBool());
m_headerMenu->popup(mapToGlobal(position));
}
@ -390,11 +405,21 @@ void EntryView::toggleColumnVisibility(QAction* action)
if (header()->sectionSize(columnIndex) == 0) {
header()->resizeSection(columnIndex, header()->defaultSectionSize());
}
// Reset flag when user manually shows Group column
if (columnIndex == EntryModel::ParentGroup && !m_inSearchMode
&& config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
m_userHidGroupColumnInSubgroupMode = false;
}
resetFixedColumns();
return;
}
if ((header()->count() - header()->hiddenSectionCount()) > 1) {
header()->hideSection(columnIndex);
// Track when user manually hides Group column while subgroup entries is enabled
if (columnIndex == EntryModel::ParentGroup && !m_inSearchMode
&& config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
m_userHidGroupColumnInSubgroupMode = true;
}
return;
}
action->setChecked(true);
@ -466,7 +491,8 @@ void EntryView::resetFixedColumns()
void EntryView::resetViewToDefaults()
{
// Reduce number of columns that are shown by default
if (m_inSearchMode) {
if (m_inSearchMode
|| (config()->get(Config::GUI_ShowSubgroupEntries).toBool() && !m_userHidGroupColumnInSubgroupMode)) {
header()->showSection(EntryModel::ParentGroup);
} else {
header()->hideSection(EntryModel::ParentGroup);
@ -602,6 +628,22 @@ bool EntryView::isColumnHidden(int logicalIndex)
return header()->isSectionHidden(logicalIndex) || header()->sectionSize(logicalIndex) == 0;
}
void EntryView::onConfigChanged(Config::ConfigKey key)
{
if (key == Config::GUI_ShowSubgroupEntries && !m_inSearchMode) {
// Reset user preference when setting is toggled - this allows the
// Group column to auto-appear when re-enabling the feature
m_userHidGroupColumnInSubgroupMode = false;
// Update Group column visibility when subgroup entries setting changes
if (config()->get(Config::GUI_ShowSubgroupEntries).toBool()) {
header()->showSection(EntryModel::ParentGroup);
} else {
header()->hideSection(EntryModel::ParentGroup);
}
}
}
void EntryView::jumpToGroupShortcut()
{
// Only allow jump to group in search mode

View file

@ -21,6 +21,7 @@
#include <QTreeView>
#include "core/Config.h"
#include "gui/entry/EntryModel.h"
class Entry;
@ -72,6 +73,7 @@ private slots:
void resetViewToDefaults();
void contextMenuShortcutPressed();
void sortIndicatorChanged(int logicalIndex, Qt::SortOrder order);
void onConfigChanged(Config::ConfigKey key);
void jumpToGroupShortcut();
private:
@ -85,6 +87,7 @@ private:
Qt::SortOrder m_lastOrder;
bool m_inSearchMode = false;
bool m_columnsNeedRelayout = true;
bool m_userHidGroupColumnInSubgroupMode = false;
QMenu* m_headerMenu;
QActionGroup* m_columnActions;