瀏覽代碼

Ladybird: Add a context menu to the tab bar

This shows the following actions:

* Reload Tab
* Duplicate Tab
* Move Tab
  * Move to Start
  * Move to End
* Close Tab
* Close Other Tabs
  * Close Tabs to Left
  * Close Tabs to Right
  * Close Other Tabs
Jamie Mansfield 1 年之前
父節點
當前提交
17fc995ee4
共有 6 個文件被更改,包括 98 次插入1 次删除
  1. 5 0
      Ladybird/Qt/BrowserWindow.cpp
  2. 2 0
      Ladybird/Qt/BrowserWindow.h
  3. 64 0
      Ladybird/Qt/Tab.cpp
  4. 4 0
      Ladybird/Qt/Tab.h
  5. 18 1
      Ladybird/Qt/TabBar.cpp
  6. 5 0
      Ladybird/Qt/TabBar.h

+ 5 - 0
Ladybird/Qt/BrowserWindow.cpp

@@ -625,6 +625,11 @@ void BrowserWindow::close_tab(int index)
         close();
         close();
 }
 }
 
 
+void BrowserWindow::move_tab(int old_index, int new_index)
+{
+    m_tabs_container->tabBar()->moveTab(old_index, new_index);
+}
+
 void BrowserWindow::open_file()
 void BrowserWindow::open_file()
 {
 {
     m_current_tab->open_file();
     m_current_tab->open_file();

+ 2 - 0
Ladybird/Qt/BrowserWindow.h

@@ -34,6 +34,7 @@ public:
 
 
     WebContentView& view() const { return m_current_tab->view(); }
     WebContentView& view() const { return m_current_tab->view(); }
 
 
+    int tab_count() { return m_tabs_container->count(); }
     int tab_index(Tab*);
     int tab_index(Tab*);
     Tab& create_new_tab(Web::HTML::ActivateTab activate_tab);
     Tab& create_new_tab(Web::HTML::ActivateTab activate_tab);
 
 
@@ -98,6 +99,7 @@ public slots:
     Tab& new_child_tab(Web::HTML::ActivateTab, Tab& parent, Web::HTML::WebViewHints, Optional<u64> page_index);
     Tab& new_child_tab(Web::HTML::ActivateTab, Tab& parent, Web::HTML::WebViewHints, Optional<u64> page_index);
     void activate_tab(int index);
     void activate_tab(int index);
     void close_tab(int index);
     void close_tab(int index);
+    void move_tab(int old_index, int new_index);
     void close_current_tab();
     void close_current_tab();
     void open_next_tab();
     void open_next_tab();
     void open_previous_tab();
     void open_previous_tab();

+ 64 - 0
Ladybird/Qt/Tab.cpp

@@ -1,6 +1,7 @@
 /*
 /*
  * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
  * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
  * Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
  * Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
+ * Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
@@ -405,6 +406,69 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St
         emit navigation_buttons_state_changed(tab_index());
         emit navigation_buttons_state_changed(tab_index());
     };
     };
 
 
+    auto* reload_tab_action = new QAction("&Reload Tab", this);
+    QObject::connect(reload_tab_action, &QAction::triggered, this, [this]() {
+        reload();
+    });
+
+    auto* duplicate_tab_action = new QAction("&Duplicate Tab", this);
+    QObject::connect(duplicate_tab_action, &QAction::triggered, this, [this]() {
+        m_window->new_tab_from_url(view().url(), Web::HTML::ActivateTab::Yes);
+    });
+
+    auto* move_to_start_action = new QAction("Move to &Start", this);
+    QObject::connect(move_to_start_action, &QAction::triggered, this, [this]() {
+        m_window->move_tab(tab_index(), 0);
+    });
+
+    auto* move_to_end_action = new QAction("Move to &End", this);
+    QObject::connect(move_to_end_action, &QAction::triggered, this, [this]() {
+        m_window->move_tab(tab_index(), m_window->tab_count() - 1);
+    });
+
+    auto* close_tab_action = new QAction("&Close Tab", this);
+    QObject::connect(close_tab_action, &QAction::triggered, this, [this]() {
+        view().on_close();
+    });
+
+    auto* close_tabs_to_left_action = new QAction("C&lose Tabs to Left", this);
+    QObject::connect(close_tabs_to_left_action, &QAction::triggered, this, [this]() {
+        for (auto i = tab_index() - 1; i >= 0; i--) {
+            m_window->close_tab(i);
+        }
+    });
+
+    auto* close_tabs_to_right_action = new QAction("Close Tabs to R&ight", this);
+    QObject::connect(close_tabs_to_right_action, &QAction::triggered, this, [this]() {
+        for (auto i = m_window->tab_count() - 1; i > tab_index(); i--) {
+            m_window->close_tab(i);
+        }
+    });
+
+    auto* close_other_tabs_action = new QAction("Cl&ose Other Tabs", this);
+    QObject::connect(close_other_tabs_action, &QAction::triggered, this, [this]() {
+        for (auto i = m_window->tab_count() - 1; i >= 0; i--) {
+            if (i == tab_index())
+                continue;
+
+            m_window->close_tab(i);
+        }
+    });
+
+    m_context_menu = new QMenu("Context menu", this);
+    m_context_menu->addAction(reload_tab_action);
+    m_context_menu->addAction(duplicate_tab_action);
+    m_context_menu->addSeparator();
+    auto* move_tab_menu = m_context_menu->addMenu("Mo&ve Tab");
+    move_tab_menu->addAction(move_to_start_action);
+    move_tab_menu->addAction(move_to_end_action);
+    m_context_menu->addSeparator();
+    m_context_menu->addAction(close_tab_action);
+    auto* close_multiple_tabs_menu = m_context_menu->addMenu("Close &Multiple Tabs");
+    close_multiple_tabs_menu->addAction(close_tabs_to_left_action);
+    close_multiple_tabs_menu->addAction(close_tabs_to_right_action);
+    close_multiple_tabs_menu->addAction(close_other_tabs_action);
+
     auto* search_selected_text_action = new QAction("&Search for <query>", this);
     auto* search_selected_text_action = new QAction("&Search for <query>", this);
     search_selected_text_action->setIcon(load_icon_from_uri("resource://icons/16x16/find.png"sv));
     search_selected_text_action->setIcon(load_icon_from_uri("resource://icons/16x16/find.png"sv));
     QObject::connect(search_selected_text_action, &QAction::triggered, this, [this]() {
     QObject::connect(search_selected_text_action, &QAction::triggered, this, [this]() {

+ 4 - 0
Ladybird/Qt/Tab.h

@@ -54,6 +54,8 @@ public:
     QIcon const& favicon() const { return m_favicon; }
     QIcon const& favicon() const { return m_favicon; }
     QString const& title() const { return m_title; }
     QString const& title() const { return m_title; }
 
 
+    QMenu* context_menu() const { return m_context_menu; }
+
     void update_navigation_buttons_state();
     void update_navigation_buttons_state();
 
 
 public slots:
 public slots:
@@ -91,6 +93,8 @@ private:
     QLabel* m_hover_label { nullptr };
     QLabel* m_hover_label { nullptr };
     QIcon m_favicon;
     QIcon m_favicon;
 
 
+    QMenu* m_context_menu { nullptr };
+
     QMenu* m_page_context_menu { nullptr };
     QMenu* m_page_context_menu { nullptr };
     Optional<String> m_page_context_menu_search_text;
     Optional<String> m_page_context_menu_search_text;
 
 

+ 18 - 1
Ladybird/Qt/TabBar.cpp

@@ -1,16 +1,25 @@
 /*
 /*
  * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
  * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
+#include "Tab.h"
 #include <AK/StdLibExtras.h>
 #include <AK/StdLibExtras.h>
+#include <AK/TypeCasts.h>
 #include <Ladybird/Qt/TabBar.h>
 #include <Ladybird/Qt/TabBar.h>
+#include <QContextMenuEvent>
 #include <QEvent>
 #include <QEvent>
 #include <QPushButton>
 #include <QPushButton>
 
 
 namespace Ladybird {
 namespace Ladybird {
 
 
+TabBar::TabBar(QWidget* parent)
+    : QTabBar(parent)
+{
+}
+
 QSize TabBar::tabSizeHint(int index) const
 QSize TabBar::tabSizeHint(int index) const
 {
 {
     auto width = this->width() / count();
     auto width = this->width() / count();
@@ -22,11 +31,19 @@ QSize TabBar::tabSizeHint(int index) const
     return hint;
     return hint;
 }
 }
 
 
+void TabBar::contextMenuEvent(QContextMenuEvent* event)
+{
+    auto* tab_widget = verify_cast<QTabWidget>(this->parent());
+    auto* tab = verify_cast<Tab>(tab_widget->widget(tabAt(event->pos())));
+    if (tab)
+        tab->context_menu()->exec(event->globalPos());
+}
+
 TabWidget::TabWidget(QWidget* parent)
 TabWidget::TabWidget(QWidget* parent)
     : QTabWidget(parent)
     : QTabWidget(parent)
 {
 {
     // This must be called first, otherwise several of the options below have no effect.
     // This must be called first, otherwise several of the options below have no effect.
-    setTabBar(new TabBar());
+    setTabBar(new TabBar(this));
 
 
     setDocumentMode(true);
     setDocumentMode(true);
     setElideMode(Qt::TextElideMode::ElideRight);
     setElideMode(Qt::TextElideMode::ElideRight);

+ 5 - 0
Ladybird/Qt/TabBar.h

@@ -1,5 +1,6 @@
 /*
 /*
  * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
  * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
@@ -10,6 +11,7 @@
 #include <QTabBar>
 #include <QTabBar>
 #include <QTabWidget>
 #include <QTabWidget>
 
 
+class QContextMenuEvent;
 class QEvent;
 class QEvent;
 class QIcon;
 class QIcon;
 class QWidget;
 class QWidget;
@@ -20,7 +22,10 @@ class TabBar : public QTabBar {
     Q_OBJECT
     Q_OBJECT
 
 
 public:
 public:
+    explicit TabBar(QWidget* parent = nullptr);
+
     virtual QSize tabSizeHint(int index) const override;
     virtual QSize tabSizeHint(int index) const override;
+    virtual void contextMenuEvent(QContextMenuEvent* event) override;
 };
 };
 
 
 class TabWidget : public QTabWidget {
 class TabWidget : public QTabWidget {