Support tearing off tags menu (#11652)

* Support tearing off tags menu
* Closes #11649 - tags menu can be torn off to set and unset tags without having to dive into the context menu every time.
* Tags menu will hide when database is locked or view is switched away from the main database view (eg, settings)
This commit is contained in:
Jonathan White 2025-02-22 20:44:12 -05:00 committed by GitHub
parent d6e726a9cf
commit e4bb80b96c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 53 additions and 9 deletions

View File

@ -817,29 +817,48 @@ void MainWindow::updateCopyAttributesMenu()
void MainWindow::updateSetTagsMenu() void MainWindow::updateSetTagsMenu()
{ {
// Remove all existing actions auto actionForTag = [](const QMenu* menu, const QString& tag) -> QAction* {
m_ui->menuTags->clear(); for (const auto action : menu->actions()) {
if (action->text() == tag) {
return action;
}
}
return nullptr;
};
auto dbWidget = m_ui->tabWidget->currentDatabaseWidget(); auto dbWidget = m_ui->tabWidget->currentDatabaseWidget();
if (dbWidget) { if (dbWidget) {
// Enumerate tags applied to the selected entries // Enumerate tags applied to the selected entries
QSet<QString> selectedTags; QSet<QString> selectedTags;
for (auto entry : dbWidget->entryView()->selectedEntries()) { for (const auto entry : dbWidget->entryView()->selectedEntries()) {
for (auto tag : entry->tagList()) { for (const auto& tag : entry->tagList()) {
selectedTags.insert(tag); selectedTags.insert(tag);
} }
} }
// Add known database tags as actions and set checked if // Add known database tags as actions and set checked if
// a selected entry has that tag // a selected entry has that tag
for (auto tag : dbWidget->database()->tagList()) { const auto tagList = dbWidget->database()->tagList();
auto action = m_ui->menuTags->addAction(icons()->icon("tag"), tag); for (const auto& tag : tagList) {
auto action = actionForTag(m_ui->menuTags, tag);
if (action) {
action->setChecked(selectedTags.contains(tag));
} else {
action = m_ui->menuTags->addAction(icons()->icon("tag"), tag);
action->setCheckable(true); action->setCheckable(true);
action->setChecked(selectedTags.contains(tag)); action->setChecked(selectedTags.contains(tag));
m_setTagsMenuActions->addAction(action); m_setTagsMenuActions->addAction(action);
} }
} }
// Remove missing tags
for (const auto action : m_ui->menuTags->actions()) {
if (!tagList.contains(action->text())) {
action->deleteLater();
}
}
}
// If no tags exist in the database then show a tip to the user // If no tags exist in the database then show a tip to the user
if (m_ui->menuTags->isEmpty()) { if (m_ui->menuTags->isEmpty()) {
auto action = m_ui->menuTags->addAction(tr("No Tags")); auto action = m_ui->menuTags->addAction(tr("No Tags"));
@ -942,6 +961,14 @@ void MainWindow::updateMenuActionState()
m_ui->menuEntryCopyAttribute->setEnabled(singleEntryOrEditing); m_ui->menuEntryCopyAttribute->setEnabled(singleEntryOrEditing);
m_ui->menuEntryTotp->setEnabled(singleEntrySelected); m_ui->menuEntryTotp->setEnabled(singleEntrySelected);
m_ui->menuTags->setEnabled(multiEntrySelected); m_ui->menuTags->setEnabled(multiEntrySelected);
// Handle tear-off tags menu
if (m_ui->menuTags->isTearOffMenuVisible()) {
if (!databaseUnlocked) {
m_ui->menuTags->hideTearOffMenu();
} else {
updateSetTagsMenu();
}
}
m_ui->actionEntryAutoType->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled()); m_ui->actionEntryAutoType->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled());
m_ui->actionEntryAutoType->menu()->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled()); m_ui->actionEntryAutoType->menu()->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled());
m_ui->actionEntryAutoTypeSequence->setText(singleEntrySelected m_ui->actionEntryAutoTypeSequence->setText(singleEntrySelected

View File

@ -314,6 +314,9 @@
<addaction name="actionEntrySetupTotp"/> <addaction name="actionEntrySetupTotp"/>
</widget> </widget>
<widget class="QMenu" name="menuTags"> <widget class="QMenu" name="menuTags">
<property name="tearOffEnabled">
<bool>true</bool>
</property>
<property name="title"> <property name="title">
<string>Tags</string> <string>Tags</string>
</property> </property>

View File

@ -2636,7 +2636,21 @@ void BaseStyle::drawControl(ControlElement element,
} }
break; break;
} }
case CE_MenuTearoff: {
if (option->state & State_Selected) {
painter->fillRect(option->rect, option->palette.brush(QPalette::Highlight));
painter->setPen(QPen(option->palette.highlightedText().color(), 1, Qt::DashLine));
} else {
painter->fillRect(option->rect, option->palette.brush(QPalette::Button));
painter->setPen(QPen(option->palette.buttonText().color(), 1, Qt::DashLine));
}
painter->drawLine(option->rect.x() + 2,
option->rect.y() + option->rect.height() / 2,
option->rect.x() + option->rect.width() - 4,
option->rect.y() + option->rect.height() / 2);
break;
}
case CE_MenuItem: { case CE_MenuItem: {
auto menuItem = qstyleoption_cast<const QStyleOptionMenuItem*>(option); auto menuItem = qstyleoption_cast<const QStyleOptionMenuItem*>(option);
if (!menuItem) if (!menuItem)