summaryrefslogtreecommitdiff
path: root/Userland/Applications
diff options
context:
space:
mode:
authorMaciej <sppmacd@pm.me>2022-01-31 21:41:36 +0100
committerAndreas Kling <kling@serenityos.org>2022-02-18 19:00:42 +0100
commit1606f70f0c039261a5de489c225aee2f1037a3cb (patch)
treebc297e394d54cf74d4a8b9e7a6c7439cfc7533f5 /Userland/Applications
parent4d1c28a23f71f92690a99455e213389519eb143a (diff)
downloadserenity-1606f70f0c039261a5de489c225aee2f1037a3cb.zip
BrowserSettings: Implement GUI for setting up content filters :^)
Diffstat (limited to 'Userland/Applications')
-rw-r--r--Userland/Applications/BrowserSettings/CMakeLists.txt3
-rw-r--r--Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.cpp152
-rw-r--r--Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.gml41
-rw-r--r--Userland/Applications/BrowserSettings/ContentFilterSettingsWidget.h46
-rw-r--r--Userland/Applications/BrowserSettings/main.cpp5
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();