1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 08:48:11 +00:00
serenity/Userland/Applications/Browser/BookmarksBarWidget.cpp
electrikmilk 6675865582 Browser: Add context menu icons
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.
2022-09-08 10:02:37 +01:00

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;
}
}