From e06021293c3574114427a9d15d09ab5c4e52fe86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ot=C3=A1vio=20Biagioni?= Date: Sat, 29 Nov 2025 16:36:23 -0300 Subject: [PATCH] feat: add options to close multiple visible tabs in context menu (#6515) Reviewed-by: nerix Reviewed-by: pajlada --- CHANGELOG.md | 1 + src/widgets/helper/NotebookTab.cpp | 160 +++++++++++++++++++++++++++++ src/widgets/helper/NotebookTab.hpp | 3 + 3 files changed, 164 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 261da82e..8e7badc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ - Dev: Unwrapped `LimitedQueueSnapshot` to `std::vector`. (#6606) - Dev: Simplified uses of `getMessageSnapshot`. (#6607) - Dev: Disabled `llvm-prefer-static-over-anonymous-namespace` in clang-tidy. (#6610) +- Dev: Added options to close multiple visible tabs. (#6515) ## 2.5.4 diff --git a/src/widgets/helper/NotebookTab.cpp b/src/widgets/helper/NotebookTab.cpp index f9261f55..67171201 100644 --- a/src/widgets/helper/NotebookTab.cpp +++ b/src/widgets/helper/NotebookTab.cpp @@ -124,6 +124,154 @@ NotebookTab::NotebookTab(Notebook *notebook) this->notebook_->removePage(this->page); }); + this->closeMultipleTabsMenu_ = new QMenu("Close Multiple Tabs", this); + this->menu_.addMenu(closeMultipleTabsMenu_); + + closeMultipleTabsMenu_->addAction("Close All Visible Tabs", [this]() { + auto reply = QMessageBox::question( + this, "Close All Visible Tabs", + "Are you sure you want to close all visible tabs?", + QMessageBox::Yes | QMessageBox::Cancel); + + if (reply != QMessageBox::Yes) + { + return; + } + + for (int i = this->notebook_->getPageCount() - 1; i >= 0; --i) + { + auto *page = this->notebook_->getPageAt(i); + + auto *container = dynamic_cast(page); + if (!container) + { + continue; + } + + auto *tab = container->getTab(); + if (!tab || !tab->isVisible()) + { + continue; + } + + this->notebook_->removePage(page); + } + }); + + this->closeTabsToLeftAction_ = this->closeMultipleTabsMenu_->addAction( + "Close Visible Tabs to Left", [this]() { + auto reply = QMessageBox::question( + this, "Close Visible Tabs to Left", + "Are you sure you want to close all visible tabs to the left?", + QMessageBox::Yes | QMessageBox::Cancel); + + if (reply != QMessageBox::Yes) + { + return; + } + + std::vector pagesToRemove; + for (int i = 0; i < this->notebook_->getPageCount(); ++i) + { + auto *page = this->notebook_->getPageAt(i); + if (page == this->page) + { + break; + } + + auto *container = dynamic_cast(page); + if (!container) + { + continue; + } + + auto *tab = container->getTab(); + if (!tab || !tab->isVisible()) + { + continue; + } + + pagesToRemove.push_back(page); + } + + for (auto *page : pagesToRemove) + { + this->notebook_->removePage(page); + } + }); + + this->closeTabsToRightAction_ = this->closeMultipleTabsMenu_->addAction( + "Close Visible Tabs to Right", [this]() { + auto reply = QMessageBox::question( + this, "Close Visible Tabs to Right", + "Are you sure you want to close all visible tabs to the right?", + QMessageBox::Yes | QMessageBox::Cancel); + + if (reply != QMessageBox::Yes) + { + return; + } + + for (int i = this->notebook_->getPageCount() - 1; i >= 0; --i) + { + auto *p = this->notebook_->getPageAt(i); + if (p == this->page) + { + break; + } + + auto *container = dynamic_cast(p); + if (!container) + { + continue; + } + + auto *tab = container->getTab(); + if (!tab || !tab->isVisible()) + { + continue; + } + + this->notebook_->removePage(p); + } + }); + + this->closeMultipleTabsMenu_->addAction( + "Close Other Visible Tabs", [this]() { + auto reply = QMessageBox::question( + this, "Close Other Visible Tabs", + "Are you sure you want to close all other visible tabs?", + QMessageBox::Yes | QMessageBox::Cancel); + + if (reply != QMessageBox::Yes) + { + return; + } + + for (int i = this->notebook_->getPageCount() - 1; i >= 0; --i) + { + auto *p = this->notebook_->getPageAt(i); + if (p == this->page) + { + continue; + } + + auto *container = dynamic_cast(p); + if (!container) + { + continue; + } + + auto *tab = container->getTab(); + if (!tab || !tab->isVisible()) + { + continue; + } + + this->notebook_->removePage(p); + } + }); + this->menu_.addAction( "Popup Tab", getApp()->getHotkeys()->getDisplaySequence(HotkeyCategory::Window, @@ -909,6 +1057,18 @@ void NotebookTab::mousePressEvent(QMouseEvent *event) case Qt::RightButton: { this->menu_.popup(event->globalPosition().toPoint() + QPoint(0, 8)); + + const int visibleTabCount = + this->notebook_->getVisibleTabCount(); + const int selectedTabIndex = + this->notebook_->visibleIndexOf(this->page); + + this->closeMultipleTabsMenu_->setEnabled(visibleTabCount > 1); + + this->closeTabsToLeftAction_->setEnabled(selectedTabIndex > 0); + this->closeTabsToRightAction_->setEnabled( + selectedTabIndex != -1 && + selectedTabIndex < (visibleTabCount - 1)); } break; default:; diff --git a/src/widgets/helper/NotebookTab.hpp b/src/widgets/helper/NotebookTab.hpp index 13c4a317..4b221d3d 100644 --- a/src/widgets/helper/NotebookTab.hpp +++ b/src/widgets/helper/NotebookTab.hpp @@ -162,6 +162,9 @@ private: int growWidth_ = 0; QMenu menu_; + QMenu *closeMultipleTabsMenu_{}; + QAction *closeTabsToLeftAction_{}; + QAction *closeTabsToRightAction_{}; pajlada::Signals::SignalHolder managedConnections_; };