123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- /*
- * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include "BrowserWindow.h"
- #include "ConsoleWidget.h"
- #include "InspectorWidget.h"
- #include "Settings.h"
- #include "StringUtils.h"
- #include "TVGIconEngine.h"
- #include <LibGfx/ImageFormats/BMPWriter.h>
- #include <LibGfx/Painter.h>
- #include <LibWebView/SearchEngine.h>
- #include <LibWebView/SourceHighlighter.h>
- #include <LibWebView/URL.h>
- #include <QClipboard>
- #include <QColorDialog>
- #include <QCoreApplication>
- #include <QCursor>
- #include <QFileDialog>
- #include <QFont>
- #include <QFontMetrics>
- #include <QGuiApplication>
- #include <QImage>
- #include <QInputDialog>
- #include <QMenu>
- #include <QMessageBox>
- #include <QPainter>
- #include <QPoint>
- #include <QResizeEvent>
- extern DeprecatedString s_serenity_resource_root;
- namespace Ladybird {
- static QIcon create_tvg_icon_with_theme_colors(QString name, QPalette const& palette)
- {
- auto path = QString(":/Icons/%1.tvg").arg(name);
- auto icon_engine = TVGIconEngine::from_file(path);
- VERIFY(icon_engine);
- auto icon_filter = [](QColor color) {
- return [color = Color::from_argb(color.rgba64().toArgb32())](Gfx::Color icon_color) {
- return color.with_alpha((icon_color.alpha() * color.alpha()) / 255);
- };
- };
- icon_engine->add_filter(QIcon::Mode::Normal, icon_filter(palette.color(QPalette::ColorGroup::Normal, QPalette::ColorRole::ButtonText)));
- icon_engine->add_filter(QIcon::Mode::Disabled, icon_filter(palette.color(QPalette::ColorGroup::Disabled, QPalette::ColorRole::ButtonText)));
- return QIcon(icon_engine);
- }
- Tab::Tab(BrowserWindow* window, StringView webdriver_content_ipc_path, WebView::EnableCallgrindProfiling enable_callgrind_profiling, UseLagomNetworking use_lagom_networking, WebView::EnableGPUPainting enable_gpu_painting)
- : QWidget(window)
- , m_window(window)
- {
- m_layout = new QBoxLayout(QBoxLayout::Direction::TopToBottom, this);
- m_layout->setSpacing(0);
- m_layout->setContentsMargins(0, 0, 0, 0);
- m_view = new WebContentView(webdriver_content_ipc_path, enable_callgrind_profiling, use_lagom_networking, enable_gpu_painting);
- m_toolbar = new QToolBar(this);
- m_location_edit = new LocationEdit(this);
- m_hover_label = new QLabel(this);
- m_hover_label->hide();
- m_hover_label->setFrameShape(QFrame::Shape::Box);
- m_hover_label->setAutoFillBackground(true);
- auto* focus_location_editor_action = new QAction("Edit Location", this);
- focus_location_editor_action->setShortcut(QKeySequence("Ctrl+L"));
- addAction(focus_location_editor_action);
- m_layout->addWidget(m_toolbar);
- m_layout->addWidget(m_view);
- recreate_toolbar_icons();
- m_toolbar->addAction(&m_window->go_back_action());
- m_toolbar->addAction(&m_window->go_forward_action());
- m_toolbar->addAction(&m_window->reload_action());
- m_toolbar->addWidget(m_location_edit);
- m_toolbar->setIconSize({ 16, 16 });
- // This is a little awkward, but without this Qt shrinks the button to the size of the icon.
- // Note: toolButtonStyle="0" -> ToolButtonIconOnly.
- m_toolbar->setStyleSheet("QToolButton[toolButtonStyle=\"0\"]{width:24px;height:24px}");
- m_reset_zoom_button = new QToolButton(m_toolbar);
- m_reset_zoom_button->setToolButtonStyle(Qt::ToolButtonTextOnly);
- m_reset_zoom_button->setToolTip("Reset zoom level");
- m_reset_zoom_button_action = m_toolbar->addWidget(m_reset_zoom_button);
- m_reset_zoom_button_action->setVisible(false);
- QObject::connect(m_reset_zoom_button, &QAbstractButton::clicked, [this] {
- view().reset_zoom();
- update_reset_zoom_button();
- m_window->update_zoom_menu();
- });
- view().on_activate_tab = [this] {
- m_window->activate_tab(tab_index());
- };
- view().on_close = [this] {
- m_window->close_tab(tab_index());
- };
- view().on_link_hover = [this](auto const& url) {
- m_hover_label->setText(qstring_from_ak_deprecated_string(url.to_deprecated_string()));
- update_hover_label();
- m_hover_label->show();
- };
- view().on_link_unhover = [this]() {
- m_hover_label->hide();
- };
- view().on_load_start = [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());
- }
- m_location_edit->setText(url.to_deprecated_string().characters());
- m_location_edit->setCursorPosition(0);
- // 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;
- m_window->go_back_action().setEnabled(m_history.can_go_back());
- m_window->go_forward_action().setEnabled(m_history.can_go_forward());
- m_window->reload_action().setEnabled(!m_history.is_empty());
- if (m_inspector_widget)
- m_inspector_widget->clear_dom_json();
- if (m_console_widget)
- m_console_widget->reset();
- };
- view().on_load_finish = [this](auto&) {
- if (m_inspector_widget != nullptr && m_inspector_widget->isVisible()) {
- view().inspect_dom_tree();
- view().inspect_accessibility_tree();
- }
- };
- QObject::connect(m_location_edit, &QLineEdit::returnPressed, this, &Tab::location_edit_return_pressed);
- view().on_title_change = [this](auto const& title) {
- m_title = qstring_from_ak_deprecated_string(title);
- m_history.update_title(title);
- emit title_changed(tab_index(), m_title);
- };
- view().on_favicon_change = [this](auto const& bitmap) {
- auto qimage = QImage(bitmap.scanline_u8(0), bitmap.width(), bitmap.height(), QImage::Format_ARGB32);
- if (qimage.isNull())
- return;
- auto qpixmap = QPixmap::fromImage(qimage);
- if (qpixmap.isNull())
- return;
- emit favicon_changed(tab_index(), QIcon(qpixmap));
- };
- view().on_request_alert = [this](auto const& message) {
- m_dialog = new QMessageBox(QMessageBox::Icon::Warning, "Ladybird", qstring_from_ak_string(message), QMessageBox::StandardButton::Ok, &view());
- m_dialog->exec();
- view().alert_closed();
- m_dialog = nullptr;
- };
- view().on_request_confirm = [this](auto const& message) {
- m_dialog = new QMessageBox(QMessageBox::Icon::Question, "Ladybird", qstring_from_ak_string(message), QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel, &view());
- auto result = m_dialog->exec();
- view().confirm_closed(result == QMessageBox::StandardButton::Ok || result == QDialog::Accepted);
- m_dialog = nullptr;
- };
- view().on_request_prompt = [this](auto const& message, auto const& default_) {
- m_dialog = new QInputDialog(&view());
- auto& dialog = static_cast<QInputDialog&>(*m_dialog);
- dialog.setWindowTitle("Ladybird");
- dialog.setLabelText(qstring_from_ak_string(message));
- dialog.setTextValue(qstring_from_ak_string(default_));
- if (dialog.exec() == QDialog::Accepted)
- view().prompt_closed(ak_string_from_qstring(dialog.textValue()).release_value_but_fixme_should_propagate_errors());
- else
- view().prompt_closed({});
- m_dialog = nullptr;
- };
- view().on_request_set_prompt_text = [this](auto const& message) {
- if (m_dialog && is<QInputDialog>(*m_dialog))
- static_cast<QInputDialog&>(*m_dialog).setTextValue(qstring_from_ak_string(message));
- };
- view().on_request_accept_dialog = [this]() {
- if (m_dialog)
- m_dialog->accept();
- };
- view().on_request_dismiss_dialog = [this]() {
- if (m_dialog)
- m_dialog->reject();
- };
- view().on_request_color_picker = [this](Color current_color) {
- m_dialog = new QColorDialog(QColor(current_color.red(), current_color.green(), current_color.blue()), &view());
- auto& dialog = static_cast<QColorDialog&>(*m_dialog);
- dialog.setWindowTitle("Ladybird");
- dialog.setOption(QColorDialog::ShowAlphaChannel, false);
- if (dialog.exec() == QDialog::Accepted)
- view().color_picker_closed(Color(dialog.selectedColor().red(), dialog.selectedColor().green(), dialog.selectedColor().blue()));
- else
- view().color_picker_closed({});
- m_dialog = nullptr;
- };
- QObject::connect(focus_location_editor_action, &QAction::triggered, this, &Tab::focus_location_editor);
- view().on_received_source = [this](auto const& url, auto const& source) {
- auto html = WebView::highlight_source(url, source);
- m_window->new_tab(html, Web::HTML::ActivateTab::Yes);
- };
- view().on_navigate_back = [this]() {
- back();
- };
- view().on_navigate_forward = [this]() {
- forward();
- };
- view().on_refresh = [this]() {
- reload();
- };
- view().on_restore_window = [this]() {
- m_window->showNormal();
- };
- view().on_reposition_window = [this](auto const& position) {
- m_window->move(position.x(), position.y());
- return Gfx::IntPoint { m_window->x(), m_window->y() };
- };
- view().on_resize_window = [this](auto const& size) {
- m_window->resize(size.width(), size.height());
- return Gfx::IntSize { m_window->width(), m_window->height() };
- };
- view().on_maximize_window = [this]() {
- m_window->showMaximized();
- return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
- };
- view().on_minimize_window = [this]() {
- m_window->showMinimized();
- return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
- };
- view().on_fullscreen_window = [this]() {
- m_window->showFullScreen();
- return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
- };
- view().on_received_dom_tree = [this](auto& dom_tree) {
- if (m_inspector_widget)
- m_inspector_widget->set_dom_json(dom_tree);
- };
- view().on_received_accessibility_tree = [this](auto& accessibility_tree) {
- if (m_inspector_widget)
- m_inspector_widget->set_accessibility_json(accessibility_tree);
- };
- auto* search_selected_text_action = new QAction("&Search for <query>", this);
- search_selected_text_action->setIcon(QIcon(QString("%1/res/icons/16x16/find.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(search_selected_text_action, &QAction::triggered, this, [this]() {
- auto url = MUST(String::formatted(Settings::the()->search_engine().query_url, URL::percent_encode(*m_page_context_menu_search_text)));
- m_window->new_tab(qstring_from_ak_string(url), Web::HTML::ActivateTab::Yes);
- });
- auto* take_visible_screenshot_action = new QAction("Take &Visible Screenshot", this);
- take_visible_screenshot_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-image.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(take_visible_screenshot_action, &QAction::triggered, this, [this]() {
- if (auto result = view().take_screenshot(WebView::ViewImplementation::ScreenshotType::Visible); result.is_error()) {
- auto error = String::formatted("{}", result.error()).release_value_but_fixme_should_propagate_errors();
- QMessageBox::warning(this, "Ladybird", qstring_from_ak_string(error));
- }
- });
- auto* take_full_screenshot_action = new QAction("Take &Full Screenshot", this);
- take_full_screenshot_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-image.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(take_full_screenshot_action, &QAction::triggered, this, [this]() {
- if (auto result = view().take_screenshot(WebView::ViewImplementation::ScreenshotType::Full); result.is_error()) {
- auto error = String::formatted("{}", result.error()).release_value_but_fixme_should_propagate_errors();
- QMessageBox::warning(this, "Ladybird", qstring_from_ak_string(error));
- }
- });
- m_page_context_menu = make<QMenu>("Context menu", this);
- m_page_context_menu->addAction(&m_window->go_back_action());
- m_page_context_menu->addAction(&m_window->go_forward_action());
- m_page_context_menu->addAction(&m_window->reload_action());
- m_page_context_menu->addSeparator();
- m_page_context_menu->addAction(&m_window->copy_selection_action());
- m_page_context_menu->addAction(&m_window->select_all_action());
- m_page_context_menu->addSeparator();
- m_page_context_menu->addAction(search_selected_text_action);
- m_page_context_menu->addSeparator();
- m_page_context_menu->addAction(take_visible_screenshot_action);
- m_page_context_menu->addAction(take_full_screenshot_action);
- m_page_context_menu->addSeparator();
- m_page_context_menu->addAction(&m_window->view_source_action());
- m_page_context_menu->addAction(&m_window->inspect_dom_node_action());
- view().on_context_menu_request = [this, search_selected_text_action](Gfx::IntPoint) {
- auto selected_text = Settings::the()->enable_search()
- ? view().selected_text_with_whitespace_collapsed()
- : OptionalNone {};
- TemporaryChange change_url { m_page_context_menu_search_text, std::move(selected_text) };
- if (m_page_context_menu_search_text.has_value()) {
- auto action_text = WebView::format_search_query_for_display(Settings::the()->search_engine().query_url, *m_page_context_menu_search_text);
- search_selected_text_action->setText(qstring_from_ak_string(action_text));
- search_selected_text_action->setVisible(true);
- } else {
- search_selected_text_action->setVisible(false);
- }
- auto screen_position = QCursor::pos();
- m_page_context_menu->exec(screen_position);
- };
- auto* open_link_action = new QAction("&Open", this);
- open_link_action->setIcon(QIcon(QString("%1/res/icons/16x16/go-forward.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_link_action, &QAction::triggered, this, [this]() {
- open_link(m_link_context_menu_url);
- });
- auto* open_link_in_new_tab_action = new QAction("&Open in New &Tab", this);
- open_link_in_new_tab_action->setIcon(QIcon(QString("%1/res/icons/16x16/new-tab.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_link_in_new_tab_action, &QAction::triggered, this, [this]() {
- open_link_in_new_tab(m_link_context_menu_url);
- });
- auto* copy_url_action = new QAction("Copy &URL", this);
- copy_url_action->setIcon(QIcon(QString("%1/res/icons/16x16/edit-copy.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(copy_url_action, &QAction::triggered, this, [this]() {
- copy_link_url(m_link_context_menu_url);
- });
- m_link_context_menu = make<QMenu>("Link context menu", this);
- m_link_context_menu->addAction(open_link_action);
- m_link_context_menu->addAction(open_link_in_new_tab_action);
- m_link_context_menu->addSeparator();
- m_link_context_menu->addAction(copy_url_action);
- m_link_context_menu->addSeparator();
- m_link_context_menu->addAction(&m_window->inspect_dom_node_action());
- view().on_link_context_menu_request = [this](auto const& url, Gfx::IntPoint) {
- m_link_context_menu_url = url;
- auto screen_position = QCursor::pos();
- m_link_context_menu->exec(screen_position);
- };
- auto* open_image_action = new QAction("&Open Image", this);
- open_image_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-image.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_image_action, &QAction::triggered, this, [this]() {
- open_link(m_image_context_menu_url);
- });
- auto* open_image_in_new_tab_action = new QAction("&Open Image in New &Tab", this);
- open_image_in_new_tab_action->setIcon(QIcon(QString("%1/res/icons/16x16/new-tab.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_image_in_new_tab_action, &QAction::triggered, this, [this]() {
- open_link_in_new_tab(m_image_context_menu_url);
- });
- auto* copy_image_action = new QAction("&Copy Image", this);
- copy_image_action->setIcon(QIcon(QString("%1/res/icons/16x16/edit-copy.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(copy_image_action, &QAction::triggered, this, [this]() {
- auto* bitmap = m_image_context_menu_bitmap.bitmap();
- if (bitmap == nullptr)
- return;
- auto data = Gfx::BMPWriter::encode(*bitmap);
- if (data.is_error())
- return;
- auto image = QImage::fromData(data.value().data(), data.value().size(), "BMP");
- if (image.isNull())
- return;
- auto* clipboard = QGuiApplication::clipboard();
- clipboard->setImage(image);
- });
- auto* copy_image_url_action = new QAction("Copy Image &URL", this);
- copy_image_url_action->setIcon(QIcon(QString("%1/res/icons/16x16/edit-copy.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(copy_image_url_action, &QAction::triggered, this, [this]() {
- copy_link_url(m_image_context_menu_url);
- });
- m_image_context_menu = make<QMenu>("Image context menu", this);
- m_image_context_menu->addAction(open_image_action);
- m_image_context_menu->addAction(open_image_in_new_tab_action);
- m_image_context_menu->addSeparator();
- m_image_context_menu->addAction(copy_image_action);
- m_image_context_menu->addAction(copy_image_url_action);
- m_image_context_menu->addSeparator();
- m_image_context_menu->addAction(&m_window->inspect_dom_node_action());
- view().on_image_context_menu_request = [this](auto& image_url, Gfx::IntPoint, Gfx::ShareableBitmap const& shareable_bitmap) {
- m_image_context_menu_url = image_url;
- m_image_context_menu_bitmap = shareable_bitmap;
- auto screen_position = QCursor::pos();
- m_image_context_menu->exec(screen_position);
- };
- m_media_context_menu_play_icon = make<QIcon>(QString("%1/res/icons/16x16/play.png").arg(s_serenity_resource_root.characters()));
- m_media_context_menu_pause_icon = make<QIcon>(QString("%1/res/icons/16x16/pause.png").arg(s_serenity_resource_root.characters()));
- m_media_context_menu_mute_icon = make<QIcon>(QString("%1/res/icons/16x16/audio-volume-muted.png").arg(s_serenity_resource_root.characters()));
- m_media_context_menu_unmute_icon = make<QIcon>(QString("%1/res/icons/16x16/audio-volume-high.png").arg(s_serenity_resource_root.characters()));
- m_media_context_menu_play_pause_action = make<QAction>("&Play", this);
- m_media_context_menu_play_pause_action->setIcon(*m_media_context_menu_play_icon);
- QObject::connect(m_media_context_menu_play_pause_action, &QAction::triggered, this, [this]() {
- view().toggle_media_play_state();
- });
- m_media_context_menu_mute_unmute_action = make<QAction>("&Mute", this);
- m_media_context_menu_mute_unmute_action->setIcon(*m_media_context_menu_mute_icon);
- QObject::connect(m_media_context_menu_mute_unmute_action, &QAction::triggered, this, [this]() {
- view().toggle_media_mute_state();
- });
- m_media_context_menu_controls_action = make<QAction>("Show &Controls", this);
- m_media_context_menu_controls_action->setCheckable(true);
- QObject::connect(m_media_context_menu_controls_action, &QAction::triggered, this, [this]() {
- view().toggle_media_controls_state();
- });
- m_media_context_menu_loop_action = make<QAction>("&Loop", this);
- m_media_context_menu_loop_action->setCheckable(true);
- QObject::connect(m_media_context_menu_loop_action, &QAction::triggered, this, [this]() {
- view().toggle_media_loop_state();
- });
- auto* open_audio_action = new QAction("&Open Audio", this);
- open_audio_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-sound.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_audio_action, &QAction::triggered, this, [this]() {
- open_link(m_media_context_menu_url);
- });
- auto* open_audio_in_new_tab_action = new QAction("Open Audio in New &Tab", this);
- open_audio_in_new_tab_action->setIcon(QIcon(QString("%1/res/icons/16x16/new-tab.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_audio_in_new_tab_action, &QAction::triggered, this, [this]() {
- open_link_in_new_tab(m_media_context_menu_url);
- });
- auto* copy_audio_url_action = new QAction("Copy Audio &URL", this);
- copy_audio_url_action->setIcon(QIcon(QString("%1/res/icons/16x16/edit-copy.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(copy_audio_url_action, &QAction::triggered, this, [this]() {
- copy_link_url(m_media_context_menu_url);
- });
- m_audio_context_menu = make<QMenu>("Audio context menu", this);
- m_audio_context_menu->addAction(m_media_context_menu_play_pause_action);
- m_audio_context_menu->addAction(m_media_context_menu_mute_unmute_action);
- m_audio_context_menu->addAction(m_media_context_menu_controls_action);
- m_audio_context_menu->addAction(m_media_context_menu_loop_action);
- m_audio_context_menu->addSeparator();
- m_audio_context_menu->addAction(open_audio_action);
- m_audio_context_menu->addAction(open_audio_in_new_tab_action);
- m_audio_context_menu->addSeparator();
- m_audio_context_menu->addAction(copy_audio_url_action);
- m_audio_context_menu->addSeparator();
- m_audio_context_menu->addAction(&m_window->inspect_dom_node_action());
- auto* open_video_action = new QAction("&Open Video", this);
- open_video_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-video.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_video_action, &QAction::triggered, this, [this]() {
- open_link(m_media_context_menu_url);
- });
- auto* open_video_in_new_tab_action = new QAction("Open Video in New &Tab", this);
- open_video_in_new_tab_action->setIcon(QIcon(QString("%1/res/icons/16x16/new-tab.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(open_video_in_new_tab_action, &QAction::triggered, this, [this]() {
- open_link_in_new_tab(m_media_context_menu_url);
- });
- auto* copy_video_url_action = new QAction("Copy Video &URL", this);
- copy_video_url_action->setIcon(QIcon(QString("%1/res/icons/16x16/edit-copy.png").arg(s_serenity_resource_root.characters())));
- QObject::connect(copy_video_url_action, &QAction::triggered, this, [this]() {
- copy_link_url(m_media_context_menu_url);
- });
- m_video_context_menu = make<QMenu>("Video context menu", this);
- m_video_context_menu->addAction(m_media_context_menu_play_pause_action);
- m_video_context_menu->addAction(m_media_context_menu_mute_unmute_action);
- m_video_context_menu->addAction(m_media_context_menu_controls_action);
- m_video_context_menu->addAction(m_media_context_menu_loop_action);
- m_video_context_menu->addSeparator();
- m_video_context_menu->addAction(open_video_action);
- m_video_context_menu->addAction(open_video_in_new_tab_action);
- m_video_context_menu->addSeparator();
- m_video_context_menu->addAction(copy_video_url_action);
- m_video_context_menu->addSeparator();
- m_video_context_menu->addAction(&m_window->inspect_dom_node_action());
- view().on_media_context_menu_request = [this](Gfx::IntPoint, Web::Page::MediaContextMenu const& menu) {
- m_media_context_menu_url = menu.media_url;
- if (menu.is_playing) {
- m_media_context_menu_play_pause_action->setIcon(*m_media_context_menu_pause_icon);
- m_media_context_menu_play_pause_action->setText("&Pause");
- } else {
- m_media_context_menu_play_pause_action->setIcon(*m_media_context_menu_play_icon);
- m_media_context_menu_play_pause_action->setText("&Play");
- }
- if (menu.is_muted) {
- m_media_context_menu_mute_unmute_action->setIcon(*m_media_context_menu_unmute_icon);
- m_media_context_menu_mute_unmute_action->setText("Un&mute");
- } else {
- m_media_context_menu_mute_unmute_action->setIcon(*m_media_context_menu_mute_icon);
- m_media_context_menu_mute_unmute_action->setText("&Mute");
- }
- m_media_context_menu_controls_action->setChecked(menu.has_user_agent_controls);
- m_media_context_menu_loop_action->setChecked(menu.is_looping);
- auto screen_position = QCursor::pos();
- if (menu.is_video)
- m_video_context_menu->exec(screen_position);
- else
- m_audio_context_menu->exec(screen_position);
- };
- }
- Tab::~Tab()
- {
- close_sub_widgets();
- }
- void Tab::update_reset_zoom_button()
- {
- auto zoom_level = view().zoom_level();
- if (zoom_level != 1.0f) {
- auto zoom_level_text = MUST(String::formatted("{}%", round_to<int>(zoom_level * 100)));
- m_reset_zoom_button->setText(qstring_from_ak_string(zoom_level_text));
- m_reset_zoom_button_action->setVisible(true);
- } else {
- m_reset_zoom_button_action->setVisible(false);
- }
- }
- void Tab::focus_location_editor()
- {
- m_location_edit->setFocus();
- m_location_edit->selectAll();
- }
- void Tab::navigate(QString const& url_qstring)
- {
- auto url_string = MUST(ak_string_from_qstring(url_qstring));
- view().load(url_string);
- }
- void Tab::load_html(StringView html)
- {
- view().load_html(html);
- }
- void Tab::back()
- {
- if (!m_history.can_go_back())
- return;
- m_is_history_navigation = true;
- m_history.go_back();
- view().load(m_history.current().url.to_deprecated_string());
- }
- void Tab::forward()
- {
- if (!m_history.can_go_forward())
- return;
- m_is_history_navigation = true;
- m_history.go_forward();
- view().load(m_history.current().url.to_deprecated_string());
- }
- void Tab::reload()
- {
- if (m_history.is_empty())
- return;
- m_is_history_navigation = true;
- view().load(m_history.current().url.to_deprecated_string());
- }
- void Tab::open_link(URL const& url)
- {
- view().on_link_click(url, "", 0);
- }
- void Tab::open_link_in_new_tab(URL const& url)
- {
- view().on_link_click(url, "_blank", 0);
- }
- void Tab::copy_link_url(URL const& url)
- {
- auto* clipboard = QGuiApplication::clipboard();
- clipboard->setText(qstring_from_ak_deprecated_string(url.to_deprecated_string()));
- }
- void Tab::location_edit_return_pressed()
- {
- navigate(m_location_edit->text());
- }
- void Tab::open_file()
- {
- auto filename = QFileDialog::getOpenFileName(this, "Open file", QDir::homePath(), "All Files (*.*)");
- if (!filename.isNull())
- navigate(filename);
- }
- int Tab::tab_index()
- {
- return m_window->tab_index(this);
- }
- void Tab::debug_request(DeprecatedString const& request, DeprecatedString const& argument)
- {
- if (request == "dump-history")
- m_history.dump();
- else
- m_view->debug_request(request, argument);
- }
- 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();
- }
- bool Tab::event(QEvent* event)
- {
- if (event->type() == QEvent::PaletteChange) {
- recreate_toolbar_icons();
- return QWidget::event(event);
- }
- return QWidget::event(event);
- }
- void Tab::recreate_toolbar_icons()
- {
- m_window->go_back_action().setIcon(create_tvg_icon_with_theme_colors("back", palette()));
- m_window->go_forward_action().setIcon(create_tvg_icon_with_theme_colors("forward", palette()));
- m_window->reload_action().setIcon(create_tvg_icon_with_theme_colors("reload", palette()));
- }
- void Tab::show_inspector_window(InspectorTarget inspector_target)
- {
- bool inspector_previously_loaded = m_inspector_widget != nullptr;
- if (!m_inspector_widget) {
- m_inspector_widget = new Ladybird::InspectorWidget;
- m_inspector_widget->setWindowTitle("Inspector");
- m_inspector_widget->resize(640, 480);
- m_inspector_widget->on_close = [this] {
- view().clear_inspected_dom_node();
- };
- m_inspector_widget->on_dom_node_inspected = [&](auto id, auto pseudo_element) {
- return view().inspect_dom_node(id, pseudo_element);
- };
- }
- if (!inspector_previously_loaded || !m_inspector_widget->dom_loaded()) {
- view().inspect_dom_tree();
- view().inspect_accessibility_tree();
- }
- m_inspector_widget->show();
- if (inspector_target == InspectorTarget::HoveredElement) {
- auto hovered_node = view().get_hovered_node_id();
- m_inspector_widget->set_selection({ hovered_node });
- } else {
- m_inspector_widget->select_default_node();
- }
- }
- void Tab::show_console_window()
- {
- if (!m_console_widget) {
- m_console_widget = new Ladybird::ConsoleWidget(view());
- m_console_widget->setWindowTitle("JS Console");
- m_console_widget->resize(640, 480);
- // Make these actions available on the window itself. Adding them to the context menu alone
- // does not enable activattion via keyboard shortcuts.
- m_console_widget->addAction(&m_window->copy_selection_action());
- m_console_widget->addAction(&m_window->select_all_action());
- m_console_context_menu = make<QMenu>("Context menu", m_console_widget);
- m_console_context_menu->addAction(&m_window->copy_selection_action());
- m_console_context_menu->addAction(&m_window->select_all_action());
- m_console_widget->view().on_context_menu_request = [this](Gfx::IntPoint) {
- auto screen_position = QCursor::pos();
- m_console_context_menu->exec(screen_position);
- };
- }
- m_console_widget->show();
- }
- void Tab::close_sub_widgets()
- {
- auto close_widget_window = [](auto* widget) {
- if (widget)
- widget->close();
- };
- close_widget_window(m_console_widget);
- close_widget_window(m_inspector_widget);
- }
- }
|