mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
4850a2d272
This allows requests like dumping the DOM tree to be forwarded to the correct tab. Otherwise, the event would be forwarded to the most recently created tab.
296 lines
12 KiB
C++
296 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
|
* Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
|
|
* Copyright (c) 2022, Filiph Sandström <filiph.sandstrom@filfatstudios.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "BrowserWindow.h"
|
|
#include "Settings.h"
|
|
#include "SettingsDialog.h"
|
|
#include "WebView.h"
|
|
#include <AK/TypeCasts.h>
|
|
#include <QAction>
|
|
#include <QDialog>
|
|
#include <QPlainTextEdit>
|
|
|
|
extern String s_serenity_resource_root;
|
|
extern Browser::Settings* s_settings;
|
|
|
|
BrowserWindow::BrowserWindow()
|
|
{
|
|
m_tabs_container = new QTabWidget;
|
|
m_tabs_container->setElideMode(Qt::TextElideMode::ElideRight);
|
|
m_tabs_container->setMovable(true);
|
|
m_tabs_container->setTabsClosable(true);
|
|
m_tabs_container->setDocumentMode(true);
|
|
|
|
m_tabs_bar = m_tabs_container->findChild<QTabBar*>();
|
|
m_tabs_bar->hide();
|
|
|
|
auto* menu = menuBar()->addMenu("&File");
|
|
|
|
auto* new_tab_action = new QAction("New &Tab");
|
|
new_tab_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_T));
|
|
menu->addAction(new_tab_action);
|
|
|
|
auto* settings_action = new QAction("&Settings");
|
|
settings_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Comma));
|
|
menu->addAction(settings_action);
|
|
|
|
auto* close_current_tab_action = new QAction("Close Current Tab");
|
|
close_current_tab_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W));
|
|
menu->addAction(close_current_tab_action);
|
|
|
|
auto* quit_action = new QAction("&Quit");
|
|
quit_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
|
|
menu->addAction(quit_action);
|
|
|
|
auto* view_menu = menuBar()->addMenu("&View");
|
|
|
|
auto* open_next_tab_action = new QAction("Open &Next Tab");
|
|
open_next_tab_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
|
|
view_menu->addAction(open_next_tab_action);
|
|
QObject::connect(open_next_tab_action, &QAction::triggered, this, &BrowserWindow::open_next_tab);
|
|
|
|
auto* open_previous_tab_action = new QAction("Open &Previous Tab");
|
|
open_previous_tab_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
|
|
view_menu->addAction(open_previous_tab_action);
|
|
QObject::connect(open_previous_tab_action, &QAction::triggered, this, &BrowserWindow::open_previous_tab);
|
|
|
|
auto* inspect_menu = menuBar()->addMenu("&Inspect");
|
|
|
|
auto* view_source_action = new QAction("View &Source");
|
|
view_source_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-html.png").arg(s_serenity_resource_root.characters())));
|
|
view_source_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_U));
|
|
inspect_menu->addAction(view_source_action);
|
|
QObject::connect(view_source_action, &QAction::triggered, this, [this] {
|
|
if (m_current_tab) {
|
|
auto source = m_current_tab->view().source();
|
|
|
|
auto* text_edit = new QPlainTextEdit;
|
|
text_edit->setFont(QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont));
|
|
text_edit->resize(800, 600);
|
|
text_edit->setPlainText(source.characters());
|
|
text_edit->show();
|
|
}
|
|
});
|
|
|
|
auto* js_console_action = new QAction("Show &JS Console");
|
|
js_console_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-javascript.png").arg(s_serenity_resource_root.characters())));
|
|
js_console_action->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_J));
|
|
inspect_menu->addAction(js_console_action);
|
|
QObject::connect(js_console_action, &QAction::triggered, this, [this] {
|
|
if (m_current_tab) {
|
|
m_current_tab->view().show_js_console();
|
|
}
|
|
});
|
|
|
|
auto* debug_menu = menuBar()->addMenu("&Debug");
|
|
|
|
auto* dump_dom_tree_action = new QAction("Dump DOM Tree");
|
|
dump_dom_tree_action->setIcon(QIcon(QString("%1/res/icons/browser/dom-tree.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(dump_dom_tree_action);
|
|
QObject::connect(dump_dom_tree_action, &QAction::triggered, this, [this] {
|
|
debug_request("dump-dom-tree");
|
|
});
|
|
|
|
auto* dump_layout_tree_action = new QAction("Dump Layout Tree");
|
|
dump_layout_tree_action->setIcon(QIcon(QString("%1/res/icons/16x16/layout.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(dump_layout_tree_action);
|
|
QObject::connect(dump_layout_tree_action, &QAction::triggered, this, [this] {
|
|
debug_request("dump-layout-tree");
|
|
});
|
|
|
|
auto* dump_stacking_context_tree_action = new QAction("Dump Stacking Context Tree");
|
|
dump_stacking_context_tree_action->setIcon(QIcon(QString("%1/res/icons/16x16/layers.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(dump_stacking_context_tree_action);
|
|
QObject::connect(dump_stacking_context_tree_action, &QAction::triggered, this, [this] {
|
|
debug_request("dump-stacking-context-tree");
|
|
});
|
|
|
|
auto* dump_style_sheets_action = new QAction("Dump Style Sheets");
|
|
dump_style_sheets_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-css.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(dump_style_sheets_action);
|
|
QObject::connect(dump_style_sheets_action, &QAction::triggered, this, [this] {
|
|
debug_request("dump-style-sheets");
|
|
});
|
|
|
|
auto* dump_history_action = new QAction("Dump History");
|
|
dump_history_action->setIcon(QIcon(QString("%1/res/icons/16x16/history.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(dump_history_action);
|
|
QObject::connect(dump_history_action, &QAction::triggered, this, [this] {
|
|
debug_request("dump-history");
|
|
});
|
|
|
|
auto* dump_cookies_action = new QAction("Dump Cookies");
|
|
dump_cookies_action->setIcon(QIcon(QString("%1/res/icons/browser/cookie.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(dump_cookies_action);
|
|
QObject::connect(dump_cookies_action, &QAction::triggered, this, [this] {
|
|
debug_request("dump-cookies");
|
|
});
|
|
|
|
auto* dump_local_storage_action = new QAction("Dump Local Storage");
|
|
dump_local_storage_action->setIcon(QIcon(QString("%1/res/icons/browser/local-storage.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(dump_local_storage_action);
|
|
QObject::connect(dump_local_storage_action, &QAction::triggered, this, [this] {
|
|
debug_request("dump-local-storage");
|
|
});
|
|
|
|
debug_menu->addSeparator();
|
|
|
|
auto* show_line_box_borders_action = new QAction("Show Line Box Borders");
|
|
show_line_box_borders_action->setCheckable(true);
|
|
debug_menu->addAction(show_line_box_borders_action);
|
|
QObject::connect(show_line_box_borders_action, &QAction::triggered, this, [this, show_line_box_borders_action] {
|
|
bool state = show_line_box_borders_action->isChecked();
|
|
debug_request("set-line-box-borders", state ? "on" : "off");
|
|
});
|
|
|
|
debug_menu->addSeparator();
|
|
|
|
auto* collect_garbage_action = new QAction("Collect Garbage");
|
|
collect_garbage_action->setIcon(QIcon(QString("%1/res/icons/16x16/trash-can.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(collect_garbage_action);
|
|
QObject::connect(collect_garbage_action, &QAction::triggered, this, [this] {
|
|
debug_request("collect-garbage");
|
|
});
|
|
|
|
auto* clear_cache_action = new QAction("Clear Cache");
|
|
clear_cache_action->setIcon(QIcon(QString("%1/res/icons/browser/clear-cache.png").arg(s_serenity_resource_root.characters())));
|
|
debug_menu->addAction(clear_cache_action);
|
|
QObject::connect(clear_cache_action, &QAction::triggered, this, [this] {
|
|
debug_request("clear-cache");
|
|
});
|
|
|
|
debug_menu->addSeparator();
|
|
|
|
auto* enable_scripting_action = new QAction("Enable Scripting");
|
|
enable_scripting_action->setCheckable(true);
|
|
enable_scripting_action->setChecked(true);
|
|
debug_menu->addAction(enable_scripting_action);
|
|
QObject::connect(enable_scripting_action, &QAction::triggered, this, [this, enable_scripting_action] {
|
|
bool state = enable_scripting_action->isChecked();
|
|
debug_request("scripting", state ? "on" : "off");
|
|
});
|
|
|
|
auto* enable_same_origin_policy_action = new QAction("Enable Same-Origin Policy");
|
|
enable_same_origin_policy_action->setCheckable(true);
|
|
debug_menu->addAction(enable_same_origin_policy_action);
|
|
QObject::connect(enable_same_origin_policy_action, &QAction::triggered, this, [this, enable_same_origin_policy_action] {
|
|
bool state = enable_same_origin_policy_action->isChecked();
|
|
debug_request("same-origin-policy", state ? "on" : "off");
|
|
});
|
|
|
|
QObject::connect(new_tab_action, &QAction::triggered, this, &BrowserWindow::new_tab);
|
|
QObject::connect(settings_action, &QAction::triggered, this, [this] {
|
|
new SettingsDialog(this);
|
|
});
|
|
QObject::connect(quit_action, &QAction::triggered, this, &QMainWindow::close);
|
|
QObject::connect(m_tabs_container, &QTabWidget::currentChanged, [this](int index) {
|
|
setWindowTitle(QString("%1 - Ladybird").arg(m_tabs_container->tabText(index)));
|
|
setWindowIcon(m_tabs_container->tabIcon(index));
|
|
m_current_tab = verify_cast<Tab>(m_tabs_container->widget(index));
|
|
});
|
|
QObject::connect(m_tabs_container, &QTabWidget::tabCloseRequested, this, &BrowserWindow::close_tab);
|
|
QObject::connect(close_current_tab_action, &QAction::triggered, this, &BrowserWindow::close_current_tab);
|
|
|
|
new_tab();
|
|
|
|
setCentralWidget(m_tabs_container);
|
|
}
|
|
|
|
void BrowserWindow::debug_request(String const& request, String const& argument)
|
|
{
|
|
if (!m_current_tab)
|
|
return;
|
|
m_current_tab->debug_request(request, argument);
|
|
}
|
|
|
|
void BrowserWindow::new_tab()
|
|
{
|
|
auto tab = make<Tab>(this);
|
|
auto tab_ptr = tab.ptr();
|
|
m_tabs.append(std::move(tab));
|
|
|
|
if (m_current_tab == nullptr) {
|
|
m_current_tab = tab_ptr;
|
|
}
|
|
|
|
m_tabs_container->addTab(tab_ptr, "New Tab");
|
|
m_tabs_container->setCurrentWidget(tab_ptr);
|
|
|
|
QObject::connect(tab_ptr, &Tab::title_changed, this, &BrowserWindow::tab_title_changed);
|
|
QObject::connect(tab_ptr, &Tab::favicon_changed, this, &BrowserWindow::tab_favicon_changed);
|
|
|
|
if (m_tabs_container->count() > 1)
|
|
m_tabs_bar->show();
|
|
|
|
tab_ptr->focus_location_editor();
|
|
}
|
|
|
|
void BrowserWindow::close_tab(int index)
|
|
{
|
|
auto* tab = m_tabs_container->widget(index);
|
|
m_tabs_container->removeTab(index);
|
|
m_tabs.remove_first_matching([&](auto& entry) {
|
|
return entry == tab;
|
|
});
|
|
|
|
if (m_tabs_container->count() <= 1)
|
|
m_tabs_bar->hide();
|
|
}
|
|
|
|
void BrowserWindow::close_current_tab()
|
|
{
|
|
auto count = m_tabs_container->count() - 1;
|
|
if (!count)
|
|
close();
|
|
else
|
|
close_tab(m_tabs_container->currentIndex());
|
|
}
|
|
|
|
int BrowserWindow::tab_index(Tab* tab)
|
|
{
|
|
return m_tabs_container->indexOf(tab);
|
|
}
|
|
|
|
void BrowserWindow::tab_title_changed(int index, QString const& title)
|
|
{
|
|
if (title.isEmpty()) {
|
|
m_tabs_container->setTabText(index, "...");
|
|
setWindowTitle("Ladybird");
|
|
} else {
|
|
m_tabs_container->setTabText(index, title);
|
|
setWindowTitle(QString("%1 - Ladybird").arg(title));
|
|
}
|
|
}
|
|
|
|
void BrowserWindow::tab_favicon_changed(int index, QIcon icon)
|
|
{
|
|
m_tabs_container->setTabIcon(index, icon);
|
|
setWindowIcon(icon);
|
|
}
|
|
|
|
void BrowserWindow::open_next_tab()
|
|
{
|
|
if (m_tabs_container->count() <= 1)
|
|
return;
|
|
|
|
auto next_index = m_tabs_container->currentIndex() + 1;
|
|
if (next_index >= m_tabs_container->count())
|
|
next_index = 0;
|
|
m_tabs_container->setCurrentIndex(next_index);
|
|
}
|
|
|
|
void BrowserWindow::open_previous_tab()
|
|
{
|
|
if (m_tabs_container->count() <= 1)
|
|
return;
|
|
|
|
auto next_index = m_tabs_container->currentIndex() - 1;
|
|
if (next_index < 0)
|
|
next_index = m_tabs_container->count() - 1;
|
|
m_tabs_container->setCurrentIndex(next_index);
|
|
}
|