2022-07-05 22:18:21 +00:00
|
|
|
/*
|
2022-07-19 10:23:11 +00:00
|
|
|
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
2022-07-05 22:18:21 +00:00
|
|
|
* Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Tab.h"
|
|
|
|
#include "BrowserWindow.h"
|
2022-07-14 03:41:13 +00:00
|
|
|
#include "Settings.h"
|
2022-10-03 22:59:08 +00:00
|
|
|
#include "Utilities.h"
|
2022-10-22 21:42:00 +00:00
|
|
|
#include <Browser/History.h>
|
2022-07-05 22:18:21 +00:00
|
|
|
#include <QCoreApplication>
|
2022-09-09 12:23:36 +00:00
|
|
|
#include <QFont>
|
|
|
|
#include <QFontMetrics>
|
2022-10-05 13:23:41 +00:00
|
|
|
#include <QPlainTextEdit>
|
2022-07-13 02:39:38 +00:00
|
|
|
#include <QPoint>
|
2022-09-09 12:23:36 +00:00
|
|
|
#include <QResizeEvent>
|
2022-07-05 22:18:21 +00:00
|
|
|
|
2022-12-04 18:43:54 +00:00
|
|
|
extern DeprecatedString s_serenity_resource_root;
|
2022-07-14 03:41:13 +00:00
|
|
|
extern Browser::Settings* s_settings;
|
2022-07-05 22:18:21 +00:00
|
|
|
|
2022-11-14 16:08:44 +00:00
|
|
|
Tab::Tab(BrowserWindow* window, int webdriver_fd_passing_socket)
|
2022-10-01 18:46:24 +00:00
|
|
|
: QWidget(window)
|
|
|
|
, m_window(window)
|
2022-07-05 22:18:21 +00:00
|
|
|
{
|
|
|
|
m_layout = new QBoxLayout(QBoxLayout::Direction::TopToBottom, this);
|
2022-09-09 12:27:59 +00:00
|
|
|
m_layout->setSpacing(0);
|
2022-07-05 22:18:21 +00:00
|
|
|
m_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
2022-11-14 16:08:44 +00:00
|
|
|
m_view = new WebContentView(webdriver_fd_passing_socket);
|
2022-10-01 18:46:24 +00:00
|
|
|
m_toolbar = new QToolBar(this);
|
|
|
|
m_location_edit = new QLineEdit(this);
|
2022-07-05 22:18:21 +00:00
|
|
|
|
2022-09-09 12:23:36 +00:00
|
|
|
m_hover_label = new QLabel(this);
|
2022-09-09 13:19:18 +00:00
|
|
|
m_hover_label->hide();
|
2022-09-09 12:23:36 +00:00
|
|
|
m_hover_label->setFrameShape(QFrame::Shape::Box);
|
|
|
|
m_hover_label->setAutoFillBackground(true);
|
|
|
|
|
2022-09-12 07:12:04 +00:00
|
|
|
auto* focus_location_editor_action = new QAction("Edit Location");
|
|
|
|
focus_location_editor_action->setShortcut(QKeySequence("Ctrl+L"));
|
|
|
|
addAction(focus_location_editor_action);
|
2022-07-07 00:56:09 +00:00
|
|
|
|
2022-07-05 22:18:21 +00:00
|
|
|
m_layout->addWidget(m_toolbar);
|
|
|
|
m_layout->addWidget(m_view);
|
|
|
|
|
2022-07-06 13:38:50 +00:00
|
|
|
auto back_icon_path = QString("%1/res/icons/16x16/go-back.png").arg(s_serenity_resource_root.characters());
|
|
|
|
auto forward_icon_path = QString("%1/res/icons/16x16/go-forward.png").arg(s_serenity_resource_root.characters());
|
|
|
|
auto home_icon_path = QString("%1/res/icons/16x16/go-home.png").arg(s_serenity_resource_root.characters());
|
2022-07-05 22:18:21 +00:00
|
|
|
auto reload_icon_path = QString("%1/res/icons/16x16/reload.png").arg(s_serenity_resource_root.characters());
|
2022-07-06 13:38:50 +00:00
|
|
|
m_back_action = make<QAction>(QIcon(back_icon_path), "Back");
|
2022-09-18 06:53:33 +00:00
|
|
|
m_back_action->setEnabled(false);
|
2022-09-17 16:06:08 +00:00
|
|
|
m_back_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Back));
|
2022-07-06 13:38:50 +00:00
|
|
|
m_forward_action = make<QAction>(QIcon(forward_icon_path), "Forward");
|
2022-09-18 06:53:33 +00:00
|
|
|
m_forward_action->setEnabled(false);
|
2022-09-17 16:06:08 +00:00
|
|
|
m_forward_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Forward));
|
2022-07-06 13:38:50 +00:00
|
|
|
m_home_action = make<QAction>(QIcon(home_icon_path), "Home");
|
|
|
|
m_reload_action = make<QAction>(QIcon(reload_icon_path), "Reload");
|
|
|
|
m_reload_action->setShortcut(QKeySequence("Ctrl+R"));
|
|
|
|
|
|
|
|
m_toolbar->addAction(m_back_action);
|
|
|
|
m_toolbar->addAction(m_forward_action);
|
|
|
|
m_toolbar->addAction(m_reload_action);
|
|
|
|
m_toolbar->addAction(m_home_action);
|
2022-07-05 22:18:21 +00:00
|
|
|
m_toolbar->addWidget(m_location_edit);
|
|
|
|
|
2022-10-05 13:23:41 +00:00
|
|
|
QObject::connect(m_view, &WebContentView::link_hovered, [this](QString const& title) {
|
2022-09-09 12:23:36 +00:00
|
|
|
m_hover_label->setText(title);
|
|
|
|
update_hover_label();
|
|
|
|
m_hover_label->show();
|
2022-07-13 02:39:38 +00:00
|
|
|
});
|
2022-10-05 13:23:41 +00:00
|
|
|
QObject::connect(m_view, &WebContentView::link_unhovered, [this] {
|
2022-09-09 12:23:36 +00:00
|
|
|
m_hover_label->hide();
|
2022-07-13 02:39:38 +00:00
|
|
|
});
|
2022-07-05 22:18:21 +00:00
|
|
|
|
2022-11-08 01:00:24 +00:00
|
|
|
QObject::connect(m_view, &WebContentView::back_mouse_button, [this] {
|
|
|
|
back();
|
|
|
|
});
|
|
|
|
|
|
|
|
QObject::connect(m_view, &WebContentView::forward_mouse_button, [this] {
|
|
|
|
forward();
|
|
|
|
});
|
|
|
|
|
2022-11-24 00:52:16 +00:00
|
|
|
QObject::connect(m_view, &WebContentView::load_started, [this](const URL& url, bool is_redirect) {
|
|
|
|
// If we are loading due to a redirect, we replace the current history entry
|
|
|
|
// with the loaded URL
|
|
|
|
if (is_redirect) {
|
|
|
|
m_history.replace_current(url, m_title.toUtf8().data());
|
|
|
|
}
|
|
|
|
|
2022-12-04 18:43:54 +00:00
|
|
|
m_location_edit->setText(url.to_deprecated_string().characters());
|
2022-11-08 12:01:20 +00:00
|
|
|
|
|
|
|
// Don't add to history if back or forward is pressed
|
|
|
|
if (!m_is_history_navigation) {
|
|
|
|
m_history.push(url, m_title.toUtf8().data());
|
|
|
|
}
|
|
|
|
m_is_history_navigation = false;
|
|
|
|
|
2022-09-18 06:53:33 +00:00
|
|
|
m_back_action->setEnabled(m_history.can_go_back());
|
|
|
|
m_forward_action->setEnabled(m_history.can_go_forward());
|
2022-07-06 13:38:50 +00:00
|
|
|
});
|
2022-07-05 22:18:21 +00:00
|
|
|
QObject::connect(m_location_edit, &QLineEdit::returnPressed, this, &Tab::location_edit_return_pressed);
|
2022-10-05 13:23:41 +00:00
|
|
|
QObject::connect(m_view, &WebContentView::title_changed, this, &Tab::page_title_changed);
|
|
|
|
QObject::connect(m_view, &WebContentView::favicon_changed, this, &Tab::page_favicon_changed);
|
2022-07-05 22:18:21 +00:00
|
|
|
|
2022-07-06 13:38:50 +00:00
|
|
|
QObject::connect(m_back_action, &QAction::triggered, this, &Tab::back);
|
|
|
|
QObject::connect(m_forward_action, &QAction::triggered, this, &Tab::forward);
|
|
|
|
QObject::connect(m_home_action, &QAction::triggered, this, &Tab::home);
|
|
|
|
QObject::connect(m_reload_action, &QAction::triggered, this, &Tab::reload);
|
2022-09-12 07:12:04 +00:00
|
|
|
QObject::connect(focus_location_editor_action, &QAction::triggered, this, &Tab::focus_location_editor);
|
2022-10-05 13:23:41 +00:00
|
|
|
|
|
|
|
QObject::connect(m_view, &WebContentView::got_source, this, [this](AK::URL, QString const& source) {
|
|
|
|
auto* text_edit = new QPlainTextEdit(this);
|
|
|
|
text_edit->setWindowFlags(Qt::Window);
|
|
|
|
text_edit->setFont(QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont));
|
|
|
|
text_edit->resize(800, 600);
|
|
|
|
text_edit->setPlainText(source);
|
|
|
|
text_edit->show();
|
|
|
|
});
|
2022-10-07 11:35:40 +00:00
|
|
|
|
2022-11-14 16:24:06 +00:00
|
|
|
QObject::connect(m_view, &WebContentView::navigate_back, this, &Tab::back);
|
|
|
|
QObject::connect(m_view, &WebContentView::navigate_forward, this, &Tab::forward);
|
|
|
|
QObject::connect(m_view, &WebContentView::refresh, this, &Tab::reload);
|
|
|
|
QObject::connect(m_view, &WebContentView::restore_window, this, [this]() {
|
|
|
|
m_window->showNormal();
|
|
|
|
});
|
|
|
|
QObject::connect(m_view, &WebContentView::reposition_window, this, [this](auto const& position) {
|
|
|
|
m_window->move(position.x(), position.y());
|
|
|
|
return Gfx::IntPoint { m_window->x(), m_window->y() };
|
|
|
|
});
|
|
|
|
QObject::connect(m_view, &WebContentView::resize_window, this, [this](auto const& size) {
|
|
|
|
m_window->resize(size.width(), size.height());
|
|
|
|
return Gfx::IntSize { m_window->width(), m_window->height() };
|
|
|
|
});
|
|
|
|
QObject::connect(m_view, &WebContentView::maximize_window, this, [this]() {
|
|
|
|
m_window->showMaximized();
|
|
|
|
return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
|
|
|
|
});
|
|
|
|
QObject::connect(m_view, &WebContentView::minimize_window, this, [this]() {
|
|
|
|
m_window->showMinimized();
|
|
|
|
return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
|
|
|
|
});
|
|
|
|
QObject::connect(m_view, &WebContentView::fullscreen_window, this, [this]() {
|
|
|
|
m_window->showFullScreen();
|
|
|
|
return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
|
|
|
|
});
|
|
|
|
|
2022-10-07 11:35:40 +00:00
|
|
|
// FIXME: This is a hack to make the JS console usable in new windows.
|
|
|
|
// Something else should ensure that there's an initial about:blank document loaded in the view.
|
2022-11-09 12:26:40 +00:00
|
|
|
// We set m_is_history_navigation = true so that the initial about:blank doesn't get added to the history.
|
2022-11-14 16:08:44 +00:00
|
|
|
//
|
|
|
|
// Note we *don't* do this if we are connected to a WebDriver, as the Set URL command may come in very
|
|
|
|
// quickly, and become replaced by this load.
|
|
|
|
if (webdriver_fd_passing_socket == -1) {
|
|
|
|
m_is_history_navigation = true;
|
|
|
|
m_view->load("about:blank"sv);
|
|
|
|
}
|
2022-09-12 07:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::focus_location_editor()
|
|
|
|
{
|
|
|
|
m_location_edit->setFocus();
|
|
|
|
m_location_edit->selectAll();
|
2022-07-06 13:38:50 +00:00
|
|
|
}
|
|
|
|
|
2022-07-14 15:32:51 +00:00
|
|
|
void Tab::navigate(QString url)
|
2022-07-06 13:38:50 +00:00
|
|
|
{
|
2022-07-19 18:08:02 +00:00
|
|
|
if (!url.startsWith("http://", Qt::CaseInsensitive) && !url.startsWith("https://", Qt::CaseInsensitive) && !url.startsWith("file://", Qt::CaseInsensitive))
|
2022-07-14 15:32:51 +00:00
|
|
|
url = "http://" + url;
|
2022-12-04 18:43:54 +00:00
|
|
|
view().load(ak_deprecated_string_from_qstring(url));
|
2022-07-06 13:38:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::back()
|
|
|
|
{
|
|
|
|
if (!m_history.can_go_back())
|
|
|
|
return;
|
|
|
|
|
2022-11-08 12:01:20 +00:00
|
|
|
m_is_history_navigation = true;
|
2022-07-06 13:38:50 +00:00
|
|
|
m_history.go_back();
|
2022-12-04 18:43:54 +00:00
|
|
|
view().load(m_history.current().url.to_deprecated_string());
|
2022-07-06 13:38:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::forward()
|
|
|
|
{
|
|
|
|
if (!m_history.can_go_forward())
|
|
|
|
return;
|
|
|
|
|
2022-11-08 12:01:20 +00:00
|
|
|
m_is_history_navigation = true;
|
2022-07-06 13:38:50 +00:00
|
|
|
m_history.go_forward();
|
2022-12-04 18:43:54 +00:00
|
|
|
view().load(m_history.current().url.to_deprecated_string());
|
2022-07-06 13:38:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::home()
|
|
|
|
{
|
2022-07-14 03:41:13 +00:00
|
|
|
navigate(s_settings->homepage());
|
2022-07-05 22:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::reload()
|
|
|
|
{
|
2022-11-08 23:35:55 +00:00
|
|
|
m_is_history_navigation = true;
|
2022-12-04 18:43:54 +00:00
|
|
|
view().load(m_history.current().url.to_deprecated_string());
|
2022-07-05 22:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::location_edit_return_pressed()
|
|
|
|
{
|
2022-07-06 13:38:50 +00:00
|
|
|
navigate(m_location_edit->text());
|
2022-07-05 22:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::page_title_changed(QString title)
|
|
|
|
{
|
2022-07-06 13:38:50 +00:00
|
|
|
m_title = title;
|
2022-12-04 18:43:54 +00:00
|
|
|
m_history.update_title(ak_deprecated_string_from_qstring(m_title));
|
2022-07-05 22:18:21 +00:00
|
|
|
emit title_changed(tab_index(), std::move(title));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::page_favicon_changed(QIcon icon)
|
|
|
|
{
|
|
|
|
emit favicon_changed(tab_index(), std::move(icon));
|
|
|
|
}
|
|
|
|
|
|
|
|
int Tab::tab_index()
|
|
|
|
{
|
2022-09-21 19:17:13 +00:00
|
|
|
return m_window->tab_index(this);
|
2022-07-05 22:18:21 +00:00
|
|
|
}
|
2022-07-08 12:14:40 +00:00
|
|
|
|
2022-12-04 18:43:54 +00:00
|
|
|
void Tab::debug_request(DeprecatedString const& request, DeprecatedString const& argument)
|
2022-07-08 12:14:40 +00:00
|
|
|
{
|
2022-10-03 21:53:04 +00:00
|
|
|
if (request == "dump-history")
|
|
|
|
m_history.dump();
|
|
|
|
else
|
|
|
|
m_view->debug_request(request, argument);
|
2022-07-08 12:14:40 +00:00
|
|
|
}
|
2022-09-09 12:23:36 +00:00
|
|
|
|
|
|
|
void Tab::resizeEvent(QResizeEvent* event)
|
|
|
|
{
|
|
|
|
QWidget::resizeEvent(event);
|
|
|
|
if (m_hover_label->isVisible())
|
|
|
|
update_hover_label();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tab::update_hover_label()
|
|
|
|
{
|
|
|
|
m_hover_label->resize(QFontMetrics(m_hover_label->font()).boundingRect(m_hover_label->text()).adjusted(-4, -2, 4, 2).size());
|
|
|
|
m_hover_label->move(6, height() - m_hover_label->height() - 8);
|
|
|
|
m_hover_label->raise();
|
|
|
|
}
|