2022-12-18 00:50:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2022-12-18 21:12:14 +00:00
|
|
|
#include "InspectorWidget.h"
|
2023-12-05 21:58:26 +00:00
|
|
|
#include <Ladybird/Qt/StringUtils.h>
|
2023-12-06 14:34:53 +00:00
|
|
|
#include <LibWebView/Attribute.h>
|
2023-11-24 01:04:54 +00:00
|
|
|
#include <LibWebView/InspectorClient.h>
|
2023-12-05 21:58:26 +00:00
|
|
|
#include <QAction>
|
2022-12-18 00:50:53 +00:00
|
|
|
#include <QCloseEvent>
|
2023-12-05 21:58:26 +00:00
|
|
|
#include <QMenu>
|
2022-12-18 00:50:53 +00:00
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
|
|
namespace Ladybird {
|
|
|
|
|
2023-11-24 01:04:54 +00:00
|
|
|
extern bool is_using_dark_system_theme(QWidget&);
|
|
|
|
|
2023-12-04 16:03:40 +00:00
|
|
|
InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view)
|
|
|
|
: QWidget(tab, Qt::Window)
|
2022-12-18 00:50:53 +00:00
|
|
|
{
|
2023-12-04 14:39:22 +00:00
|
|
|
m_inspector_view = new WebContentView({}, {});
|
2023-02-21 19:49:00 +00:00
|
|
|
|
2023-11-24 01:04:54 +00:00
|
|
|
if (is_using_dark_system_theme(*this))
|
|
|
|
m_inspector_view->update_palette(WebContentView::PaletteMode::Dark);
|
|
|
|
|
|
|
|
m_inspector_client = make<WebView::InspectorClient>(content_view, *m_inspector_view);
|
|
|
|
|
2023-12-05 21:58:26 +00:00
|
|
|
m_edit_node_action = new QAction("&Edit node", this);
|
|
|
|
connect(m_edit_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_edit_dom_node(); });
|
|
|
|
|
2023-12-06 16:16:28 +00:00
|
|
|
m_copy_node_action = new QAction("&Copy HTML", this);
|
|
|
|
connect(m_copy_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_copy_dom_node(); });
|
|
|
|
|
2023-12-06 16:56:16 +00:00
|
|
|
m_screenshot_node_action = new QAction("Take node &screenshot", this);
|
|
|
|
connect(m_screenshot_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_screenshot_dom_node(); });
|
|
|
|
|
2023-12-07 16:05:34 +00:00
|
|
|
m_create_child_element_action = new QAction("Create child &element", this);
|
|
|
|
connect(m_create_child_element_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_create_child_element(); });
|
|
|
|
|
|
|
|
m_create_child_text_node_action = new QAction("Create child &text node", this);
|
|
|
|
connect(m_create_child_text_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_create_child_text_node(); });
|
|
|
|
|
2023-12-05 21:58:26 +00:00
|
|
|
m_delete_node_action = new QAction("&Delete node", this);
|
|
|
|
connect(m_delete_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_remove_dom_node(); });
|
|
|
|
|
|
|
|
m_add_attribute_action = new QAction("&Add attribute", this);
|
|
|
|
connect(m_add_attribute_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_add_dom_node_attribute(); });
|
|
|
|
|
|
|
|
m_remove_attribute_action = new QAction("&Remove attribute", this);
|
|
|
|
connect(m_remove_attribute_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_remove_dom_node_attribute(); });
|
|
|
|
|
2023-12-06 15:12:31 +00:00
|
|
|
m_copy_attribute_value_action = new QAction("Copy attribute &value", this);
|
|
|
|
connect(m_copy_attribute_value_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_copy_dom_node_attribute_value(); });
|
|
|
|
|
2023-12-05 21:58:26 +00:00
|
|
|
m_dom_node_text_context_menu = new QMenu("DOM text context menu", this);
|
|
|
|
m_dom_node_text_context_menu->addAction(m_edit_node_action);
|
2023-12-06 16:16:28 +00:00
|
|
|
m_dom_node_text_context_menu->addAction(m_copy_node_action);
|
2023-12-05 21:58:26 +00:00
|
|
|
m_dom_node_text_context_menu->addSeparator();
|
|
|
|
m_dom_node_text_context_menu->addAction(m_delete_node_action);
|
|
|
|
|
2023-12-07 16:05:34 +00:00
|
|
|
auto* create_child_menu = new QMenu("Create child", this);
|
|
|
|
create_child_menu->addAction(m_create_child_element_action);
|
|
|
|
create_child_menu->addAction(m_create_child_text_node_action);
|
|
|
|
|
2023-12-05 21:58:26 +00:00
|
|
|
m_dom_node_tag_context_menu = new QMenu("DOM tag context menu", this);
|
|
|
|
m_dom_node_tag_context_menu->addAction(m_edit_node_action);
|
|
|
|
m_dom_node_tag_context_menu->addSeparator();
|
|
|
|
m_dom_node_tag_context_menu->addAction(m_add_attribute_action);
|
2023-12-07 16:05:34 +00:00
|
|
|
m_dom_node_tag_context_menu->addMenu(create_child_menu);
|
2023-12-05 21:58:26 +00:00
|
|
|
m_dom_node_tag_context_menu->addAction(m_delete_node_action);
|
2023-12-06 16:16:28 +00:00
|
|
|
m_dom_node_tag_context_menu->addSeparator();
|
|
|
|
m_dom_node_tag_context_menu->addAction(m_copy_node_action);
|
2023-12-06 16:56:16 +00:00
|
|
|
m_dom_node_tag_context_menu->addAction(m_screenshot_node_action);
|
2023-12-05 21:58:26 +00:00
|
|
|
|
|
|
|
m_dom_node_attribute_context_menu = new QMenu("DOM attribute context menu", this);
|
|
|
|
m_dom_node_attribute_context_menu->addAction(m_edit_node_action);
|
2023-12-06 15:12:31 +00:00
|
|
|
m_dom_node_attribute_context_menu->addAction(m_copy_attribute_value_action);
|
2023-12-05 21:58:26 +00:00
|
|
|
m_dom_node_attribute_context_menu->addAction(m_remove_attribute_action);
|
|
|
|
m_dom_node_attribute_context_menu->addSeparator();
|
|
|
|
m_dom_node_attribute_context_menu->addAction(m_add_attribute_action);
|
2023-12-07 16:05:34 +00:00
|
|
|
m_dom_node_attribute_context_menu->addMenu(create_child_menu);
|
2023-12-05 21:58:26 +00:00
|
|
|
m_dom_node_attribute_context_menu->addAction(m_delete_node_action);
|
2023-12-06 16:16:28 +00:00
|
|
|
m_dom_node_attribute_context_menu->addSeparator();
|
|
|
|
m_dom_node_attribute_context_menu->addAction(m_copy_node_action);
|
2023-12-06 16:56:16 +00:00
|
|
|
m_dom_node_attribute_context_menu->addAction(m_screenshot_node_action);
|
2023-12-05 21:58:26 +00:00
|
|
|
|
|
|
|
m_inspector_client->on_requested_dom_node_text_context_menu = [this](auto position) {
|
|
|
|
m_edit_node_action->setText("&Edit text");
|
2023-12-06 16:16:28 +00:00
|
|
|
m_copy_node_action->setText("&Copy text");
|
2023-12-05 21:58:26 +00:00
|
|
|
|
|
|
|
m_dom_node_text_context_menu->exec(to_widget_position(position));
|
|
|
|
};
|
|
|
|
|
|
|
|
m_inspector_client->on_requested_dom_node_tag_context_menu = [this](auto position, auto const& tag) {
|
|
|
|
m_edit_node_action->setText(qstring_from_ak_string(MUST(String::formatted("&Edit \"{}\"", tag))));
|
2023-12-06 16:16:28 +00:00
|
|
|
m_copy_node_action->setText("&Copy HTML");
|
2023-12-05 21:58:26 +00:00
|
|
|
|
|
|
|
m_dom_node_tag_context_menu->exec(to_widget_position(position));
|
|
|
|
};
|
|
|
|
|
2023-12-06 15:12:31 +00:00
|
|
|
m_inspector_client->on_requested_dom_node_attribute_context_menu = [this](auto position, auto const&, WebView::Attribute const& attribute) {
|
|
|
|
static constexpr size_t MAX_ATTRIBUTE_VALUE_LENGTH = 32;
|
|
|
|
|
2023-12-06 16:16:28 +00:00
|
|
|
m_copy_node_action->setText("&Copy HTML");
|
2023-12-06 14:34:53 +00:00
|
|
|
m_edit_node_action->setText(qstring_from_ak_string(MUST(String::formatted("&Edit attribute \"{}\"", attribute.name))));
|
|
|
|
m_remove_attribute_action->setText(qstring_from_ak_string(MUST(String::formatted("&Remove attribute \"{}\"", attribute.name))));
|
2023-12-06 15:12:31 +00:00
|
|
|
m_copy_attribute_value_action->setText(qstring_from_ak_string(MUST(String::formatted("Copy attribute &value \"{:.{}}{}\"",
|
|
|
|
attribute.value, MAX_ATTRIBUTE_VALUE_LENGTH,
|
|
|
|
attribute.value.bytes_as_string_view().length() > MAX_ATTRIBUTE_VALUE_LENGTH ? "..."sv : ""sv))));
|
2023-12-05 21:58:26 +00:00
|
|
|
|
|
|
|
m_dom_node_attribute_context_menu->exec(to_widget_position(position));
|
|
|
|
};
|
|
|
|
|
2023-11-24 01:04:54 +00:00
|
|
|
setLayout(new QVBoxLayout);
|
2023-12-04 14:39:22 +00:00
|
|
|
layout()->addWidget(m_inspector_view);
|
2023-11-24 01:04:54 +00:00
|
|
|
|
|
|
|
setWindowTitle("Inspector");
|
|
|
|
resize(875, 825);
|
2022-12-18 21:12:14 +00:00
|
|
|
}
|
|
|
|
|
2023-11-24 01:04:54 +00:00
|
|
|
InspectorWidget::~InspectorWidget() = default;
|
|
|
|
|
|
|
|
void InspectorWidget::inspect()
|
2022-12-18 21:12:14 +00:00
|
|
|
{
|
2023-11-24 01:04:54 +00:00
|
|
|
m_inspector_client->inspect();
|
2022-12-18 00:50:53 +00:00
|
|
|
}
|
|
|
|
|
2023-11-24 01:04:54 +00:00
|
|
|
void InspectorWidget::reset()
|
2023-02-21 19:49:00 +00:00
|
|
|
{
|
2023-11-24 01:04:54 +00:00
|
|
|
m_inspector_client->reset();
|
2023-02-21 19:49:00 +00:00
|
|
|
}
|
|
|
|
|
2023-11-24 01:04:54 +00:00
|
|
|
void InspectorWidget::select_hovered_node()
|
2022-12-18 00:50:53 +00:00
|
|
|
{
|
2023-11-24 01:04:54 +00:00
|
|
|
m_inspector_client->select_hovered_node();
|
|
|
|
}
|
2023-11-04 15:55:09 +00:00
|
|
|
|
2023-11-24 01:04:54 +00:00
|
|
|
void InspectorWidget::select_default_node()
|
|
|
|
{
|
|
|
|
m_inspector_client->select_default_node();
|
2022-12-18 00:50:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectorWidget::closeEvent(QCloseEvent* event)
|
|
|
|
{
|
|
|
|
event->accept();
|
2023-11-24 01:04:54 +00:00
|
|
|
m_inspector_client->clear_selection();
|
2022-12-18 00:50:53 +00:00
|
|
|
}
|
|
|
|
|
2023-12-05 21:58:26 +00:00
|
|
|
QPoint InspectorWidget::to_widget_position(Gfx::IntPoint position) const
|
|
|
|
{
|
|
|
|
auto widget_position = m_inspector_view->mapTo(this, QPoint { position.x(), position.y() });
|
|
|
|
return mapToGlobal(widget_position);
|
|
|
|
}
|
|
|
|
|
2022-12-18 00:50:53 +00:00
|
|
|
}
|