diff --git a/Base/home/anon/BrowserSettingsWidget.gml b/Base/home/anon/BrowserSettingsWidget.gml new file mode 100644 index 0000000000..da4fabd1d1 --- /dev/null +++ b/Base/home/anon/BrowserSettingsWidget.gml @@ -0,0 +1,180 @@ +@GUI::Frame { + fill_with_background_color: true + layout: @GUI::VerticalBoxLayout { + margins: [10] + spacing: 5 + } + + @GUI::GroupBox { + title: "Homepage" + fixed_height: 70 + layout: @GUI::VerticalBoxLayout { + margins: [16, 8, 8] + spacing: 2 + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + fixed_height: 32 + icon: "/res/icons/32x32/home.png" + } + + @GUI::Label { + text: "URL:" + text_alignment: "CenterLeft" + fixed_width: 30 + } + + @GUI::TextBox { + name: "homepage_url_textbox" + placeholder: "https://example.com" + } + } + } + + @GUI::GroupBox { + title: "Appearance" + fixed_height: 104 + layout: @GUI::VerticalBoxLayout { + margins: [16, 8, 8] + spacing: 2 + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + fixed_height: 32 + icon: "/res/icons/32x32/color-chooser.png" + } + + @GUI::Label { + text: "Color scheme:" + text_alignment: "CenterLeft" + fixed_width: 110 + } + + @GUI::ComboBox { + name: "color_scheme_combobox" + } + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + } + + @GUI::CheckBox { + name: "show_bookmarks_bar_checkbox" + text: "Show bookmarks" + } + } + } + + @GUI::GroupBox { + title: "Search Engine" + fixed_height: 140 + layout: @GUI::VerticalBoxLayout { + margins: [16, 8, 8] + spacing: 2 + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + fixed_height: 32 + icon: "/res/icons/32x32/search-engine.png" + } + + @GUI::CheckBox { + text: "Search using '?' in the URL box" + name: "enable_search_engine_checkbox" + } + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + name: "search_engine_combobox_group" + + @GUI::Widget { + fixed_width: 32 + } + + @GUI::Label { + text: "Search engine:" + text_alignment: "CenterLeft" + fixed_width: 110 + } + + @GUI::ComboBox { + name: "search_engine_combobox" + } + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + name: "custom_search_engine_group" + + @GUI::Widget { + fixed_width: 32 + } + + @GUI::Label { + text: "Enter URL template:" + text_alignment: "CenterLeft" + fixed_width: 110 + } + + @GUI::TextBox { + name: "custom_search_engine_textbox" + placeholder: "https://host/search?q={}" + } + } + } + + @GUI::GroupBox { + title: "Downloads" + fixed_height: 70 + layout: @GUI::VerticalBoxLayout { + margins: [16, 8, 8] + spacing: 2 + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + fixed_height: 32 + icon: "/res/icons/32x32/downloads.png" + } + + @GUI::CheckBox { + name: "auto_close_download_windows_checkbox" + text: "Automatically close download window when complete" + } + } + } +} diff --git a/Userland/Applications/Browser/CMakeLists.txt b/Userland/Applications/Browser/CMakeLists.txt index 90e59b3ae9..47f1ce133a 100644 --- a/Userland/Applications/Browser/CMakeLists.txt +++ b/Userland/Applications/Browser/CMakeLists.txt @@ -6,7 +6,9 @@ serenity_component( ) compile_gml(BrowserWindow.gml BrowserWindowGML.h browser_window_gml) +compile_gml(CookiesTab.gml CookiesTabGML.h cookies_tab_gml) compile_gml(EditBookmark.gml EditBookmarkGML.h edit_bookmark_gml) +compile_gml(StorageWidget.gml StorageWidgetGML.h storage_widget_gml) compile_gml(Tab.gml TabGML.h tab_gml) set(SOURCES @@ -15,11 +17,15 @@ set(SOURCES BrowserWindowGML.h ConsoleWidget.cpp CookieJar.cpp + CookiesModel.cpp + CookiesTabGML.h DownloadWidget.cpp EditBookmarkGML.h History.cpp IconBag.cpp InspectorWidget.cpp + StorageWidget.cpp + StorageWidgetGML.h Tab.cpp TabGML.h WindowActions.cpp diff --git a/Userland/Applications/Browser/CookiesModel.cpp b/Userland/Applications/Browser/CookiesModel.cpp new file mode 100644 index 0000000000..7cf100578e --- /dev/null +++ b/Userland/Applications/Browser/CookiesModel.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "CookiesModel.h" + +namespace Browser { + +void CookiesModel::add_item(Web::Cookie::Cookie const& item) +{ + begin_insert_rows({}, m_cookies.size(), m_cookies.size()); + m_cookies.append(item); + end_insert_rows(); + + did_update(DontInvalidateIndices); +} + +void CookiesModel::clear_items() +{ + begin_insert_rows({}, m_cookies.size(), m_cookies.size()); + m_cookies.clear(); + end_insert_rows(); + + did_update(DontInvalidateIndices); +} + +String CookiesModel::column_name(int column) const +{ + switch (column) { + case Column::Name: + return "Name"; + case Column::Value: + return "Value"; + case Column::Domain: + return "Domain"; + case Column::Path: + return "Path"; + case Column::ExpiryTime: + return "Expiry time"; + case Column::__Count: + return {}; + } + + return {}; +} + +GUI::ModelIndex CookiesModel::index(int row, int column, GUI::ModelIndex const&) const +{ + return create_index(row, column, &m_cookies.at(row)); +} + +GUI::Variant CookiesModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const +{ + if (role != GUI::ModelRole::Display) + return {}; + + const auto& cookie = m_cookies[index.row()]; + + switch (index.column()) { + case Column::Name: + return cookie.name; + case Column::Value: + return cookie.value; + case Column::Domain: + return cookie.domain; + case Column::Path: + return cookie.path; + case Column::ExpiryTime: + return cookie.expiry_time.to_string(); + } + + VERIFY_NOT_REACHED(); +} + +} diff --git a/Userland/Applications/Browser/CookiesModel.h b/Userland/Applications/Browser/CookiesModel.h new file mode 100644 index 0000000000..4fa8e541c3 --- /dev/null +++ b/Userland/Applications/Browser/CookiesModel.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "Tab.h" +#include +#include +#include +#include + +namespace Browser { + +class CookiesModel final : public GUI::Model { +public: + enum Column { + Name, + Value, + Domain, + Path, + ExpiryTime, + __Count, + }; + + void add_item(Web::Cookie::Cookie const& item); + void clear_items(); + virtual int row_count(GUI::ModelIndex const&) const override { return m_cookies.size(); } + virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Count; } + virtual String column_name(int column) const override; + virtual GUI::ModelIndex index(int row, int column = 0, GUI::ModelIndex const& = GUI::ModelIndex()) const override; + virtual GUI::Variant data(GUI::ModelIndex const& index, GUI::ModelRole role = GUI::ModelRole::Display) const override; + +private: + AK::Vector m_cookies; +}; + +} diff --git a/Userland/Applications/Browser/CookiesTab.gml b/Userland/Applications/Browser/CookiesTab.gml new file mode 100644 index 0000000000..7de9c12777 --- /dev/null +++ b/Userland/Applications/Browser/CookiesTab.gml @@ -0,0 +1,16 @@ +@GUI::Widget { + name: "cookies_tab" + layout: @GUI::VerticalBoxLayout { + margins: [4] + } + + @GUI::GroupBox { + layout: @GUI::VerticalBoxLayout { + margins: [6] + } + + @GUI::TableView { + name: "cookies_tableview" + } + } +} diff --git a/Userland/Applications/Browser/StorageWidget.cpp b/Userland/Applications/Browser/StorageWidget.cpp new file mode 100644 index 0000000000..cf8feb0dea --- /dev/null +++ b/Userland/Applications/Browser/StorageWidget.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "StorageWidget.h" +#include "CookiesModel.h" +#include +#include +#include +#include +#include +#include + +namespace Browser { + +StorageWidget::StorageWidget() +{ + load_from_gml(storage_widget_gml); + auto& tab_widget = *find_descendant_of_type_named("tab_widget"); + + auto cookies_tab = tab_widget.try_add_tab("Cookies").release_value_but_fixme_should_propagate_errors(); + cookies_tab->load_from_gml(cookies_tab_gml); + + m_cookies_table_view = cookies_tab->find_descendant_of_type_named("cookies_tableview"); + m_cookies_model = adopt_ref(*new CookiesModel()); + + m_cookies_table_view->set_model(*m_cookies_model); + m_cookies_table_view->set_column_headers_visible(true); + m_cookies_table_view->set_alternating_row_colors(true); +} + +void StorageWidget::add_cookie(Web::Cookie::Cookie const& cookie) +{ + m_cookies_model->add_item(cookie); +} + +void StorageWidget::clear_cookies() +{ + m_cookies_model->clear_items(); +} + +} diff --git a/Userland/Applications/Browser/StorageWidget.gml b/Userland/Applications/Browser/StorageWidget.gml new file mode 100644 index 0000000000..4e7eb0c49e --- /dev/null +++ b/Userland/Applications/Browser/StorageWidget.gml @@ -0,0 +1,10 @@ +@GUI::Widget { + fill_with_background_color: true + layout: @GUI::VerticalBoxLayout { + margins: [4] + } + + @GUI::TabWidget { + name: "tab_widget" + } +} diff --git a/Userland/Applications/Browser/StorageWidget.h b/Userland/Applications/Browser/StorageWidget.h new file mode 100644 index 0000000000..126af19ed7 --- /dev/null +++ b/Userland/Applications/Browser/StorageWidget.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "CookiesModel.h" +#include "Tab.h" +#include +#include + +namespace Browser { + +class StorageWidget final : public GUI::Widget { + C_OBJECT(StorageWidget); + +public: + virtual ~StorageWidget() override = default; + void add_cookie(Web::Cookie::Cookie const& cookie); + void clear_cookies(); + +private: + StorageWidget(); + + RefPtr m_cookies_table_view; + RefPtr m_cookies_model; +}; + +} diff --git a/Userland/Applications/Browser/Tab.cpp b/Userland/Applications/Browser/Tab.cpp index 97ba5b10df..36f596cfc8 100644 --- a/Userland/Applications/Browser/Tab.cpp +++ b/Userland/Applications/Browser/Tab.cpp @@ -14,6 +14,7 @@ #include "ConsoleWidget.h" #include "DownloadWidget.h" #include "InspectorWidget.h" +#include "StorageWidget.h" #include #include #include @@ -533,4 +534,26 @@ void Tab::show_console_window() window->move_to_front(); } +void Tab::show_storage_inspector() +{ + if (!m_storage_widget) { + auto storage_window = GUI::Window::construct(&window()); + storage_window->resize(500, 300); + storage_window->set_title("Storage inspector"); + storage_window->set_icon(g_icon_bag.cookie); + m_storage_widget = storage_window->set_main_widget(); + } + + if (on_want_cookies) { + auto cookies = on_want_cookies(); + m_storage_widget->clear_cookies(); + for (auto cookie : cookies) + m_storage_widget->add_cookie(cookie); + } + + auto* window = m_storage_widget->window(); + window->show(); + window->move_to_front(); +} + } diff --git a/Userland/Applications/Browser/Tab.h b/Userland/Applications/Browser/Tab.h index dec2551ff4..928ccf3340 100644 --- a/Userland/Applications/Browser/Tab.h +++ b/Userland/Applications/Browser/Tab.h @@ -25,6 +25,7 @@ namespace Browser { class BrowserWindow; class InspectorWidget; class ConsoleWidget; +class StorageWidget; class Tab final : public GUI::Widget { C_OBJECT(Tab); @@ -62,6 +63,7 @@ public: Function on_get_cookie; Function on_set_cookie; Function on_dump_cookies; + Function()> on_want_cookies; enum class InspectorTarget { Document, @@ -70,6 +72,7 @@ public: void show_inspector_window(InspectorTarget); void show_console_window(); + void show_storage_inspector(); const String& title() const { return m_title; } const Gfx::Bitmap* icon() const { return m_icon; } @@ -97,6 +100,7 @@ private: RefPtr m_bookmark_button; RefPtr m_dom_inspector_widget; RefPtr m_console_widget; + RefPtr m_storage_widget; RefPtr m_statusbar; RefPtr m_toolbar_container;