diff --git a/Userland/Applications/Browser/BrowserWindow.cpp b/Userland/Applications/Browser/BrowserWindow.cpp index e197378b951..c7029a3384b 100644 --- a/Userland/Applications/Browser/BrowserWindow.cpp +++ b/Userland/Applications/Browser/BrowserWindow.cpp @@ -280,6 +280,14 @@ void BrowserWindow::build_menus() storage_window_action->set_status_tip("Show Storage inspector for this page"); inspect_menu.add_action(storage_window_action); + auto history_window_action = GUI::Action::create( + "Open &History Window", g_icon_bag.history, [this](auto&) { + active_tab().show_history_inspector(); + }, + this); + storage_window_action->set_status_tip("Show History inspector for this tab"); + inspect_menu.add_action(history_window_action); + auto& settings_menu = add_menu("&Settings"); m_change_homepage_action = GUI::Action::create( diff --git a/Userland/Applications/Browser/CMakeLists.txt b/Userland/Applications/Browser/CMakeLists.txt index df474a785f2..908c036417d 100644 --- a/Userland/Applications/Browser/CMakeLists.txt +++ b/Userland/Applications/Browser/CMakeLists.txt @@ -7,6 +7,7 @@ serenity_component( compile_gml(BrowserWindow.gml BrowserWindowGML.h browser_window_gml) compile_gml(EditBookmark.gml EditBookmarkGML.h edit_bookmark_gml) +compile_gml(History/HistoryWidget.gml HistoryWidgetGML.h history_widget_gml) compile_gml(StorageWidget.gml StorageWidgetGML.h storage_widget_gml) compile_gml(Tab.gml TabGML.h tab_gml) @@ -20,6 +21,8 @@ set(SOURCES DownloadWidget.cpp ElementSizePreviewWidget.cpp History.cpp + History/HistoryModel.cpp + History/HistoryWidget.cpp IconBag.cpp InspectorWidget.cpp StorageModel.cpp @@ -32,6 +35,7 @@ set(SOURCES set(GENERATED_SOURCES BrowserWindowGML.h EditBookmarkGML.h + HistoryWidgetGML.h StorageWidgetGML.h TabGML.h ) diff --git a/Userland/Applications/Browser/History.cpp b/Userland/Applications/Browser/History.cpp index fce443159e3..52d189fd615 100644 --- a/Userland/Applications/Browser/History.cpp +++ b/Userland/Applications/Browser/History.cpp @@ -18,6 +18,11 @@ void History::dump() const } } +Vector History::get_all_history_entries() +{ + return m_items; +} + void History::push(const URL& url, DeprecatedString const& title) { if (!m_items.is_empty() && m_items[m_current].url == url) diff --git a/Userland/Applications/Browser/History.h b/Userland/Applications/Browser/History.h index cdc0d33fd5e..16fbfd0740e 100644 --- a/Userland/Applications/Browser/History.h +++ b/Userland/Applications/Browser/History.h @@ -18,6 +18,7 @@ public: DeprecatedString title; }; void dump() const; + Vector get_all_history_entries(); void push(const URL& url, DeprecatedString const& title); void replace_current(const URL& url, DeprecatedString const& title); diff --git a/Userland/Applications/Browser/History/HistoryModel.cpp b/Userland/Applications/Browser/History/HistoryModel.cpp new file mode 100644 index 00000000000..d40f34bae15 --- /dev/null +++ b/Userland/Applications/Browser/History/HistoryModel.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "HistoryModel.h" +#include + +namespace Browser { + +void HistoryModel::set_items(AK::Vector items) +{ + begin_insert_rows({}, m_entries.size(), m_entries.size()); + m_entries = items; + end_insert_rows(); + + did_update(DontInvalidateIndices); +} + +void HistoryModel::clear_items() +{ + begin_insert_rows({}, m_entries.size(), m_entries.size()); + m_entries.clear(); + end_insert_rows(); + + did_update(DontInvalidateIndices); +} + +int HistoryModel::row_count(GUI::ModelIndex const& index) const +{ + if (!index.is_valid()) + return m_entries.size(); + return 0; +} + +DeprecatedString HistoryModel::column_name(int column) const +{ + switch (column) { + case Column::Title: + return "Title"; + case Column::URL: + return "URL"; + default: + VERIFY_NOT_REACHED(); + } + + return {}; +} + +GUI::ModelIndex HistoryModel::index(int row, int column, GUI::ModelIndex const&) const +{ + if (static_cast(row) < m_entries.size()) + return create_index(row, column, &m_entries.at(row)); + return {}; +} + +GUI::Variant HistoryModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const +{ + if (role != GUI::ModelRole::Display) + return {}; + + auto const& history_entry = m_entries[index.row()]; + + switch (index.column()) { + case Column::Title: + return history_entry.title; + case Column::URL: + return history_entry.url.serialize(); + } + + VERIFY_NOT_REACHED(); +} + +TriState HistoryModel::data_matches(GUI::ModelIndex const& index, GUI::Variant const& term) const +{ + auto needle = term.as_string(); + if (needle.is_empty()) + return TriState::True; + + auto const& history_entry = m_entries[index.row()]; + auto haystack = DeprecatedString::formatted("{} {}", history_entry.title, history_entry.url.serialize()); + if (fuzzy_match(needle, haystack).score > 0) + return TriState::True; + return TriState::False; +} + +} diff --git a/Userland/Applications/Browser/History/HistoryModel.h b/Userland/Applications/Browser/History/HistoryModel.h new file mode 100644 index 00000000000..10df2405715 --- /dev/null +++ b/Userland/Applications/Browser/History/HistoryModel.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "Applications/Browser/History.h" +#include +#include +#include + +namespace Browser { + +class HistoryModel final : public GUI::Model { +public: + enum Column { + Title, + URL, + __Count, + }; + + void set_items(AK::Vector items); + void clear_items(); + virtual int row_count(GUI::ModelIndex const&) const override; + virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Count; } + virtual DeprecatedString 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; + virtual TriState data_matches(GUI::ModelIndex const& index, GUI::Variant const& term) const override; + +private: + AK::Vector m_entries; +}; + +} diff --git a/Userland/Applications/Browser/History/HistoryWidget.cpp b/Userland/Applications/Browser/History/HistoryWidget.cpp new file mode 100644 index 00000000000..6519e2a9ff7 --- /dev/null +++ b/Userland/Applications/Browser/History/HistoryWidget.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "HistoryWidget.h" +#include +#include + +namespace Browser { +HistoryWidget::HistoryWidget() +{ + load_from_gml(history_widget_gml); + + m_table_view = find_descendant_of_type_named("history_tableview"); + m_textbox = find_descendant_of_type_named("history_filter_textbox"); + + m_model = adopt_ref(*new HistoryModel()); + + m_filtering_model = MUST(GUI::FilteringProxyModel::create(*m_model)); + m_filtering_model->set_filter_term(""sv); + + m_textbox->on_change = [this] { + m_filtering_model->set_filter_term(m_textbox->text()); + if (m_filtering_model->row_count() != 0) + m_table_view->set_cursor(m_filtering_model->index(0, 0), GUI::AbstractView::SelectionUpdate::Set); + }; + + m_table_view->set_model(m_filtering_model); + m_table_view->set_alternating_row_colors(true); +} + +void HistoryWidget::set_history_entries(Vector entries) +{ + m_model->set_items(entries); +} + +void HistoryWidget::clear_history_entries() +{ + m_model->clear_items(); +} + +} diff --git a/Userland/Applications/Browser/History/HistoryWidget.gml b/Userland/Applications/Browser/History/HistoryWidget.gml new file mode 100644 index 00000000000..d72c8a9a02a --- /dev/null +++ b/Userland/Applications/Browser/History/HistoryWidget.gml @@ -0,0 +1,15 @@ +@GUI::Widget { + fill_with_background_color: true + layout: @GUI::VerticalBoxLayout { + margins: [4] + } + + @GUI::TextBox { + name: "history_filter_textbox" + placeholder: "Filter" + } + + @GUI::TableView { + name: "history_tableview" + } +} diff --git a/Userland/Applications/Browser/History/HistoryWidget.h b/Userland/Applications/Browser/History/HistoryWidget.h new file mode 100644 index 00000000000..5d518f596f9 --- /dev/null +++ b/Userland/Applications/Browser/History/HistoryWidget.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "Applications/Browser/History.h" +#include "HistoryModel.h" +#include +#include +#include + +namespace Browser { + +class HistoryWidget final : public GUI::Widget { + C_OBJECT(HistoryWidget); + +public: + virtual ~HistoryWidget() override = default; + + void set_history_entries(Vector entries); + void clear_history_entries(); + +private: + HistoryWidget(); + + RefPtr m_table_view; + RefPtr m_textbox; + RefPtr m_model; + RefPtr m_filtering_model; +}; + +} diff --git a/Userland/Applications/Browser/Tab.cpp b/Userland/Applications/Browser/Tab.cpp index d6f32ed3f63..477162a62fb 100644 --- a/Userland/Applications/Browser/Tab.cpp +++ b/Userland/Applications/Browser/Tab.cpp @@ -14,6 +14,7 @@ #include "BrowserWindow.h" #include "ConsoleWidget.h" #include "DownloadWidget.h" +#include "History/HistoryWidget.h" #include "InspectorWidget.h" #include "StorageWidget.h" #include @@ -752,6 +753,24 @@ void Tab::show_storage_inspector() window->move_to_front(); } +void Tab::show_history_inspector() +{ + if (!m_history_widget) { + auto history_window = GUI::Window::construct(&window()); + history_window->resize(500, 300); + history_window->set_title("History"); + history_window->set_icon(g_icon_bag.history); + m_history_widget = history_window->set_main_widget(); + } + + m_history_widget->clear_history_entries(); + m_history_widget->set_history_entries(m_history.get_all_history_entries()); + + auto* window = m_history_widget->window(); + window->show(); + window->move_to_front(); +} + void Tab::show_event(GUI::ShowEvent&) { m_web_content_view->set_visible(true); diff --git a/Userland/Applications/Browser/Tab.h b/Userland/Applications/Browser/Tab.h index f5d076f1fe3..84ef7d316d2 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 HistoryWidget; class StorageWidget; class Tab final : public GUI::Widget { @@ -86,6 +87,7 @@ public: void show_console_window(); void show_storage_inspector(); + void show_history_inspector(); DeprecatedString const& title() const { return m_title; } Gfx::Bitmap const* icon() const { return m_icon; } @@ -125,6 +127,7 @@ private: RefPtr m_dom_inspector_widget; RefPtr m_console_widget; RefPtr m_storage_widget; + RefPtr m_history_widget; RefPtr m_statusbar; RefPtr m_toolbar_container;