/* * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include <AK/URL.h> #include <AK/Vector.h> #include <LibConfig/Listener.h> #include <LibDesktop/Launcher.h> #include <LibGUI/Action.h> #include <LibGUI/ColumnsView.h> #include <LibGUI/FileSystemModel.h> #include <LibGUI/IconView.h> #include <LibGUI/StackWidget.h> #include <LibGUI/TableView.h> #include <fcntl.h> #include <sys/stat.h> namespace FileManager { void spawn_terminal(String const& directory); class LauncherHandler : public RefCounted<LauncherHandler> { public: LauncherHandler(NonnullRefPtr<Desktop::Launcher::Details> const& details) : m_details(details) { } NonnullRefPtr<GUI::Action> create_launch_action(Function<void(LauncherHandler const&)>); Desktop::Launcher::Details const& details() const { return *m_details; } private: NonnullRefPtr<Desktop::Launcher::Details> m_details; }; class DirectoryView final : public GUI::StackWidget , private GUI::ModelClient , public Config::Listener { C_OBJECT(DirectoryView); public: enum class Mode { Desktop, Normal, }; virtual ~DirectoryView() override; bool open(String const& path); String path() const { return model().root_path(); } void open_parent_directory(); void open_previous_directory(); void open_next_directory(); int path_history_size() const { return m_path_history.size(); } int path_history_position() const { return m_path_history_position; } static RefPtr<LauncherHandler> get_default_launch_handler(NonnullRefPtrVector<LauncherHandler> const& handlers); static NonnullRefPtrVector<LauncherHandler> get_launch_handlers(URL const& url); static NonnullRefPtrVector<LauncherHandler> get_launch_handlers(String const& path); void refresh(); void launch(URL const&, LauncherHandler const&) const; Function<void(StringView path, bool can_read_in_path, bool can_write_in_path)> on_path_change; Function<void(GUI::AbstractView&)> on_selection_change; Function<void(GUI::ModelIndex const&, GUI::ContextMenuEvent const&)> on_context_menu_request; Function<void(StringView)> on_status_message; Function<void(int done, int total)> on_thumbnail_progress; Function<void()> on_accepted_drop; enum ViewMode { Invalid, Table, Columns, Icon }; void set_view_mode(ViewMode); ViewMode view_mode() const { return m_view_mode; } void set_view_mode_from_string(String const&); GUI::AbstractView& current_view() { switch (m_view_mode) { case ViewMode::Table: return *m_table_view; case ViewMode::Columns: return *m_columns_view; case ViewMode::Icon: return *m_icon_view; default: VERIFY_NOT_REACHED(); } } GUI::AbstractView const& current_view() const { return const_cast<DirectoryView*>(this)->current_view(); } template<typename Callback> void for_each_view_implementation(Callback callback) { if (m_icon_view) callback(*m_icon_view); if (m_table_view) callback(*m_table_view); if (m_columns_view) callback(*m_columns_view); } void set_should_show_dotfiles(bool); GUI::FileSystemModel::Node const& node(GUI::ModelIndex const&) const; bool is_desktop() const { return m_mode == Mode::Desktop; } Vector<String> selected_file_paths() const; GUI::Action& mkdir_action() { return *m_mkdir_action; } GUI::Action& touch_action() { return *m_touch_action; } GUI::Action& open_terminal_action() { return *m_open_terminal_action; } GUI::Action& delete_action() { return *m_delete_action; } GUI::Action& force_delete_action() { return *m_force_delete_action; } GUI::Action& rename_action() { return *m_rename_action; } GUI::Action& view_as_icons_action() { return *m_view_as_icons_action; } GUI::Action& view_as_table_action() { return *m_view_as_table_action; } GUI::Action& view_as_columns_action() { return *m_view_as_columns_action; } // ^Config::Listener virtual void config_string_did_change(String const& domain, String const& group, String const& key, String const& value) override; private: explicit DirectoryView(Mode); GUI::FileSystemModel const& model() const { return *m_model; } GUI::FileSystemModel& model() { return *m_model; } void handle_selection_change(); void handle_drop(GUI::ModelIndex const&, GUI::DropEvent const&); void do_delete(bool should_confirm); // ^GUI::ModelClient virtual void model_did_update(unsigned) override; void setup_actions(); void setup_model(); void setup_icon_view(); void setup_columns_view(); void setup_table_view(); void handle_activation(GUI::ModelIndex const&); void set_status_message(StringView); void update_statusbar(); bool can_modify_current_selection(); Mode m_mode { Mode::Normal }; ViewMode m_view_mode { Invalid }; NonnullRefPtr<GUI::FileSystemModel> m_model; NonnullRefPtr<GUI::SortingProxyModel> m_sorting_model; size_t m_path_history_position { 0 }; Vector<String> m_path_history; void add_path_to_history(String); RefPtr<GUI::Label> m_error_label; RefPtr<GUI::TableView> m_table_view; RefPtr<GUI::IconView> m_icon_view; RefPtr<GUI::ColumnsView> m_columns_view; RefPtr<GUI::Action> m_mkdir_action; RefPtr<GUI::Action> m_touch_action; RefPtr<GUI::Action> m_open_terminal_action; RefPtr<GUI::Action> m_delete_action; RefPtr<GUI::Action> m_force_delete_action; RefPtr<GUI::Action> m_rename_action; RefPtr<GUI::Action> m_view_as_table_action; RefPtr<GUI::Action> m_view_as_icons_action; RefPtr<GUI::Action> m_view_as_columns_action; }; }