-
-
Notifications
You must be signed in to change notification settings - Fork 174
Add "Undo close tab" feature #1342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -420,7 +420,9 @@ void KiwixApp::createActions() | |
| CREATE_ACTION_SHORTCUTS(CloseCurrentTabAction, gt("close-tab"), QList<QKeySequence>({QKeySequence(Qt::CTRL | Qt::Key_F4), QKeySequence(Qt::CTRL | Qt::Key_W)})); | ||
|
|
||
| CREATE_ACTION_SHORTCUT(ReopenClosedTabAction, gt("reopen-closed-tab"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_T)); | ||
| HIDE_ACTION(ReopenClosedTabAction); | ||
| mpa_actions[ReopenClosedTabAction]->setEnabled(false); | ||
| connect(mpa_actions[ReopenClosedTabAction], &QAction::triggered, | ||
| this, &KiwixApp::reopenLastClosedTab); | ||
|
|
||
| CREATE_ACTION_SHORTCUT(BrowseLibraryAction, gt("browse-library"), QKeySequence(Qt::CTRL | Qt::Key_E)); | ||
| HIDE_ACTION(BrowseLibraryAction); | ||
|
|
@@ -623,3 +625,20 @@ QString KiwixApp::getPrevSaveDir() const | |
| QDir dir(prevSaveDir); | ||
| return dir.exists() ? prevSaveDir : DEFAULT_SAVE_DIR; | ||
| } | ||
|
|
||
| void KiwixApp::pushClosedTab(const QString& url, const QString& title) { | ||
| if (url.isEmpty() || title.isEmpty()) | ||
| return; | ||
| m_closedTabs.push({url, title}); | ||
|
||
| mpa_actions[ReopenClosedTabAction]->setEnabled(true); | ||
| } | ||
|
|
||
| void KiwixApp::reopenLastClosedTab() { | ||
| if (m_closedTabs.isEmpty()) | ||
| return; | ||
|
|
||
| auto tab = m_closedTabs.pop(); | ||
| openUrl(tab.url, true); | ||
| if (m_closedTabs.isEmpty()) | ||
| mpa_actions[ReopenClosedTabAction]->setEnabled(false); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
|
|
||
| #include <mutex> | ||
| #include <iostream> | ||
| #include <QStack> | ||
|
|
||
| typedef TabBar::TabType TabType; | ||
|
|
||
|
|
@@ -144,6 +145,17 @@ public slots: | |
|
|
||
| QString findLibraryDirectory(); | ||
| void loadAndInstallTranslations(QTranslator& translator, const QString& filename, const QString& directory); | ||
|
|
||
| struct ClosedTabInfo { | ||
| QString url; | ||
| QString title; | ||
| }; | ||
| QStack<ClosedTabInfo> m_closedTabs; | ||
|
|
||
| public: | ||
| void pushClosedTab(const QString& url, const QString& title); | ||
| bool hasClosedTabs() const { return !m_closedTabs.isEmpty(); } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused function |
||
| void reopenLastClosedTab(); | ||
|
Comment on lines
+149
to
+158
|
||
| }; | ||
|
|
||
| QString getFileContent(QString filePath); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -310,11 +310,21 @@ QStringList TabBar::getTabZimIds() const | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| void TabBar::closeTab(int index) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // The first and last tabs (i.e. the library tab and the + (new tab) button) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // cannot be closed | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // First and last tabs cannot be closed | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // First and last tabs cannot be closed | |
| // First and last tabs (library tab and + button) cannot be closed |
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The QMenu menu is created on the stack and will be properly destroyed when it goes out of scope after menu.exec() returns. However, consider using a parent pointer (e.g., QMenu menu(this)) to ensure proper cleanup even if exceptions occur, following Qt best practices for object lifetime management.
| QMenu menu; | |
| QMenu menu(this); |
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The context menu is only shown when clicking outside tabs (tabIndex == -1), but no context menu is shown when clicking on a tab. Consider adding a context menu for tabs themselves (when tabIndex >= 0) with options like "Close Tab", "Close Other Tabs", etc., which would provide better UX consistency with other tabbed applications.
| menu.exec(event->globalPos()); | |
| menu.exec(event->globalPos()); | |
| } else { // Clicked on a tab | |
| QMenu menu; | |
| QAction* closeTabAction = menu.addAction(tr("Close Tab")); | |
| QAction* closeOtherTabsAction = menu.addAction(tr("Close Other Tabs")); | |
| QAction* closeTabsToRightAction = menu.addAction(tr("Close Tabs to the Right")); | |
| QAction* selectedAction = menu.exec(event->globalPos()); | |
| if (selectedAction == closeTabAction) { | |
| // Close the clicked tab | |
| emit tabCloseRequested(tabIndex); | |
| } else if (selectedAction == closeOtherTabsAction) { | |
| // Close all tabs except the clicked one | |
| for (int i = count() - 1; i >= 0; --i) { | |
| if (i != tabIndex) { | |
| emit tabCloseRequested(i); | |
| } | |
| } | |
| } else if (selectedAction == closeTabsToRightAction) { | |
| // Close all tabs to the right of the clicked one | |
| for (int i = count() - 1; i > tabIndex; --i) { | |
| emit tabCloseRequested(i); | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check
title.isEmpty()may reject valid tabs with empty titles. Consider saving tabs even with empty titles, as some pages may legitimately have no title yet, or remove only the URL check if that's the critical validation. This could prevent users from reopening legitimately closed tabs.