mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 08:48:11 +00:00

This adds two new icons for browser context menu items "Close Other Tabs" and "Download". This adds existing icons where they were missing in context menu items.
335 lines
10 KiB
C++
335 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
|
|
* Copyright (c) 2022, Jakob-Niklas See <git@nwex.de>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <Applications/Browser/BookmarksBarWidget.h>
|
|
#include <Applications/Browser/Browser.h>
|
|
#include <Applications/Browser/EditBookmarkGML.h>
|
|
#include <LibGUI/Action.h>
|
|
#include <LibGUI/BoxLayout.h>
|
|
#include <LibGUI/Button.h>
|
|
#include <LibGUI/Dialog.h>
|
|
#include <LibGUI/Event.h>
|
|
#include <LibGUI/JsonArrayModel.h>
|
|
#include <LibGUI/Menu.h>
|
|
#include <LibGUI/Model.h>
|
|
#include <LibGUI/TextBox.h>
|
|
#include <LibGUI/Widget.h>
|
|
#include <LibGUI/Window.h>
|
|
#include <LibGfx/Palette.h>
|
|
|
|
namespace Browser {
|
|
|
|
namespace {
|
|
|
|
class BookmarkEditor final : public GUI::Dialog {
|
|
C_OBJECT(BookmarkEditor)
|
|
|
|
public:
|
|
static Vector<JsonValue>
|
|
edit_bookmark(Window* parent_window, StringView title, StringView url)
|
|
{
|
|
auto editor = BookmarkEditor::construct(parent_window, title, url);
|
|
editor->set_title("Edit Bookmark");
|
|
editor->set_icon(g_icon_bag.bookmark_filled);
|
|
|
|
if (editor->exec() == ExecResult::OK) {
|
|
return Vector<JsonValue> { editor->title(), editor->url() };
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
private:
|
|
BookmarkEditor(Window* parent_window, StringView title, StringView url)
|
|
: Dialog(parent_window)
|
|
{
|
|
auto& widget = set_main_widget<GUI::Widget>();
|
|
if (!widget.load_from_gml(edit_bookmark_gml))
|
|
VERIFY_NOT_REACHED();
|
|
|
|
set_resizable(false);
|
|
resize(260, 85);
|
|
|
|
m_title_textbox = *widget.find_descendant_of_type_named<GUI::TextBox>("title_textbox");
|
|
m_title_textbox->set_text(title);
|
|
m_title_textbox->set_focus(true);
|
|
m_title_textbox->select_all();
|
|
|
|
m_url_textbox = *widget.find_descendant_of_type_named<GUI::TextBox>("url_textbox");
|
|
m_url_textbox->set_text(url);
|
|
|
|
auto& ok_button = *widget.find_descendant_of_type_named<GUI::Button>("ok_button");
|
|
ok_button.on_click = [this](auto) {
|
|
done(ExecResult::OK);
|
|
};
|
|
ok_button.set_default(true);
|
|
|
|
auto& cancel_button = *widget.find_descendant_of_type_named<GUI::Button>("cancel_button");
|
|
cancel_button.on_click = [this](auto) {
|
|
done(ExecResult::Cancel);
|
|
};
|
|
}
|
|
|
|
String title() const
|
|
{
|
|
return m_title_textbox->text();
|
|
}
|
|
|
|
String url() const
|
|
{
|
|
return m_url_textbox->text();
|
|
}
|
|
|
|
RefPtr<GUI::TextBox> m_title_textbox;
|
|
RefPtr<GUI::TextBox> m_url_textbox;
|
|
};
|
|
|
|
}
|
|
|
|
static BookmarksBarWidget* s_the;
|
|
|
|
BookmarksBarWidget& BookmarksBarWidget::the()
|
|
{
|
|
return *s_the;
|
|
}
|
|
|
|
BookmarksBarWidget::BookmarksBarWidget(String const& bookmarks_file, bool enabled)
|
|
{
|
|
s_the = this;
|
|
set_layout<GUI::HorizontalBoxLayout>();
|
|
layout()->set_spacing(0);
|
|
layout()->set_margins(2);
|
|
|
|
set_fixed_height(20);
|
|
|
|
if (!enabled)
|
|
set_visible(false);
|
|
|
|
m_additional = GUI::Button::construct();
|
|
m_additional->set_tooltip("Show hidden bookmarks");
|
|
m_additional->set_menu(m_additional_menu);
|
|
m_additional->set_menu_position(GUI::Button::MenuPosition::BottomLeft);
|
|
auto bitmap_or_error = Gfx::Bitmap::try_load_from_file("/res/icons/16x16/overflow-menu.png"sv);
|
|
if (!bitmap_or_error.is_error())
|
|
m_additional->set_icon(bitmap_or_error.release_value());
|
|
m_additional->set_button_style(Gfx::ButtonStyle::Coolbar);
|
|
m_additional->set_fixed_size(22, 20);
|
|
m_additional->set_focus_policy(GUI::FocusPolicy::TabFocus);
|
|
|
|
m_separator = GUI::Widget::construct();
|
|
|
|
m_context_menu = GUI::Menu::construct();
|
|
auto default_action = GUI::Action::create(
|
|
"&Open", g_icon_bag.go_to, [this](auto&) {
|
|
if (on_bookmark_click)
|
|
on_bookmark_click(m_context_menu_url, OpenInNewTab::No);
|
|
},
|
|
this);
|
|
m_context_menu_default_action = default_action;
|
|
m_context_menu->add_action(default_action);
|
|
m_context_menu->add_action(GUI::Action::create(
|
|
"Open in New &Tab", g_icon_bag.new_tab, [this](auto&) {
|
|
if (on_bookmark_click)
|
|
on_bookmark_click(m_context_menu_url, OpenInNewTab::Yes);
|
|
},
|
|
this));
|
|
m_context_menu->add_separator();
|
|
m_context_menu->add_action(GUI::Action::create(
|
|
"&Edit...", g_icon_bag.rename, [this](auto&) {
|
|
edit_bookmark(m_context_menu_url);
|
|
},
|
|
this));
|
|
m_context_menu->add_action(GUI::CommonActions::make_delete_action(
|
|
[this](auto&) {
|
|
remove_bookmark(m_context_menu_url);
|
|
},
|
|
this));
|
|
|
|
Vector<GUI::JsonArrayModel::FieldSpec> fields;
|
|
fields.empend("title", "Title", Gfx::TextAlignment::CenterLeft);
|
|
fields.empend("url", "Url", Gfx::TextAlignment::CenterRight);
|
|
set_model(GUI::JsonArrayModel::create(bookmarks_file, move(fields)));
|
|
model()->invalidate();
|
|
}
|
|
|
|
BookmarksBarWidget::~BookmarksBarWidget()
|
|
{
|
|
if (m_model)
|
|
m_model->unregister_client(*this);
|
|
}
|
|
|
|
void BookmarksBarWidget::set_model(RefPtr<GUI::Model> model)
|
|
{
|
|
if (model == m_model)
|
|
return;
|
|
if (m_model)
|
|
m_model->unregister_client(*this);
|
|
m_model = move(model);
|
|
m_model->register_client(*this);
|
|
}
|
|
|
|
void BookmarksBarWidget::resize_event(GUI::ResizeEvent& event)
|
|
{
|
|
Widget::resize_event(event);
|
|
update_content_size();
|
|
}
|
|
|
|
void BookmarksBarWidget::model_did_update(unsigned)
|
|
{
|
|
remove_all_children();
|
|
|
|
m_bookmarks.clear();
|
|
|
|
int width = 0;
|
|
for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
|
|
|
|
auto title = model()->index(item_index, 0).data().to_string();
|
|
auto url = model()->index(item_index, 1).data().to_string();
|
|
|
|
Gfx::IntRect rect { width, 0, font().width(title) + 32, height() };
|
|
|
|
auto& button = add<GUI::Button>();
|
|
m_bookmarks.append(button);
|
|
|
|
button.set_button_style(Gfx::ButtonStyle::Coolbar);
|
|
button.set_text(title);
|
|
button.set_icon(g_icon_bag.filetype_html);
|
|
button.set_fixed_size(font().width(title) + 32, 20);
|
|
button.set_relative_rect(rect);
|
|
button.set_focus_policy(GUI::FocusPolicy::TabFocus);
|
|
button.set_tooltip(url);
|
|
button.set_allowed_mouse_buttons_for_pressing(GUI::MouseButton::Primary | GUI::MouseButton::Middle);
|
|
|
|
button.on_click = [title, url, this](auto) {
|
|
if (on_bookmark_click)
|
|
on_bookmark_click(url, OpenInNewTab::No);
|
|
};
|
|
|
|
button.on_middle_mouse_click = [title, url, this](auto) {
|
|
if (on_bookmark_click)
|
|
on_bookmark_click(url, OpenInNewTab::Yes);
|
|
};
|
|
|
|
button.on_context_menu_request = [this, url](auto& context_menu_event) {
|
|
m_context_menu_url = url;
|
|
m_context_menu->popup(context_menu_event.screen_position(), m_context_menu_default_action);
|
|
};
|
|
|
|
width += rect.width();
|
|
}
|
|
|
|
add_child(*m_separator);
|
|
add_child(*m_additional);
|
|
|
|
update_content_size();
|
|
update();
|
|
}
|
|
|
|
void BookmarksBarWidget::update_content_size()
|
|
{
|
|
int x_position = 0;
|
|
m_last_visible_index = -1;
|
|
|
|
for (size_t i = 0; i < m_bookmarks.size(); ++i) {
|
|
auto& bookmark = m_bookmarks.at(i);
|
|
if (x_position + bookmark.width() + m_additional->width() > width()) {
|
|
m_last_visible_index = i;
|
|
break;
|
|
}
|
|
bookmark.set_x(x_position);
|
|
bookmark.set_visible(true);
|
|
x_position += bookmark.width();
|
|
}
|
|
|
|
if (m_last_visible_index < 0) {
|
|
m_additional->set_visible(false);
|
|
} else {
|
|
// hide all items > m_last_visible_index and create new bookmarks menu for them
|
|
m_additional->set_visible(true);
|
|
m_additional_menu = GUI::Menu::construct("Additional Bookmarks");
|
|
m_additional->set_menu(m_additional_menu);
|
|
for (size_t i = m_last_visible_index; i < m_bookmarks.size(); ++i) {
|
|
auto& bookmark = m_bookmarks.at(i);
|
|
bookmark.set_visible(false);
|
|
m_additional_menu->add_action(GUI::Action::create(bookmark.text(), g_icon_bag.filetype_html, [&](auto&) { bookmark.on_click(0); }));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool BookmarksBarWidget::contains_bookmark(String const& url)
|
|
{
|
|
for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
|
|
|
|
auto item_title = model()->index(item_index, 0).data().to_string();
|
|
auto item_url = model()->index(item_index, 1).data().to_string();
|
|
if (item_url == url) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BookmarksBarWidget::remove_bookmark(String const& url)
|
|
{
|
|
for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
|
|
|
|
auto item_title = model()->index(item_index, 0).data().to_string();
|
|
auto item_url = model()->index(item_index, 1).data().to_string();
|
|
if (item_url == url) {
|
|
auto& json_model = *static_cast<GUI::JsonArrayModel*>(model());
|
|
|
|
auto const item_removed = json_model.remove(item_index);
|
|
if (item_removed)
|
|
json_model.store();
|
|
|
|
return item_removed;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool BookmarksBarWidget::add_bookmark(String const& url, String const& title)
|
|
{
|
|
Vector<JsonValue> values;
|
|
values.append(title);
|
|
values.append(url);
|
|
|
|
auto& json_model = *static_cast<GUI::JsonArrayModel*>(model());
|
|
if (json_model.add(move(values))) {
|
|
json_model.store();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BookmarksBarWidget::edit_bookmark(String const& url)
|
|
{
|
|
for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
|
|
auto item_title = model()->index(item_index, 0).data().to_string();
|
|
auto item_url = model()->index(item_index, 1).data().to_string();
|
|
|
|
if (item_url == url) {
|
|
auto values = BookmarkEditor::edit_bookmark(window(), item_title, item_url);
|
|
bool item_replaced = false;
|
|
|
|
if (!values.is_empty()) {
|
|
auto& json_model = *static_cast<GUI::JsonArrayModel*>(model());
|
|
item_replaced = json_model.set(item_index, move(values));
|
|
|
|
if (item_replaced)
|
|
json_model.store();
|
|
}
|
|
|
|
return item_replaced;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|