Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/URL.h>
10#include <AK/Vector.h>
11#include <LibConfig/Listener.h>
12#include <LibDesktop/Launcher.h>
13#include <LibGUI/Action.h>
14#include <LibGUI/ColumnsView.h>
15#include <LibGUI/FileSystemModel.h>
16#include <LibGUI/IconView.h>
17#include <LibGUI/StackWidget.h>
18#include <LibGUI/TableView.h>
19#include <fcntl.h>
20#include <sys/stat.h>
21
22namespace FileManager {
23
24void spawn_terminal(DeprecatedString const& directory);
25
26class LauncherHandler : public RefCounted<LauncherHandler> {
27public:
28 LauncherHandler(NonnullRefPtr<Desktop::Launcher::Details> const& details)
29 : m_details(details)
30 {
31 }
32
33 NonnullRefPtr<GUI::Action> create_launch_action(Function<void(LauncherHandler const&)>);
34 Desktop::Launcher::Details const& details() const { return *m_details; }
35
36private:
37 NonnullRefPtr<Desktop::Launcher::Details> m_details;
38};
39
40class DirectoryView final
41 : public GUI::StackWidget
42 , private GUI::ModelClient
43 , public Config::Listener {
44 C_OBJECT(DirectoryView);
45
46public:
47 enum class Mode {
48 Desktop,
49 Normal,
50 };
51
52 virtual ~DirectoryView() override;
53
54 bool open(DeprecatedString const& path);
55 DeprecatedString path() const { return model().root_path(); }
56 void open_parent_directory();
57 void open_previous_directory();
58 void open_next_directory();
59 int path_history_size() const { return m_path_history.size(); }
60 int path_history_position() const { return m_path_history_position; }
61 static RefPtr<LauncherHandler> get_default_launch_handler(Vector<NonnullRefPtr<LauncherHandler>> const& handlers);
62 static Vector<NonnullRefPtr<LauncherHandler>> get_launch_handlers(URL const& url);
63 static Vector<NonnullRefPtr<LauncherHandler>> get_launch_handlers(DeprecatedString const& path);
64
65 void refresh();
66
67 void launch(URL const&, LauncherHandler const&) const;
68
69 Function<void(StringView path, bool can_read_in_path, bool can_write_in_path)> on_path_change;
70 Function<void(GUI::AbstractView&)> on_selection_change;
71 Function<void(GUI::ModelIndex const&, GUI::ContextMenuEvent const&)> on_context_menu_request;
72 Function<void(StringView)> on_status_message;
73 Function<void(int done, int total)> on_thumbnail_progress;
74 Function<void()> on_accepted_drop;
75
76 enum ViewMode {
77 Invalid,
78 Table,
79 Columns,
80 Icon
81 };
82 void set_view_mode(ViewMode);
83 ViewMode view_mode() const { return m_view_mode; }
84
85 void set_view_mode_from_string(DeprecatedString const&);
86
87 GUI::AbstractView& current_view()
88 {
89 switch (m_view_mode) {
90 case ViewMode::Table:
91 return *m_table_view;
92 case ViewMode::Columns:
93 return *m_columns_view;
94 case ViewMode::Icon:
95 return *m_icon_view;
96 default:
97 VERIFY_NOT_REACHED();
98 }
99 }
100
101 GUI::AbstractView const& current_view() const
102 {
103 return const_cast<DirectoryView*>(this)->current_view();
104 }
105
106 template<typename Callback>
107 void for_each_view_implementation(Callback callback)
108 {
109 if (m_icon_view)
110 callback(*m_icon_view);
111 if (m_table_view)
112 callback(*m_table_view);
113 if (m_columns_view)
114 callback(*m_columns_view);
115 }
116
117 void set_should_show_dotfiles(bool);
118
119 GUI::FileSystemModel::Node const& node(GUI::ModelIndex const&) const;
120
121 bool is_desktop() const { return m_mode == Mode::Desktop; }
122
123 Vector<DeprecatedString> selected_file_paths() const;
124
125 GUI::Action& mkdir_action() { return *m_mkdir_action; }
126 GUI::Action& touch_action() { return *m_touch_action; }
127 GUI::Action& open_terminal_action() { return *m_open_terminal_action; }
128 GUI::Action& delete_action() { return *m_delete_action; }
129 GUI::Action& force_delete_action() { return *m_force_delete_action; }
130 GUI::Action& rename_action() { return *m_rename_action; }
131 GUI::Action& view_as_icons_action() { return *m_view_as_icons_action; }
132 GUI::Action& view_as_table_action() { return *m_view_as_table_action; }
133 GUI::Action& view_as_columns_action() { return *m_view_as_columns_action; }
134
135 // ^Config::Listener
136 virtual void config_string_did_change(DeprecatedString const& domain, DeprecatedString const& group, DeprecatedString const& key, DeprecatedString const& value) override;
137
138private:
139 explicit DirectoryView(Mode);
140
141 GUI::FileSystemModel const& model() const { return *m_model; }
142 GUI::FileSystemModel& model() { return *m_model; }
143
144 void handle_selection_change();
145 void handle_drop(GUI::ModelIndex const&, GUI::DropEvent const&);
146 void do_delete(bool should_confirm);
147
148 // ^GUI::ModelClient
149 virtual void model_did_update(unsigned) override;
150
151 void setup_actions();
152 void setup_model();
153 void setup_icon_view();
154 void setup_columns_view();
155 void setup_table_view();
156
157 void handle_activation(GUI::ModelIndex const&);
158
159 void set_status_message(StringView);
160 void update_statusbar();
161 bool can_modify_current_selection();
162
163 Mode m_mode { Mode::Normal };
164 ViewMode m_view_mode { Invalid };
165
166 NonnullRefPtr<GUI::FileSystemModel> m_model;
167 NonnullRefPtr<GUI::SortingProxyModel> m_sorting_model;
168 size_t m_path_history_position { 0 };
169 Vector<DeprecatedString> m_path_history;
170 void add_path_to_history(DeprecatedString);
171
172 RefPtr<GUI::Label> m_error_label;
173
174 RefPtr<GUI::TableView> m_table_view;
175 RefPtr<GUI::IconView> m_icon_view;
176 RefPtr<GUI::ColumnsView> m_columns_view;
177
178 RefPtr<GUI::Action> m_mkdir_action;
179 RefPtr<GUI::Action> m_touch_action;
180 RefPtr<GUI::Action> m_open_terminal_action;
181 RefPtr<GUI::Action> m_delete_action;
182 RefPtr<GUI::Action> m_force_delete_action;
183 RefPtr<GUI::Action> m_rename_action;
184
185 RefPtr<GUI::Action> m_view_as_table_action;
186 RefPtr<GUI::Action> m_view_as_icons_action;
187 RefPtr<GUI::Action> m_view_as_columns_action;
188};
189
190}