diff options
Diffstat (limited to 'Userland/Applications')
5 files changed, 246 insertions, 1 deletions
diff --git a/Userland/Applications/BrowserSettings/CMakeLists.txt b/Userland/Applications/BrowserSettings/CMakeLists.txt index ede8a20d1e..b49cc5687e 100644 --- a/Userland/Applications/BrowserSettings/CMakeLists.txt +++ b/Userland/Applications/BrowserSettings/CMakeLists.txt @@ -5,9 +5,12 @@ serenity_component( ) compile_gml(BrowserSettingsWidget.gml BrowserSettingsWidgetGML.h browser_settings_widget_gml) +compile_gml(ContentFilterSettingsWidget.gml ContentFilterSettingsWidgetGML.h content_filter_settings_widget_gml) set(SOURCES main.cpp + ContentFilterSettingsWidget.cpp + ContentFilterSettingsWidgetGML.h BrowserSettingsWidget.cpp BrowserSettingsWidgetGML.h ) diff --git a/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.cpp b/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.cpp new file mode 100644 index 0000000000..04dd93e4db --- /dev/null +++ b/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2022, Maciej Zygmanowski <sppmacd@pm.me> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ContentFilterSettingsWidget.h" + +#include <AK/NonnullRefPtr.h> +#include <Applications/BrowserSettings/ContentFilterSettingsWidgetGML.h> +#include <LibConfig/Client.h> +#include <LibCore/StandardPaths.h> +#include <LibCore/Stream.h> +#include <LibGUI/CheckBox.h> +#include <LibGUI/Event.h> +#include <LibGUI/Forward.h> +#include <LibGUI/InputBox.h> +#include <LibGUI/ListView.h> +#include <LibGUI/Menu.h> + +static String filter_list_file_path() +{ + return String::formatted("{}/BrowserContentFilters.txt", Core::StandardPaths::config_directory()); +} + +ErrorOr<void> DomainListModel::load() +{ + // FIXME: This should be somewhat shared with Browser. + auto file = TRY(Core::Stream::File::open(filter_list_file_path(), Core::Stream::OpenMode::Read)); + auto content_filter_list = TRY(Core::Stream::BufferedFile::create(move(file))); + auto buffer = TRY(ByteBuffer::create_uninitialized(4096)); + while (TRY(content_filter_list->can_read_line())) { + auto length = TRY(content_filter_list->read_line(buffer)); + StringView line { buffer.data(), length }; + dbgln("Content filter for {}", line); + if (!line.is_empty()) + m_domain_list.append(line); + } + + return {}; +} + +ErrorOr<void> DomainListModel::save() +{ + if (!m_was_modified) + return {}; + m_was_modified = false; + + StringBuilder builder; + for (auto const& domain : m_domain_list) + TRY(builder.try_appendff("{}\n", domain)); + + auto file = TRY(Core::Stream::File::open(filter_list_file_path(), Core::Stream::OpenMode::Write)); + TRY(file->write(builder.to_byte_buffer().bytes())); + return {}; +} + +void DomainListModel::add_domain(String name) +{ + begin_insert_rows({}, m_domain_list.size(), m_domain_list.size()); + m_domain_list.append(move(name)); + end_insert_rows(); + m_was_modified = true; + did_update(UpdateFlag::DontInvalidateIndices); +} + +void DomainListModel::delete_domain(size_t index) +{ + begin_delete_rows({}, index, index); + m_domain_list.remove(index); + end_delete_rows(); + m_was_modified = true; + did_update(UpdateFlag::DontInvalidateIndices); +} + +void DomainListModel::reset_default_values() +{ + // FIXME: This probably should not be hardcoded. + m_domain_list = { + "207.net", + "247realmedia.com", + "2o7.net", + "adbrite.com", + "admob.com", + "adthis.com", + "advertising.com", + "aquantive.com", + "atwola.com", + "channelintelligence.com", + "doubleclick.com", + "doubleclick.net", + "esomniture.com", + "google-analytics.com", + "googleadservices.com", + "googlesyndication.com", + "gravity.com", + "hitbox.com", + "intellitxt.com", + "nielsen-online.com", + "omniture.com", + "quantcast.com", + "quantserve.com", + "scorecardresearch.com", + }; + m_was_modified = true; + did_update(UpdateFlag::InvalidateAllIndices); +} + +ContentFilterSettingsWidget::ContentFilterSettingsWidget() +{ + load_from_gml(content_filter_settings_widget_gml); + m_enable_content_filtering_checkbox = find_descendant_of_type_named<GUI::CheckBox>("enable_content_filtering_checkbox"); + m_domain_list_view = find_descendant_of_type_named<GUI::ListView>("domain_list_view"); + m_add_new_domain_button = find_descendant_of_type_named<GUI::Button>("add_new_domain_button"); + + m_enable_content_filtering_checkbox->set_checked(Config::read_bool("Browser", "Preferences", "EnableContentFilters")); + + m_add_new_domain_button->on_click = [&](unsigned) { + String text; + if (GUI::InputBox::show(window(), text, "Enter domain name", "Add domain to Content Filter") == GUI::Dialog::ExecOK) + m_domain_list_model->add_domain(std::move(text)); + }; + + m_domain_list_model = make_ref_counted<DomainListModel>(); + // FIXME: Propagate errors + MUST(m_domain_list_model->load()); + m_domain_list_view->set_model(m_domain_list_model); + + auto delete_action = GUI::CommonActions::make_delete_action([&](GUI::Action const&) { + if (!m_domain_list_view->selection().is_empty()) + m_domain_list_model->delete_domain(m_domain_list_view->selection().first().row()); + }); + m_entry_context_menu = GUI::Menu::construct(); + m_entry_context_menu->add_action(delete_action); + + m_domain_list_view->on_context_menu_request = [&](GUI::ModelIndex const& index, GUI::ContextMenuEvent const& event) { + m_domain_list_view->set_cursor(index, GUI::AbstractView::SelectionUpdate::Set); + m_entry_context_menu->popup(event.screen_position()); + }; +} + +void ContentFilterSettingsWidget::apply_settings() +{ + // FIXME: Propagate errors + MUST(m_domain_list_model->save()); + Config::write_bool("Browser", "Preferences", "EnableContentFilters", m_enable_content_filtering_checkbox->is_checked()); +} + +void ContentFilterSettingsWidget::reset_default_values() +{ + m_domain_list_model->reset_default_values(); +} diff --git a/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.gml b/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.gml new file mode 100644 index 0000000000..db76acb589 --- /dev/null +++ b/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.gml @@ -0,0 +1,41 @@ +@GUI::Frame { + fill_with_background_color: true + + layout: @GUI::VerticalBoxLayout { + margins: [10] + spacing: 5 + } + + @GUI::CheckBox { + name: "enable_content_filtering_checkbox" + text: "Enable content filtering" + } + + @GUI::GroupBox { + title: "Domain list" + + layout: @GUI::VerticalBoxLayout { + margins: [8] + } + + @GUI::ListView { + name: "domain_list_view" + } + + @GUI::Widget { + fixed_height: 32 + + layout: @GUI::HorizontalBoxLayout { + } + + @GUI::Widget { + } + + @GUI::Button { + name: "add_new_domain_button" + fixed_width: 100 + text: "Add new domain" + } + } + } +} diff --git a/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.h b/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.h new file mode 100644 index 0000000000..dea26e5cad --- /dev/null +++ b/Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, Maciej Zygmanowski <sppmacd@pm.me> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "LibGUI/CheckBox.h" +#include <LibGUI/Button.h> +#include <LibGUI/ListView.h> +#include <LibGUI/SettingsWindow.h> + +class DomainListModel : public GUI::Model { +public: + ErrorOr<void> load(); + ErrorOr<void> save(); + void reset_default_values(); + + virtual int row_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return m_domain_list.size(); } + virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return 1; } + virtual GUI::Variant data(GUI::ModelIndex const& index, GUI::ModelRole = GUI::ModelRole::Display) const override { return m_domain_list[index.row()]; } + + void add_domain(String name); + void delete_domain(size_t index); + +private: + bool m_was_modified { false }; + Vector<String> m_domain_list; +}; + +class ContentFilterSettingsWidget : public GUI::SettingsWindow::Tab { + C_OBJECT(ContentFilterSettingsWidget) +public: + virtual void apply_settings() override; + virtual void reset_default_values() override; + +private: + ContentFilterSettingsWidget(); + + RefPtr<GUI::Menu> m_entry_context_menu; + RefPtr<GUI::CheckBox> m_enable_content_filtering_checkbox; + RefPtr<GUI::Button> m_add_new_domain_button; + RefPtr<GUI::ListView> m_domain_list_view; + RefPtr<DomainListModel> m_domain_list_model; +}; diff --git a/Userland/Applications/BrowserSettings/main.cpp b/Userland/Applications/BrowserSettings/main.cpp index f98fe5bd29..965eb16291 100644 --- a/Userland/Applications/BrowserSettings/main.cpp +++ b/Userland/Applications/BrowserSettings/main.cpp @@ -5,6 +5,7 @@ */ #include "BrowserSettingsWidget.h" +#include "ContentFilterSettingsWidget.h" #include <LibConfig/Client.h> #include <LibCore/System.h> #include <LibGUI/Application.h> @@ -14,12 +15,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) { - TRY(Core::System::pledge("stdio rpath recvfd sendfd unix")); + TRY(Core::System::pledge("stdio rpath wpath cpath recvfd sendfd unix")); auto app = TRY(GUI::Application::try_create(arguments)); Config::pledge_domain("Browser"); TRY(Core::System::unveil("/res", "r")); TRY(Core::System::unveil("/home", "r")); + TRY(Core::System::unveil("/home/anon/.config/BrowserContentFilters.txt", "rwc")); TRY(Core::System::unveil(nullptr, nullptr)); auto app_icon = GUI::Icon::default_icon("app-browser"); @@ -27,6 +29,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) auto window = TRY(GUI::SettingsWindow::create("Browser Settings", GUI::SettingsWindow::ShowDefaultsButton::Yes)); window->set_icon(app_icon.bitmap_for_size(16)); (void)TRY(window->add_tab<BrowserSettingsWidget>("Browser")); + (void)TRY(window->add_tab<ContentFilterSettingsWidget>("Content Filtering")); window->show(); return app->exec(); |