2020-01-18 05:38:21 -03:00
/*
2021-04-05 18:12:53 -03:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < kling @ serenityos . org >
2020-01-18 05:38:21 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 05:38:21 -03:00
*/
2020-09-17 09:34:47 -03:00
# include "DesktopWidget.h"
2019-06-07 06:48:03 -03:00
# include "DirectoryView.h"
2019-09-10 10:21:58 -03:00
# include "FileUtils.h"
2021-01-01 20:31:30 -03:00
# include "PropertiesWindow.h"
2020-05-26 08:52:44 -03:00
# include <AK/LexicalPath.h>
2019-09-10 10:21:58 -03:00
# include <AK/StringBuilder.h>
2020-02-13 17:55:05 -03:00
# include <AK/URL.h>
2020-12-20 08:17:59 -03:00
# include <Applications/FileManager/FileManagerWindowGML.h>
2021-03-05 16:43:39 -03:00
# include <LibCore/ArgsParser.h>
2020-02-06 11:04:03 -03:00
# include <LibCore/ConfigFile.h>
2021-02-20 21:56:28 -03:00
# include <LibCore/File.h>
2020-02-14 09:18:34 -03:00
# include <LibCore/MimeData.h>
2020-04-19 14:57:05 -03:00
# include <LibCore/StandardPaths.h>
2020-04-26 16:30:01 -03:00
# include <LibDesktop/Launcher.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/Action.h>
# include <LibGUI/ActionGroup.h>
# include <LibGUI/Application.h>
# include <LibGUI/BoxLayout.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Breadcrumbbar.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/Clipboard.h>
2020-08-14 17:17:46 -03:00
# include <LibGUI/Desktop.h>
2020-09-16 15:57:41 -03:00
# include <LibGUI/FileIconProvider.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/FileSystemModel.h>
# include <LibGUI/InputBox.h>
# include <LibGUI/Label.h>
2020-02-14 21:56:30 -03:00
# include <LibGUI/Menu.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Menubar.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/MessageBox.h>
2020-04-18 17:04:41 -03:00
# include <LibGUI/Painter.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Progressbar.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/Splitter.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Statusbar.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/TextEditor.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Toolbar.h>
# include <LibGUI/ToolbarContainer.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/TreeView.h>
# include <LibGUI/Widget.h>
# include <LibGUI/Window.h>
2020-04-18 17:04:41 -03:00
# include <LibGfx/Palette.h>
2020-08-10 15:29:08 -03:00
# include <pthread.h>
2020-08-04 09:09:42 -03:00
# include <serenity.h>
2019-03-01 11:47:07 -03:00
# include <signal.h>
2020-06-28 14:40:10 -03:00
# include <spawn.h>
2019-02-09 06:22:04 -02:00
# include <stdio.h>
2020-03-08 08:05:14 -03:00
# include <string.h>
2021-04-25 10:36:27 -03:00
# include <sys/wait.h>
2019-06-07 06:48:03 -03:00
# include <unistd.h>
2019-02-09 06:22:04 -02:00
2020-09-17 10:26:00 -03:00
using namespace FileManager ;
2020-08-17 14:52:01 -03:00
static int run_in_desktop_mode ( RefPtr < Core : : ConfigFile > ) ;
2021-02-28 15:54:03 -03:00
static int run_in_windowed_mode ( RefPtr < Core : : ConfigFile > , String initial_location , String entry_focused_on_init ) ;
2020-12-28 12:50:51 -03:00
static void do_copy ( const Vector < String > & selected_file_paths , FileUtils : : FileOperation file_operation ) ;
2020-12-10 04:07:01 -03:00
static void do_paste ( const String & target_directory , GUI : : Window * window ) ;
2020-12-22 12:57:59 -03:00
static void do_create_link ( const Vector < String > & selected_file_paths , GUI : : Window * window ) ;
2021-04-25 10:36:27 -03:00
static void do_unzip_archive ( const Vector < String > & selected_file_paths , GUI : : Window * window ) ;
2020-12-10 04:07:01 -03:00
static void show_properties ( const String & container_dir_path , const String & path , const Vector < String > & selected , GUI : : Window * window ) ;
2021-03-03 08:00:32 -03:00
static bool add_launch_handler_actions_to_menu ( RefPtr < GUI : : Menu > & menu , const DirectoryView & directory_view , const String & full_path , RefPtr < GUI : : Action > & default_action , NonnullRefPtrVector < LauncherHandler > & current_file_launch_handlers ) ;
2020-04-18 17:04:41 -03:00
2019-02-11 11:56:23 -02:00
int main ( int argc , char * * argv )
2019-02-09 06:22:04 -02:00
{
2021-01-16 13:42:31 -03:00
if ( pledge ( " stdio thread recvfd sendfd accept unix cpath rpath wpath fattr proc exec sigaction " , nullptr ) < 0 ) {
2020-01-11 18:13:38 -03:00
perror ( " pledge " ) ;
return 1 ;
}
2019-03-01 11:47:07 -03:00
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
act . sa_flags = SA_NOCLDWAIT ;
act . sa_handler = SIG_IGN ;
int rc = sigaction ( SIGCHLD , & act , nullptr ) ;
if ( rc < 0 ) {
perror ( " sigaction " ) ;
return 1 ;
}
2020-02-02 08:34:39 -03:00
RefPtr < Core : : ConfigFile > config = Core : : ConfigFile : : get_for_app ( " FileManager " ) ;
2019-11-04 13:27:56 -03:00
2021-03-05 16:43:39 -03:00
Core : : ArgsParser args_parser ;
bool is_desktop_mode { false } , is_selection_mode { false } , ignore_path_resolution { false } ;
String initial_location ;
args_parser . add_option ( is_desktop_mode , " Run in desktop mode " , " desktop " , ' d ' ) ;
args_parser . add_option ( is_selection_mode , " Show entry in parent folder " , " select " , ' s ' ) ;
args_parser . add_option ( ignore_path_resolution , " Use raw path, do not resolve real path " , " raw " , ' r ' ) ;
args_parser . add_positional_argument ( initial_location , " Path to open " , " path " , Core : : ArgsParser : : Required : : No ) ;
args_parser . parse ( argc , argv ) ;
2020-07-04 09:05:19 -03:00
auto app = GUI : : Application : : construct ( argc , argv ) ;
2019-02-09 06:22:04 -02:00
2021-01-16 13:42:31 -03:00
if ( pledge ( " stdio thread recvfd sendfd accept cpath rpath wpath fattr proc exec unix " , nullptr ) < 0 ) {
2020-01-12 07:59:11 -03:00
perror ( " pledge " ) ;
return 1 ;
}
2021-03-05 16:43:39 -03:00
if ( is_desktop_mode )
2020-08-17 14:52:01 -03:00
return run_in_desktop_mode ( move ( config ) ) ;
2020-04-18 17:04:41 -03:00
// our initial location is defined as, in order of precedence:
2021-03-05 16:43:39 -03:00
// 1. the command-line path argument (e.g. FileManager /bin)
2020-04-18 17:04:41 -03:00
// 2. the user's home directory
// 3. the root directory
2021-03-05 16:43:39 -03:00
if ( ! initial_location . is_empty ( ) ) {
if ( ! ignore_path_resolution )
initial_location = Core : : File : : real_path_for ( initial_location ) ;
if ( ! Core : : File : : is_directory ( initial_location ) )
is_selection_mode = true ;
2020-04-30 17:38:03 -03:00
}
2020-04-18 17:04:41 -03:00
if ( initial_location . is_empty ( ) )
2020-04-19 14:57:05 -03:00
initial_location = Core : : StandardPaths : : home_directory ( ) ;
2020-04-18 17:04:41 -03:00
if ( initial_location . is_empty ( ) )
initial_location = " / " ;
2021-02-28 15:54:03 -03:00
String focused_entry ;
2021-03-05 16:43:39 -03:00
if ( is_selection_mode ) {
LexicalPath path ( initial_location ) ;
initial_location = path . dirname ( ) ;
focused_entry = path . basename ( ) ;
}
2021-02-28 15:54:03 -03:00
return run_in_windowed_mode ( move ( config ) , initial_location , focused_entry ) ;
2020-04-18 17:04:41 -03:00
}
2020-12-28 12:50:51 -03:00
void do_copy ( const Vector < String > & selected_file_paths , FileUtils : : FileOperation file_operation )
2020-12-10 04:07:01 -03:00
{
if ( selected_file_paths . is_empty ( ) )
2021-02-23 16:42:32 -03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-10 04:07:01 -03:00
StringBuilder copy_text ;
2020-12-28 12:50:51 -03:00
if ( file_operation = = FileUtils : : FileOperation : : Cut ) {
copy_text . append ( " #cut \n " ) ; // This exploits the comment lines in the text/uri-list specification, which might be a bit hackish
}
2020-12-10 04:07:01 -03:00
for ( auto & path : selected_file_paths ) {
auto url = URL : : create_with_file_protocol ( path ) ;
copy_text . appendff ( " {} \n " , url ) ;
}
GUI : : Clipboard : : the ( ) . set_data ( copy_text . build ( ) . bytes ( ) , " text/uri-list " ) ;
}
void do_paste ( const String & target_directory , GUI : : Window * window )
{
auto data_and_type = GUI : : Clipboard : : the ( ) . data_and_type ( ) ;
if ( data_and_type . mime_type ! = " text/uri-list " ) {
dbgln ( " Cannot paste clipboard type {} " , data_and_type . mime_type ) ;
return ;
}
auto copied_lines = String : : copy ( data_and_type . data ) . split ( ' \n ' ) ;
if ( copied_lines . is_empty ( ) ) {
dbgln ( " No files to paste " ) ;
return ;
}
2020-12-28 12:50:51 -03:00
bool should_delete_src = false ;
if ( copied_lines [ 0 ] = = " #cut " ) { // cut operation encoded as a text/uri-list commen
should_delete_src = true ;
copied_lines . remove ( 0 ) ;
}
2020-12-10 04:07:01 -03:00
for ( auto & uri_as_string : copied_lines ) {
if ( uri_as_string . is_empty ( ) )
continue ;
URL url = uri_as_string ;
if ( ! url . is_valid ( ) | | url . protocol ( ) ! = " file " ) {
dbgln ( " Cannot paste URI {} " , uri_as_string ) ;
continue ;
}
auto new_path = String : : formatted ( " {}/{} " , target_directory , url . basename ( ) ) ;
2021-02-20 21:56:28 -03:00
if ( auto result = Core : : File : : copy_file_or_directory ( new_path , url . path ( ) ) ; result . is_error ( ) ) {
auto error_message = String : : formatted ( " Could not paste '{}': {} " , url . path ( ) , result . error ( ) . error_code ) ;
2020-12-10 04:07:01 -03:00
GUI : : MessageBox : : show ( window , error_message , " File Manager " , GUI : : MessageBox : : Type : : Error ) ;
2020-12-28 12:50:51 -03:00
} else if ( should_delete_src ) {
FileUtils : : delete_path ( url . path ( ) , window ) ;
2020-12-10 04:07:01 -03:00
}
}
}
2020-12-22 12:57:59 -03:00
void do_create_link ( const Vector < String > & selected_file_paths , GUI : : Window * window )
{
auto path = selected_file_paths . first ( ) ;
2020-12-28 05:38:11 -03:00
auto destination = String : : formatted ( " {}/{} " , Core : : StandardPaths : : desktop_directory ( ) , LexicalPath { path } . basename ( ) ) ;
2021-02-20 21:56:28 -03:00
if ( auto result = Core : : File : : link_file ( destination , path ) ; result . is_error ( ) ) {
GUI : : MessageBox : : show ( window , String : : formatted ( " Could not create desktop shortcut: \n {} " , result . error ( ) ) , " File Manager " ,
2020-12-22 12:57:59 -03:00
GUI : : MessageBox : : Type : : Error ) ;
}
}
2021-04-25 10:36:27 -03:00
void do_unzip_archive ( const Vector < String > & selected_file_paths , GUI : : Window * window )
{
String archive_file_path = selected_file_paths . first ( ) ;
String output_directory_path = archive_file_path . substring ( 0 , archive_file_path . length ( ) - 4 ) ;
pid_t unzip_pid = fork ( ) ;
if ( unzip_pid < 0 ) {
perror ( " fork " ) ;
VERIFY_NOT_REACHED ( ) ;
}
if ( ! unzip_pid ) {
int rc = execlp ( " /bin/unzip " , " /bin/unzip " , " -o " , output_directory_path . characters ( ) , archive_file_path . characters ( ) , nullptr ) ;
if ( rc < 0 ) {
perror ( " execlp " ) ;
_exit ( 1 ) ;
}
} else {
// FIXME: this could probably be tied in with the new file operation progress tracking
int status ;
int rc = waitpid ( unzip_pid , & status , 0 ) ;
if ( rc < 0 | | ! WIFEXITED ( status ) | | WEXITSTATUS ( status ) ! = 0 )
GUI : : MessageBox : : show ( window , " Could not extract archive " , " Extract Archive Error " , GUI : : MessageBox : : Type : : Error ) ;
}
}
2020-12-10 04:07:01 -03:00
void show_properties ( const String & container_dir_path , const String & path , const Vector < String > & selected , GUI : : Window * window )
{
2021-01-01 20:31:30 -03:00
RefPtr < PropertiesWindow > properties ;
2020-12-10 04:07:01 -03:00
if ( selected . is_empty ( ) ) {
2021-01-01 20:31:30 -03:00
properties = window - > add < PropertiesWindow > ( path , true ) ;
2020-12-10 04:07:01 -03:00
} else {
2021-01-01 20:31:30 -03:00
properties = window - > add < PropertiesWindow > ( selected . first ( ) , access ( container_dir_path . characters ( ) , W_OK ) ! = 0 ) ;
2020-12-10 04:07:01 -03:00
}
2021-01-01 20:31:30 -03:00
properties - > on_close = [ properties = properties . ptr ( ) ] {
properties - > remove_from_parent ( ) ;
} ;
properties - > center_on_screen ( ) ;
properties - > show ( ) ;
2020-12-10 04:07:01 -03:00
}
2021-03-03 08:00:32 -03:00
bool add_launch_handler_actions_to_menu ( RefPtr < GUI : : Menu > & menu , const DirectoryView & directory_view , const String & full_path , RefPtr < GUI : : Action > & default_action , NonnullRefPtrVector < LauncherHandler > & current_file_launch_handlers )
{
current_file_launch_handlers = directory_view . get_launch_handlers ( full_path ) ;
bool added_open_menu_items = false ;
auto default_file_handler = directory_view . get_default_launch_handler ( current_file_launch_handlers ) ;
if ( default_file_handler ) {
auto file_open_action = default_file_handler - > create_launch_action ( [ & , full_path = move ( full_path ) ] ( auto & launcher_handler ) {
directory_view . launch ( URL : : create_with_file_protocol ( full_path ) , launcher_handler ) ;
} ) ;
if ( default_file_handler - > details ( ) . launcher_type = = Desktop : : Launcher : : LauncherType : : Application )
file_open_action - > set_text ( String : : formatted ( " Run {} " , file_open_action - > text ( ) ) ) ;
else
file_open_action - > set_text ( String : : formatted ( " Open in {} " , file_open_action - > text ( ) ) ) ;
default_action = file_open_action ;
menu - > add_action ( move ( file_open_action ) ) ;
added_open_menu_items = true ;
} else {
default_action . clear ( ) ;
}
if ( current_file_launch_handlers . size ( ) > 1 ) {
added_open_menu_items = true ;
auto & file_open_with_menu = menu - > add_submenu ( " Open with " ) ;
for ( auto & handler : current_file_launch_handlers ) {
if ( & handler = = default_file_handler . ptr ( ) )
continue ;
file_open_with_menu . add_action ( handler . create_launch_action ( [ & , full_path = move ( full_path ) ] ( auto & launcher_handler ) {
directory_view . launch ( URL : : create_with_file_protocol ( full_path ) , launcher_handler ) ;
} ) ) ;
}
}
return added_open_menu_items ;
}
2020-12-20 20:09:48 -03:00
int run_in_desktop_mode ( [[maybe_unused]] RefPtr < Core : : ConfigFile > config )
2020-04-18 17:04:41 -03:00
{
2020-08-10 15:29:08 -03:00
static constexpr const char * process_name = " FileManager (Desktop) " ;
set_process_name ( process_name , strlen ( process_name ) ) ;
pthread_setname_np ( pthread_self ( ) , process_name ) ;
2020-04-18 17:04:41 -03:00
auto window = GUI : : Window : : construct ( ) ;
window - > set_title ( " Desktop Manager " ) ;
window - > set_window_type ( GUI : : WindowType : : Desktop ) ;
window - > set_has_alpha_channel ( true ) ;
2020-09-17 09:34:47 -03:00
auto & desktop_widget = window - > set_main_widget < FileManager : : DesktopWidget > ( ) ;
2020-04-18 17:04:41 -03:00
desktop_widget . set_layout < GUI : : VerticalBoxLayout > ( ) ;
2020-12-20 20:09:48 -03:00
[[maybe_unused]] auto & directory_view = desktop_widget . add < DirectoryView > ( DirectoryView : : Mode : : Desktop ) ;
2020-04-18 17:04:41 -03:00
2020-12-10 04:07:01 -03:00
auto copy_action = GUI : : CommonActions : : make_copy_action (
[ & ] ( auto & ) {
auto paths = directory_view . selected_file_paths ( ) ;
if ( paths . is_empty ( ) )
2021-02-23 16:42:32 -03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-10 04:07:01 -03:00
2020-12-28 12:50:51 -03:00
do_copy ( paths , FileUtils : : FileOperation : : Copy ) ;
2020-12-10 04:07:01 -03:00
} ,
window ) ;
copy_action - > set_enabled ( false ) ;
2020-12-28 12:50:51 -03:00
auto cut_action = GUI : : CommonActions : : make_cut_action (
[ & ] ( auto & ) {
auto paths = directory_view . selected_file_paths ( ) ;
if ( paths . is_empty ( ) )
2021-02-23 16:42:32 -03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-28 12:50:51 -03:00
do_copy ( paths , FileUtils : : FileOperation : : Cut ) ;
} ,
window ) ;
cut_action - > set_enabled ( false ) ;
2021-04-25 10:36:27 -03:00
auto unzip_archive_action
= GUI : : Action : : create (
" E&xtract Here " ,
[ & ] ( const GUI : : Action & ) {
auto paths = directory_view . selected_file_paths ( ) ;
if ( paths . is_empty ( ) )
return ;
do_unzip_archive ( paths , directory_view . window ( ) ) ;
} ,
window ) ;
2020-12-10 04:07:01 -03:00
directory_view . on_selection_change = [ & ] ( const GUI : : AbstractView & view ) {
copy_action - > set_enabled ( ! view . selection ( ) . is_empty ( ) ) ;
2020-12-28 12:50:51 -03:00
cut_action - > set_enabled ( ! view . selection ( ) . is_empty ( ) ) ;
2020-12-10 04:07:01 -03:00
} ;
2021-04-04 17:39:41 -03:00
auto properties_action = GUI : : CommonActions : : make_properties_action (
[ & ] ( auto & ) {
String path = directory_view . path ( ) ;
Vector < String > selected = directory_view . selected_file_paths ( ) ;
2020-12-10 04:07:01 -03:00
2021-04-04 17:39:41 -03:00
show_properties ( path , path , selected , directory_view . window ( ) ) ;
} ,
window ) ;
2020-12-10 04:07:01 -03:00
auto paste_action = GUI : : CommonActions : : make_paste_action (
[ & ] ( const GUI : : Action & ) {
do_paste ( directory_view . path ( ) , directory_view . window ( ) ) ;
} ,
window ) ;
paste_action - > set_enabled ( GUI : : Clipboard : : the ( ) . mime_type ( ) = = " text/uri-list " & & access ( directory_view . path ( ) . characters ( ) , W_OK ) = = 0 ) ;
GUI : : Clipboard : : the ( ) . on_change = [ & ] ( const String & data_type ) {
paste_action - > set_enabled ( data_type = = " text/uri-list " & & access ( directory_view . path ( ) . characters ( ) , W_OK ) = = 0 ) ;
} ;
2020-04-22 15:27:35 -03:00
auto desktop_view_context_menu = GUI : : Menu : : construct ( " Directory View " ) ;
2021-04-09 11:44:08 -03:00
auto file_manager_action = GUI : : Action : : create ( " Show in &File Manager " , { } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/app-file-manager.png " ) , [ & ] ( const GUI : : Action & ) {
2020-08-17 14:59:11 -03:00
Desktop : : Launcher : : open ( URL : : create_with_file_protocol ( directory_view . path ( ) ) ) ;
2020-04-22 16:10:38 -03:00
} ) ;
2021-04-09 11:44:08 -03:00
auto display_properties_action = GUI : : Action : : create ( " &Display Settings " , { } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/app-display-settings.png " ) , [ & ] ( const GUI : : Action & ) {
2020-04-26 16:30:01 -03:00
Desktop : : Launcher : : open ( URL : : create_with_file_protocol ( " /bin/DisplaySettings " ) ) ;
2020-04-22 15:46:10 -03:00
} ) ;
2020-08-17 15:06:21 -03:00
desktop_view_context_menu - > add_action ( directory_view . mkdir_action ( ) ) ;
2020-08-17 15:10:19 -03:00
desktop_view_context_menu - > add_action ( directory_view . touch_action ( ) ) ;
2020-12-10 04:07:01 -03:00
desktop_view_context_menu - > add_action ( paste_action ) ;
2020-08-17 15:06:21 -03:00
desktop_view_context_menu - > add_separator ( ) ;
2020-04-22 16:10:38 -03:00
desktop_view_context_menu - > add_action ( file_manager_action ) ;
2020-09-13 09:58:23 -03:00
desktop_view_context_menu - > add_action ( directory_view . open_terminal_action ( ) ) ;
2020-04-22 16:10:38 -03:00
desktop_view_context_menu - > add_separator ( ) ;
2020-04-22 15:46:10 -03:00
desktop_view_context_menu - > add_action ( display_properties_action ) ;
2020-04-22 15:27:35 -03:00
2020-12-10 04:07:01 -03:00
auto desktop_context_menu = GUI : : Menu : : construct ( " Directory View Directory " ) ;
desktop_context_menu - > add_action ( copy_action ) ;
2020-12-28 12:50:51 -03:00
desktop_context_menu - > add_action ( cut_action ) ;
2020-12-10 04:07:01 -03:00
desktop_context_menu - > add_action ( paste_action ) ;
desktop_context_menu - > add_action ( directory_view . delete_action ( ) ) ;
desktop_context_menu - > add_separator ( ) ;
desktop_context_menu - > add_action ( properties_action ) ;
2021-03-03 08:00:32 -03:00
RefPtr < GUI : : Menu > file_context_menu ;
NonnullRefPtrVector < LauncherHandler > current_file_handlers ;
RefPtr < GUI : : Action > file_context_menu_action_default_action ;
2020-08-17 14:52:01 -03:00
directory_view . on_context_menu_request = [ & ] ( const GUI : : ModelIndex & index , const GUI : : ContextMenuEvent & event ) {
2021-03-03 08:00:32 -03:00
if ( index . is_valid ( ) ) {
auto & node = directory_view . node ( index ) ;
if ( node . is_directory ( ) ) {
desktop_context_menu - > popup ( event . screen_position ( ) ) ;
} else {
file_context_menu = GUI : : Menu : : construct ( " Directory View File " ) ;
file_context_menu - > add_action ( copy_action ) ;
file_context_menu - > add_action ( cut_action ) ;
file_context_menu - > add_action ( paste_action ) ;
file_context_menu - > add_action ( directory_view . delete_action ( ) ) ;
file_context_menu - > add_separator ( ) ;
2021-04-25 10:36:27 -03:00
if ( node . full_path ( ) . ends_with ( " .zip " , AK : : CaseSensitivity : : CaseInsensitive ) ) {
file_context_menu - > add_action ( unzip_archive_action ) ;
file_context_menu - > add_separator ( ) ;
}
2021-03-03 08:00:32 -03:00
bool added_open_menu_items = add_launch_handler_actions_to_menu ( file_context_menu , directory_view , node . full_path ( ) , file_context_menu_action_default_action , current_file_handlers ) ;
if ( added_open_menu_items )
file_context_menu - > add_separator ( ) ;
file_context_menu - > add_action ( properties_action ) ;
2021-04-06 12:21:57 -03:00
file_context_menu - > popup ( event . screen_position ( ) , file_context_menu_action_default_action ) ;
2021-03-03 08:00:32 -03:00
}
} else {
2020-04-22 15:27:35 -03:00
desktop_view_context_menu - > popup ( event . screen_position ( ) ) ;
2021-03-03 08:00:32 -03:00
}
2020-04-22 15:27:35 -03:00
} ;
2020-08-14 17:17:46 -03:00
auto wm_config = Core : : ConfigFile : : get_for_app ( " WindowManager " ) ;
auto selected_wallpaper = wm_config - > read_entry ( " Background " , " Wallpaper " , " " ) ;
if ( ! selected_wallpaper . is_empty ( ) ) {
GUI : : Desktop : : the ( ) . set_wallpaper ( selected_wallpaper , false ) ;
}
2020-04-18 17:04:41 -03:00
window - > show ( ) ;
2020-07-04 11:52:01 -03:00
return GUI : : Application : : the ( ) - > exec ( ) ;
2020-04-18 17:04:41 -03:00
}
2021-02-28 15:54:03 -03:00
int run_in_windowed_mode ( RefPtr < Core : : ConfigFile > config , String initial_location , String entry_focused_on_init )
2020-04-18 17:04:41 -03:00
{
2020-02-02 11:07:41 -03:00
auto window = GUI : : Window : : construct ( ) ;
2019-05-27 08:52:28 -03:00
window - > set_title ( " File Manager " ) ;
2019-11-20 17:52:15 -03:00
2019-11-09 06:29:03 -03:00
auto left = config - > read_num_entry ( " Window " , " Left " , 150 ) ;
auto top = config - > read_num_entry ( " Window " , " Top " , 75 ) ;
auto width = config - > read_num_entry ( " Window " , " Width " , 640 ) ;
2020-10-02 18:14:37 -03:00
auto height = config - > read_num_entry ( " Window " , " Height " , 480 ) ;
window - > set_rect ( { left , top , width , height } ) ;
2019-11-20 17:52:15 -03:00
2020-03-03 17:42:48 -03:00
auto & widget = window - > set_main_widget < GUI : : Widget > ( ) ;
2019-03-02 05:16:57 -03:00
2020-12-20 08:17:59 -03:00
widget . load_from_gml ( file_manager_window_gml ) ;
2020-04-23 12:44:49 -03:00
2021-04-13 11:18:20 -03:00
auto & toolbar_container = * widget . find_descendant_of_type_named < GUI : : ToolbarContainer > ( " toolbar_container " ) ;
auto & main_toolbar = * widget . find_descendant_of_type_named < GUI : : Toolbar > ( " main_toolbar " ) ;
auto & location_toolbar = * widget . find_descendant_of_type_named < GUI : : Toolbar > ( " location_toolbar " ) ;
2020-03-04 15:07:55 -03:00
location_toolbar . layout ( ) - > set_margins ( { 6 , 3 , 6 , 3 } ) ;
2019-03-20 18:01:02 -03:00
2021-01-01 04:57:48 -03:00
auto & location_textbox = * widget . find_descendant_of_type_named < GUI : : TextBox > ( " location_textbox " ) ;
2019-03-02 20:34:40 -03:00
2021-04-13 11:18:20 -03:00
auto & breadcrumb_toolbar = * widget . find_descendant_of_type_named < GUI : : Toolbar > ( " breadcrumb_toolbar " ) ;
2021-01-15 15:37:27 -03:00
breadcrumb_toolbar . layout ( ) - > set_margins ( { 6 , 0 , 6 , 0 } ) ;
2021-04-13 11:18:20 -03:00
auto & breadcrumbbar = * widget . find_descendant_of_type_named < GUI : : Breadcrumbbar > ( " breadcrumbbar " ) ;
2020-12-14 16:14:50 -03:00
2021-01-01 04:57:48 -03:00
auto & splitter = * widget . find_descendant_of_type_named < GUI : : HorizontalSplitter > ( " splitter " ) ;
auto & tree_view = * widget . find_descendant_of_type_named < GUI : : TreeView > ( " tree_view " ) ;
2020-12-20 08:17:59 -03:00
2020-09-16 14:56:58 -03:00
auto directories_model = GUI : : FileSystemModel : : create ( { } , GUI : : FileSystemModel : : Mode : : DirectoriesOnly ) ;
2020-03-04 15:07:55 -03:00
tree_view . set_model ( directories_model ) ;
2021-04-05 06:57:47 -03:00
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : Icon , false ) ;
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : Size , false ) ;
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : Owner , false ) ;
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : Group , false ) ;
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : Permissions , false ) ;
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : ModificationTime , false ) ;
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : Inode , false ) ;
tree_view . set_column_visible ( GUI : : FileSystemModel : : Column : : SymlinkTarget , false ) ;
2020-09-19 09:09:59 -03:00
bool is_reacting_to_tree_view_selection_change = false ;
2020-08-17 14:52:01 -03:00
auto & directory_view = splitter . add < DirectoryView > ( DirectoryView : : Mode : : Normal ) ;
2020-03-04 15:07:55 -03:00
2020-12-14 16:14:50 -03:00
location_textbox . on_escape_pressed = [ & ] {
directory_view . set_focus ( true ) ;
} ;
2020-09-16 14:56:58 -03:00
// Open the root directory. FIXME: This is awkward.
tree_view . toggle_index ( directories_model - > index ( 0 , 0 , { } ) ) ;
2021-04-13 11:18:20 -03:00
auto & statusbar = * widget . find_descendant_of_type_named < GUI : : Statusbar > ( " statusbar " ) ;
2020-03-04 15:07:55 -03:00
2021-04-18 11:43:45 -03:00
GUI : : Application : : the ( ) - > on_action_enter = [ & statusbar ] ( GUI : : Action & action ) {
auto text = action . status_tip ( ) ;
if ( text . is_empty ( ) )
text = Gfx : : parse_ampersand_string ( action . text ( ) ) ;
statusbar . set_override_text ( move ( text ) ) ;
} ;
GUI : : Application : : the ( ) - > on_action_leave = [ & statusbar ] ( GUI : : Action & ) {
statusbar . set_override_text ( { } ) ;
} ;
2021-04-13 11:18:20 -03:00
auto & progressbar = * widget . find_descendant_of_type_named < GUI : : Progressbar > ( " progressbar " ) ;
progressbar . set_format ( GUI : : Progressbar : : Format : : ValueSlashMax ) ;
2020-03-04 15:07:55 -03:00
progressbar . set_frame_shape ( Gfx : : FrameShape : : Panel ) ;
progressbar . set_frame_shadow ( Gfx : : FrameShadow : : Sunken ) ;
progressbar . set_frame_thickness ( 1 ) ;
location_textbox . on_return_pressed = [ & ] {
directory_view . open ( location_textbox . text ( ) ) ;
2019-03-02 20:34:40 -03:00
} ;
2019-12-02 21:54:29 -03:00
auto refresh_tree_view = [ & ] {
2020-01-10 12:58:00 -03:00
directories_model - > update ( ) ;
2019-12-02 21:54:29 -03:00
2020-03-04 15:07:55 -03:00
auto current_path = directory_view . path ( ) ;
2019-12-02 21:54:29 -03:00
2019-12-12 06:49:17 -03:00
struct stat st ;
// If the directory no longer exists, we find a parent that does.
2020-01-27 18:11:26 -03:00
while ( stat ( current_path . characters ( ) , & st ) ! = 0 ) {
2020-03-04 15:07:55 -03:00
directory_view . open_parent_directory ( ) ;
current_path = directory_view . path ( ) ;
2020-01-10 12:58:00 -03:00
if ( current_path = = directories_model - > root_path ( ) ) {
2019-12-12 06:49:17 -03:00
break ;
}
}
2020-01-10 12:58:00 -03:00
// Reselect the existing folder in the tree.
2020-02-02 11:07:41 -03:00
auto new_index = directories_model - > index ( current_path , GUI : : FileSystemModel : : Column : : Name ) ;
2020-12-08 13:51:53 -03:00
if ( new_index . is_valid ( ) ) {
tree_view . expand_all_parents_of ( new_index ) ;
tree_view . set_cursor ( new_index , GUI : : AbstractView : : SelectionUpdate : : Set , true ) ;
}
2019-12-02 21:54:29 -03:00
2020-03-04 15:07:55 -03:00
directory_view . refresh ( ) ;
2019-12-02 21:54:29 -03:00
} ;
2020-02-02 11:07:41 -03:00
auto directory_context_menu = GUI : : Menu : : construct ( " Directory View Directory " ) ;
auto directory_view_context_menu = GUI : : Menu : : construct ( " Directory View " ) ;
auto tree_view_directory_context_menu = GUI : : Menu : : construct ( " Tree View Directory " ) ;
auto tree_view_context_menu = GUI : : Menu : : construct ( " Tree View " ) ;
2019-12-12 06:49:17 -03:00
2021-04-09 11:44:08 -03:00
auto open_parent_directory_action = GUI : : Action : : create ( " Open &Parent Directory " , { Mod_Alt , Key_Up } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/open-parent-directory.png " ) , [ & ] ( const GUI : : Action & ) {
2020-03-04 15:07:55 -03:00
directory_view . open_parent_directory ( ) ;
2019-03-01 22:20:11 -03:00
} ) ;
2021-02-12 19:39:57 -03:00
RefPtr < GUI : : Action > layout_toolbar_action ;
RefPtr < GUI : : Action > layout_location_action ;
RefPtr < GUI : : Action > layout_statusbar_action ;
RefPtr < GUI : : Action > layout_folderpane_action ;
auto show_toolbar = config - > read_bool_entry ( " Layout " , " ShowToolbar " , true ) ;
2021-04-09 11:44:08 -03:00
layout_toolbar_action = GUI : : Action : : create_checkable ( " &Toolbar " , [ & ] ( auto & action ) {
2021-02-12 19:39:57 -03:00
if ( action . is_checked ( ) ) {
main_toolbar . set_visible ( true ) ;
toolbar_container . set_visible ( true ) ;
} else {
main_toolbar . set_visible ( false ) ;
if ( ! location_toolbar . is_visible ( ) & & ! breadcrumb_toolbar . is_visible ( ) )
toolbar_container . set_visible ( false ) ;
}
show_toolbar = action . is_checked ( ) ;
config - > write_bool_entry ( " Layout " , " ShowToolbar " , action . is_checked ( ) ) ;
config - > sync ( ) ;
} ) ;
layout_toolbar_action - > set_checked ( show_toolbar ) ;
main_toolbar . set_visible ( show_toolbar ) ;
auto show_location = config - > read_bool_entry ( " Layout " , " ShowLocationBar " , true ) ;
2021-04-09 11:44:08 -03:00
layout_location_action = GUI : : Action : : create_checkable ( " &Location Bar " , [ & ] ( auto & action ) {
2021-02-12 19:39:57 -03:00
if ( action . is_checked ( ) ) {
breadcrumb_toolbar . set_visible ( true ) ;
location_toolbar . set_visible ( false ) ;
toolbar_container . set_visible ( true ) ;
} else {
breadcrumb_toolbar . set_visible ( false ) ;
location_toolbar . set_visible ( false ) ;
if ( ! main_toolbar . is_visible ( ) )
toolbar_container . set_visible ( false ) ;
}
show_location = action . is_checked ( ) ;
config - > write_bool_entry ( " Layout " , " ShowLocationBar " , action . is_checked ( ) ) ;
config - > sync ( ) ;
} ) ;
layout_location_action - > set_checked ( show_location ) ;
breadcrumb_toolbar . set_visible ( show_location ) ;
toolbar_container . set_visible ( show_location | show_toolbar ) ;
2021-04-09 11:44:08 -03:00
layout_statusbar_action = GUI : : Action : : create_checkable ( " &Status Bar " , [ & ] ( auto & action ) {
2021-02-12 19:39:57 -03:00
action . is_checked ( ) ? statusbar . set_visible ( true ) : statusbar . set_visible ( false ) ;
2021-04-13 11:18:20 -03:00
config - > write_bool_entry ( " Layout " , " ShowStatusbar " , action . is_checked ( ) ) ;
2021-02-12 19:39:57 -03:00
config - > sync ( ) ;
} ) ;
2021-04-13 11:18:20 -03:00
auto show_statusbar = config - > read_bool_entry ( " Layout " , " ShowStatusbar " , true ) ;
2021-02-12 19:39:57 -03:00
layout_statusbar_action - > set_checked ( show_statusbar ) ;
statusbar . set_visible ( show_statusbar ) ;
2021-04-09 11:44:08 -03:00
layout_folderpane_action = GUI : : Action : : create_checkable ( " &Folder Pane " , { Mod_Ctrl , Key_P } , [ & ] ( auto & action ) {
2021-02-12 19:39:57 -03:00
action . is_checked ( ) ? tree_view . set_visible ( true ) : tree_view . set_visible ( false ) ;
config - > write_bool_entry ( " Layout " , " ShowFolderPane " , action . is_checked ( ) ) ;
config - > sync ( ) ;
} ) ;
auto show_folderpane = config - > read_bool_entry ( " Layout " , " ShowFolderPane " , true ) ;
layout_folderpane_action - > set_checked ( show_folderpane ) ;
tree_view . set_visible ( show_folderpane ) ;
location_textbox . on_focusout = [ & ] {
if ( show_location )
breadcrumb_toolbar . set_visible ( true ) ;
if ( ! ( show_location | show_toolbar ) )
toolbar_container . set_visible ( false ) ;
location_toolbar . set_visible ( false ) ;
} ;
2020-02-02 11:07:41 -03:00
RefPtr < GUI : : Action > view_as_table_action ;
RefPtr < GUI : : Action > view_as_icons_action ;
RefPtr < GUI : : Action > view_as_columns_action ;
2019-04-26 16:09:56 -03:00
2020-07-15 12:35:15 -03:00
view_as_icons_action = GUI : : Action : : create_checkable (
2021-04-09 11:44:08 -03:00
" View as &Icons " , { Mod_Ctrl , KeyCode : : Key_1 } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/icon-view.png " ) , [ & ] ( const GUI : : Action & ) {
2020-07-15 12:35:15 -03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Icon ) ;
config - > write_entry ( " DirectoryView " , " ViewMode " , " Icon " ) ;
2020-02-13 17:54:27 -03:00
config - > sync ( ) ;
} ,
window ) ;
2019-03-22 23:53:51 -03:00
2020-07-15 12:35:15 -03:00
view_as_table_action = GUI : : Action : : create_checkable (
2021-04-09 11:44:08 -03:00
" View as &Table " , { Mod_Ctrl , KeyCode : : Key_2 } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/table-view.png " ) , [ & ] ( const GUI : : Action & ) {
2020-07-15 12:35:15 -03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Table ) ;
config - > write_entry ( " DirectoryView " , " ViewMode " , " Table " ) ;
2020-02-13 17:54:27 -03:00
config - > sync ( ) ;
} ,
window ) ;
2019-07-09 17:10:03 -03:00
2020-04-21 12:19:27 -03:00
view_as_columns_action = GUI : : Action : : create_checkable (
2021-04-09 11:44:08 -03:00
" View as &Columns " , { Mod_Ctrl , KeyCode : : Key_3 } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/columns-view.png " ) , [ & ] ( const GUI : : Action & ) {
2020-03-04 15:07:55 -03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Columns ) ;
2020-02-13 17:54:27 -03:00
config - > write_entry ( " DirectoryView " , " ViewMode " , " Columns " ) ;
config - > sync ( ) ;
} ,
window ) ;
2020-01-10 13:17:14 -03:00
2020-02-02 11:07:41 -03:00
auto view_type_action_group = make < GUI : : ActionGroup > ( ) ;
2019-07-09 17:10:03 -03:00
view_type_action_group - > set_exclusive ( true ) ;
view_type_action_group - > add_action ( * view_as_icons_action ) ;
2020-07-15 12:35:15 -03:00
view_type_action_group - > add_action ( * view_as_table_action ) ;
2020-01-10 13:17:14 -03:00
view_type_action_group - > add_action ( * view_as_columns_action ) ;
2019-11-20 17:52:15 -03:00
2019-12-12 06:49:17 -03:00
auto tree_view_selected_file_paths = [ & ] {
Vector < String > paths ;
auto & view = tree_view ;
2020-03-04 15:07:55 -03:00
view . selection ( ) . for_each_index ( [ & ] ( const GUI : : ModelIndex & index ) {
2020-01-10 12:58:00 -03:00
paths . append ( directories_model - > full_path ( index ) ) ;
2019-12-12 06:49:17 -03:00
} ) ;
return paths ;
} ;
2021-04-09 11:44:08 -03:00
auto select_all_action = GUI : : CommonActions : : make_select_all_action ( [ & ] ( auto & ) {
2020-03-04 15:07:55 -03:00
directory_view . current_view ( ) . select_all ( ) ;
2020-01-07 06:29:21 -03:00
} ) ;
2020-02-13 17:54:27 -03:00
auto copy_action = GUI : : CommonActions : : make_copy_action (
2020-08-17 14:52:01 -03:00
[ & ] ( auto & ) {
auto paths = directory_view . selected_file_paths ( ) ;
2020-04-26 19:03:17 -03:00
2020-12-10 04:07:01 -03:00
if ( paths . is_empty ( ) )
2020-02-13 17:54:27 -03:00
paths = tree_view_selected_file_paths ( ) ;
2020-04-26 19:03:17 -03:00
2020-02-13 17:54:27 -03:00
if ( paths . is_empty ( ) )
2021-02-23 16:42:32 -03:00
VERIFY_NOT_REACHED ( ) ;
2020-04-26 19:03:17 -03:00
2020-12-28 12:50:51 -03:00
do_copy ( paths , FileUtils : : FileOperation : : Copy ) ;
2020-12-10 04:07:01 -03:00
refresh_tree_view ( ) ;
2020-02-13 17:54:27 -03:00
} ,
window ) ;
2019-09-13 17:09:01 -03:00
copy_action - > set_enabled ( false ) ;
2019-09-10 10:21:58 -03:00
2020-12-28 12:50:51 -03:00
auto cut_action = GUI : : CommonActions : : make_cut_action (
[ & ] ( auto & ) {
auto paths = directory_view . selected_file_paths ( ) ;
if ( paths . is_empty ( ) )
paths = tree_view_selected_file_paths ( ) ;
if ( paths . is_empty ( ) )
2021-02-23 16:42:32 -03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-28 12:50:51 -03:00
do_copy ( paths , FileUtils : : FileOperation : : Cut ) ;
refresh_tree_view ( ) ;
} ,
window ) ;
cut_action - > set_enabled ( false ) ;
2020-12-22 12:57:59 -03:00
auto shortcut_action
= GUI : : Action : : create (
2021-04-09 11:44:08 -03:00
" Create Desktop &Shortcut " ,
2020-12-22 12:57:59 -03:00
{ } ,
Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/filetype-symlink.png " ) ,
[ & ] ( const GUI : : Action & ) {
auto paths = directory_view . selected_file_paths ( ) ;
if ( paths . is_empty ( ) ) {
return ;
}
do_create_link ( paths , directory_view . window ( ) ) ;
} ,
window ) ;
2021-04-25 10:36:27 -03:00
auto unzip_archive_action
= GUI : : Action : : create (
" E&xtract Here " ,
[ & ] ( const GUI : : Action & ) {
auto paths = directory_view . selected_file_paths ( ) ;
if ( paths . is_empty ( ) )
return ;
do_unzip_archive ( paths , directory_view . window ( ) ) ;
refresh_tree_view ( ) ;
} ,
window ) ;
2021-04-04 17:39:41 -03:00
auto properties_action = GUI : : CommonActions : : make_properties_action (
[ & ] ( auto & action ) {
String container_dir_path ;
String path ;
Vector < String > selected ;
if ( action . activator ( ) = = directory_context_menu | | directory_view . active_widget ( ) - > is_focused ( ) ) {
path = directory_view . path ( ) ;
container_dir_path = path ;
selected = directory_view . selected_file_paths ( ) ;
} else {
path = directories_model - > full_path ( tree_view . selection ( ) . first ( ) ) ;
container_dir_path = LexicalPath ( path ) . basename ( ) ;
selected = tree_view_selected_file_paths ( ) ;
}
2020-02-13 17:54:27 -03:00
2021-04-04 17:39:41 -03:00
show_properties ( container_dir_path , path , selected , directory_view . window ( ) ) ;
} ,
window ) ;
2019-11-20 17:52:15 -03:00
2020-04-27 13:06:42 -03:00
auto paste_action = GUI : : CommonActions : : make_paste_action (
[ & ] ( const GUI : : Action & action ) {
2020-12-10 04:07:01 -03:00
String target_directory ;
if ( action . activator ( ) = = directory_context_menu )
target_directory = directory_view . selected_file_paths ( ) [ 0 ] ;
else
target_directory = directory_view . path ( ) ;
do_paste ( target_directory , directory_view . window ( ) ) ;
refresh_tree_view ( ) ;
2020-04-27 13:06:42 -03:00
} ,
window ) ;
auto folder_specific_paste_action = GUI : : CommonActions : : make_paste_action (
[ & ] ( const GUI : : Action & action ) {
2020-12-10 04:07:01 -03:00
String target_directory ;
if ( action . activator ( ) = = directory_context_menu )
target_directory = directory_view . selected_file_paths ( ) [ 0 ] ;
else
target_directory = directory_view . path ( ) ;
do_paste ( target_directory , directory_view . window ( ) ) ;
refresh_tree_view ( ) ;
2020-04-27 13:06:42 -03:00
} ,
window ) ;
2020-02-13 17:54:27 -03:00
auto go_back_action = GUI : : CommonActions : : make_go_back_action (
[ & ] ( auto & ) {
2020-03-04 15:07:55 -03:00
directory_view . open_previous_directory ( ) ;
2020-02-13 17:54:27 -03:00
} ,
window ) ;
auto go_forward_action = GUI : : CommonActions : : make_go_forward_action (
[ & ] ( auto & ) {
2020-03-04 15:07:55 -03:00
directory_view . open_next_directory ( ) ;
2020-02-13 17:54:27 -03:00
} ,
window ) ;
auto go_home_action = GUI : : CommonActions : : make_go_home_action (
[ & ] ( auto & ) {
2020-04-19 14:57:05 -03:00
directory_view . open ( Core : : StandardPaths : : home_directory ( ) ) ;
2020-02-13 17:54:27 -03:00
} ,
window ) ;
2019-07-21 04:19:09 -03:00
2020-05-14 17:51:15 -03:00
GUI : : Clipboard : : the ( ) . on_change = [ & ] ( const String & data_type ) {
2020-04-27 13:06:42 -03:00
auto current_location = directory_view . path ( ) ;
2020-05-15 16:35:03 -03:00
paste_action - > set_enabled ( data_type = = " text/uri-list " & & access ( current_location . characters ( ) , W_OK ) = = 0 ) ;
2020-04-27 13:06:42 -03:00
} ;
2020-09-13 16:38:44 -03:00
auto tree_view_delete_action = GUI : : CommonActions : : make_delete_action (
[ & ] ( auto & ) {
FileUtils : : delete_paths ( tree_view_selected_file_paths ( ) , true , window ) ;
2020-12-08 13:51:53 -03:00
refresh_tree_view ( ) ;
2020-09-13 16:38:44 -03:00
} ,
& tree_view ) ;
// This is a little awkward. The menu action does something different depending on which view has focus.
// It would be nice to find a good abstraction for this instead of creating a branching action like this.
auto focus_dependent_delete_action = GUI : : CommonActions : : make_delete_action ( [ & ] ( auto & ) {
if ( tree_view . is_focused ( ) )
tree_view_delete_action - > activate ( ) ;
else
directory_view . delete_action ( ) . activate ( ) ;
2020-12-08 13:51:53 -03:00
refresh_tree_view ( ) ;
} ) ;
2020-12-10 01:18:29 -03:00
focus_dependent_delete_action - > set_enabled ( false ) ;
2020-12-08 13:51:53 -03:00
2021-04-09 11:44:08 -03:00
auto mkdir_action = GUI : : Action : : create ( " New &Directory... " , { Mod_Ctrl | Mod_Shift , Key_N } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/mkdir.png " ) , [ & ] ( const GUI : : Action & ) {
2020-12-08 13:51:53 -03:00
directory_view . mkdir_action ( ) . activate ( ) ;
refresh_tree_view ( ) ;
} ) ;
2021-04-09 11:44:08 -03:00
auto touch_action = GUI : : Action : : create ( " New &File... " , { Mod_Ctrl | Mod_Shift , Key_F } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/new.png " ) , [ & ] ( const GUI : : Action & ) {
2020-12-08 13:51:53 -03:00
directory_view . touch_action ( ) . activate ( ) ;
refresh_tree_view ( ) ;
2020-09-13 16:38:44 -03:00
} ) ;
2021-04-13 11:18:20 -03:00
auto menubar = GUI : : Menubar : : construct ( ) ;
2019-02-14 05:52:12 -02:00
2021-05-01 05:45:39 -03:00
auto & file_menu = menubar - > add_menu ( " &File " ) ;
file_menu . add_action ( mkdir_action ) ;
file_menu . add_action ( touch_action ) ;
file_menu . add_action ( copy_action ) ;
file_menu . add_action ( cut_action ) ;
file_menu . add_action ( paste_action ) ;
file_menu . add_action ( focus_dependent_delete_action ) ;
file_menu . add_action ( directory_view . open_terminal_action ( ) ) ;
file_menu . add_separator ( ) ;
file_menu . add_action ( properties_action ) ;
file_menu . add_separator ( ) ;
file_menu . add_action ( GUI : : CommonActions : : make_quit_action ( [ ] ( auto & ) {
2020-07-04 11:52:01 -03:00
GUI : : Application : : the ( ) - > quit ( ) ;
2019-02-14 05:52:12 -02:00
} ) ) ;
2020-04-04 07:18:40 -03:00
2021-04-09 11:44:08 -03:00
auto action_show_dotfiles = GUI : : Action : : create_checkable ( " Show &Dotfiles " , { Mod_Ctrl , Key_H } , [ & ] ( auto & action ) {
2020-10-08 17:34:48 -03:00
directory_view . set_should_show_dotfiles ( action . is_checked ( ) ) ;
2020-12-08 13:51:53 -03:00
refresh_tree_view ( ) ;
2021-02-12 19:37:07 -03:00
config - > write_bool_entry ( " DirectoryView " , " ShowDotFiles " , action . is_checked ( ) ) ;
config - > sync ( ) ;
2020-10-08 17:34:48 -03:00
} ) ;
2021-02-12 19:37:07 -03:00
auto show_dotfiles = config - > read_bool_entry ( " DirectoryView " , " ShowDotFiles " , false ) ;
directory_view . set_should_show_dotfiles ( show_dotfiles ) ;
action_show_dotfiles - > set_checked ( show_dotfiles ) ;
2021-04-05 18:12:53 -03:00
auto & view_menu = menubar - > add_menu ( " &View " ) ;
2021-04-09 11:44:08 -03:00
auto & layout_menu = view_menu . add_submenu ( " &Layout " ) ;
2021-02-12 19:39:57 -03:00
layout_menu . add_action ( * layout_toolbar_action ) ;
layout_menu . add_action ( * layout_location_action ) ;
layout_menu . add_action ( * layout_statusbar_action ) ;
layout_menu . add_action ( * layout_folderpane_action ) ;
view_menu . add_separator ( ) ;
2020-04-04 07:18:40 -03:00
view_menu . add_action ( * view_as_icons_action ) ;
view_menu . add_action ( * view_as_table_action ) ;
view_menu . add_action ( * view_as_columns_action ) ;
2020-07-18 13:46:37 -03:00
view_menu . add_separator ( ) ;
2020-10-08 17:34:48 -03:00
view_menu . add_action ( action_show_dotfiles ) ;
2020-04-04 07:18:40 -03:00
2021-04-09 11:44:08 -03:00
auto go_to_location_action = GUI : : Action : : create ( " Go to &Location... " , { Mod_Ctrl , Key_L } , [ & ] ( auto & ) {
2021-02-12 19:39:57 -03:00
toolbar_container . set_visible ( true ) ;
2021-01-09 00:08:40 -03:00
location_toolbar . set_visible ( true ) ;
breadcrumb_toolbar . set_visible ( false ) ;
location_textbox . select_all ( ) ;
location_textbox . set_focus ( true ) ;
} ) ;
2021-04-05 18:12:53 -03:00
auto & go_menu = menubar - > add_menu ( " &Go " ) ;
2020-04-04 07:18:40 -03:00
go_menu . add_action ( go_back_action ) ;
go_menu . add_action ( go_forward_action ) ;
go_menu . add_action ( open_parent_directory_action ) ;
go_menu . add_action ( go_home_action ) ;
2021-01-09 00:08:40 -03:00
go_menu . add_action ( go_to_location_action ) ;
2020-04-04 07:18:40 -03:00
2021-04-05 18:12:53 -03:00
auto & help_menu = menubar - > add_menu ( " &Help " ) ;
2021-02-24 18:22:15 -03:00
help_menu . add_action ( GUI : : CommonActions : : make_about_action ( " File Manager " , GUI : : Icon : : default_icon ( " app-file-manager " ) , window ) ) ;
2019-02-14 05:52:12 -02:00
2021-03-25 17:41:39 -03:00
window - > set_menubar ( menubar ) ;
2019-02-14 05:52:12 -02:00
2020-03-04 15:07:55 -03:00
main_toolbar . add_action ( go_back_action ) ;
main_toolbar . add_action ( go_forward_action ) ;
main_toolbar . add_action ( open_parent_directory_action ) ;
main_toolbar . add_action ( go_home_action ) ;
2019-03-27 23:38:23 -03:00
2020-03-04 15:07:55 -03:00
main_toolbar . add_separator ( ) ;
2020-12-08 13:51:53 -03:00
main_toolbar . add_action ( mkdir_action ) ;
main_toolbar . add_action ( touch_action ) ;
2020-03-04 15:07:55 -03:00
main_toolbar . add_action ( copy_action ) ;
2020-12-28 12:50:51 -03:00
main_toolbar . add_action ( cut_action ) ;
2020-03-04 15:07:55 -03:00
main_toolbar . add_action ( paste_action ) ;
2020-09-13 16:38:44 -03:00
main_toolbar . add_action ( focus_dependent_delete_action ) ;
2020-09-13 09:58:23 -03:00
main_toolbar . add_action ( directory_view . open_terminal_action ( ) ) ;
2019-02-19 22:39:46 -03:00
2020-03-04 15:07:55 -03:00
main_toolbar . add_separator ( ) ;
main_toolbar . add_action ( * view_as_icons_action ) ;
main_toolbar . add_action ( * view_as_table_action ) ;
main_toolbar . add_action ( * view_as_columns_action ) ;
2019-03-24 21:29:45 -03:00
2021-03-07 12:04:59 -03:00
directory_view . on_path_change = [ & ] ( const String & new_path , bool can_read_in_path , bool can_write_in_path ) {
2020-09-16 15:57:41 -03:00
auto icon = GUI : : FileIconProvider : : icon_for_path ( new_path ) ;
auto * bitmap = icon . bitmap_for_size ( 16 ) ;
window - > set_icon ( bitmap ) ;
location_textbox . set_icon ( bitmap ) ;
2020-07-19 16:37:25 -03:00
2020-10-05 09:59:50 -03:00
window - > set_title ( String : : formatted ( " {} - File Manager " , new_path ) ) ;
2020-03-04 15:07:55 -03:00
location_textbox . set_text ( new_path ) ;
2020-09-19 09:09:59 -03:00
2020-12-14 16:14:50 -03:00
{
LexicalPath lexical_path ( new_path ) ;
2021-04-13 11:18:20 -03:00
auto segment_index_of_new_path_in_breadcrumbbar = [ & ] ( ) - > Optional < size_t > {
for ( size_t i = 0 ; i < breadcrumbbar . segment_count ( ) ; + + i ) {
if ( breadcrumbbar . segment_data ( i ) = = new_path )
2020-12-14 16:14:50 -03:00
return i ;
}
return { } ;
} ( ) ;
2021-04-13 11:18:20 -03:00
if ( segment_index_of_new_path_in_breadcrumbbar . has_value ( ) ) {
breadcrumbbar . set_selected_segment ( segment_index_of_new_path_in_breadcrumbbar . value ( ) ) ;
2020-12-14 16:14:50 -03:00
} else {
2021-04-13 11:18:20 -03:00
breadcrumbbar . clear_segments ( ) ;
2020-12-14 16:14:50 -03:00
2021-04-13 11:18:20 -03:00
breadcrumbbar . append_segment ( " / " , GUI : : FileIconProvider : : icon_for_path ( " / " ) . bitmap_for_size ( 16 ) , " / " , " / " ) ;
2020-12-14 16:14:50 -03:00
StringBuilder builder ;
for ( auto & part : lexical_path . parts ( ) ) {
// NOTE: We rebuild the path as we go, so we have something to pass to GUI::FileIconProvider.
builder . append ( ' / ' ) ;
builder . append ( part ) ;
2021-04-13 11:18:20 -03:00
breadcrumbbar . append_segment ( part , GUI : : FileIconProvider : : icon_for_path ( builder . string_view ( ) ) . bitmap_for_size ( 16 ) , builder . string_view ( ) , builder . string_view ( ) ) ;
2020-12-14 16:14:50 -03:00
}
2021-04-13 11:18:20 -03:00
breadcrumbbar . set_selected_segment ( breadcrumbbar . segment_count ( ) - 1 ) ;
2020-12-14 16:14:50 -03:00
2021-04-13 11:18:20 -03:00
breadcrumbbar . on_segment_click = [ & ] ( size_t segment_index ) {
directory_view . open ( breadcrumbbar . segment_data ( segment_index ) ) ;
2020-12-14 16:14:50 -03:00
} ;
}
}
2020-09-19 09:09:59 -03:00
if ( ! is_reacting_to_tree_view_selection_change ) {
auto new_index = directories_model - > index ( new_path , GUI : : FileSystemModel : : Column : : Name ) ;
if ( new_index . is_valid ( ) ) {
tree_view . expand_all_parents_of ( new_index ) ;
tree_view . set_cursor ( new_index , GUI : : AbstractView : : SelectionUpdate : : Set ) ;
}
2019-12-12 06:49:17 -03:00
}
2019-05-23 18:15:57 -03:00
2020-04-26 10:56:07 -03:00
struct stat st ;
if ( lstat ( new_path . characters ( ) , & st ) ) {
perror ( " stat " ) ;
return ;
}
2020-09-05 11:16:01 -03:00
paste_action - > set_enabled ( can_write_in_path & & GUI : : Clipboard : : the ( ) . mime_type ( ) = = " text/uri-list " ) ;
2020-04-26 10:56:07 -03:00
go_forward_action - > set_enabled ( directory_view . path_history_position ( ) < directory_view . path_history_size ( ) - 1 ) ;
2020-03-04 15:07:55 -03:00
go_back_action - > set_enabled ( directory_view . path_history_position ( ) > 0 ) ;
2020-04-26 10:23:33 -03:00
open_parent_directory_action - > set_enabled ( new_path ! = " / " ) ;
2021-03-07 12:04:59 -03:00
view_as_table_action - > set_enabled ( can_read_in_path ) ;
view_as_icons_action - > set_enabled ( can_read_in_path ) ;
view_as_columns_action - > set_enabled ( can_read_in_path ) ;
2019-02-09 06:22:04 -02:00
} ;
2021-03-07 12:04:59 -03:00
directory_view . on_accepted_drop = [ & ] {
2020-12-08 13:51:53 -03:00
refresh_tree_view ( ) ;
} ;
2020-03-04 15:07:55 -03:00
directory_view . on_status_message = [ & ] ( const StringView & message ) {
statusbar . set_text ( message ) ;
2019-02-10 08:07:13 -02:00
} ;
2020-03-04 15:07:55 -03:00
directory_view . on_thumbnail_progress = [ & ] ( int done , int total ) {
2019-03-25 00:25:25 -03:00
if ( done = = total ) {
2020-03-04 15:07:55 -03:00
progressbar . set_visible ( false ) ;
2019-03-25 00:25:25 -03:00
return ;
}
2020-03-04 15:07:55 -03:00
progressbar . set_range ( 0 , total ) ;
progressbar . set_value ( done ) ;
progressbar . set_visible ( true ) ;
2019-03-25 00:25:25 -03:00
} ;
2020-03-04 15:07:55 -03:00
directory_view . on_selection_change = [ & ] ( GUI : : AbstractView & view ) {
2020-08-14 07:04:03 -03:00
auto & selection = view . selection ( ) ;
2020-04-27 13:24:19 -03:00
copy_action - > set_enabled ( ! selection . is_empty ( ) ) ;
2020-12-28 12:50:51 -03:00
cut_action - > set_enabled ( ! selection . is_empty ( ) ) ;
2020-12-10 01:18:29 -03:00
focus_dependent_delete_action - > set_enabled ( ( ! tree_view . selection ( ) . is_empty ( ) & & tree_view . is_focused ( ) )
| | ! directory_view . current_view ( ) . selection ( ) . is_empty ( ) ) ;
2019-09-13 17:09:01 -03:00
} ;
2019-12-08 02:39:45 -03:00
directory_context_menu - > add_action ( copy_action ) ;
2020-12-28 12:50:51 -03:00
directory_context_menu - > add_action ( cut_action ) ;
2020-04-27 13:06:42 -03:00
directory_context_menu - > add_action ( folder_specific_paste_action ) ;
2020-09-13 16:38:44 -03:00
directory_context_menu - > add_action ( directory_view . delete_action ( ) ) ;
2020-12-22 12:57:59 -03:00
directory_context_menu - > add_action ( shortcut_action ) ;
2019-12-08 02:39:45 -03:00
directory_context_menu - > add_separator ( ) ;
directory_context_menu - > add_action ( properties_action ) ;
2020-12-08 13:51:53 -03:00
directory_view_context_menu - > add_action ( mkdir_action ) ;
directory_view_context_menu - > add_action ( touch_action ) ;
2020-04-26 19:11:01 -03:00
directory_view_context_menu - > add_action ( paste_action ) ;
2020-09-13 09:58:23 -03:00
directory_view_context_menu - > add_action ( directory_view . open_terminal_action ( ) ) ;
2020-04-05 10:42:56 -03:00
directory_view_context_menu - > add_separator ( ) ;
2020-10-08 17:34:48 -03:00
directory_view_context_menu - > add_action ( action_show_dotfiles ) ;
directory_view_context_menu - > add_separator ( ) ;
2020-04-05 10:42:56 -03:00
directory_view_context_menu - > add_action ( properties_action ) ;
2019-12-08 02:39:45 -03:00
2019-12-12 06:49:17 -03:00
tree_view_directory_context_menu - > add_action ( copy_action ) ;
2020-12-28 12:50:51 -03:00
tree_view_directory_context_menu - > add_action ( cut_action ) ;
2019-12-12 06:49:17 -03:00
tree_view_directory_context_menu - > add_action ( paste_action ) ;
2020-09-13 16:48:16 -03:00
tree_view_directory_context_menu - > add_action ( tree_view_delete_action ) ;
2019-12-12 06:49:17 -03:00
tree_view_directory_context_menu - > add_separator ( ) ;
tree_view_directory_context_menu - > add_action ( properties_action ) ;
tree_view_directory_context_menu - > add_separator ( ) ;
2020-12-08 13:51:53 -03:00
tree_view_directory_context_menu - > add_action ( mkdir_action ) ;
tree_view_directory_context_menu - > add_action ( touch_action ) ;
2019-12-12 06:49:17 -03:00
2020-07-13 21:58:21 -03:00
RefPtr < GUI : : Menu > file_context_menu ;
NonnullRefPtrVector < LauncherHandler > current_file_handlers ;
RefPtr < GUI : : Action > file_context_menu_action_default_action ;
2020-08-17 14:58:42 -03:00
directory_view . on_context_menu_request = [ & ] ( const GUI : : ModelIndex & index , const GUI : : ContextMenuEvent & event ) {
2019-12-08 02:39:45 -03:00
if ( index . is_valid ( ) ) {
2020-08-17 17:49:52 -03:00
auto & node = directory_view . node ( index ) ;
2019-12-08 02:39:45 -03:00
2020-04-27 13:06:42 -03:00
if ( node . is_directory ( ) ) {
2020-09-05 11:16:01 -03:00
auto should_get_enabled = access ( node . full_path ( ) . characters ( ) , W_OK ) = = 0 & & GUI : : Clipboard : : the ( ) . mime_type ( ) = = " text/uri-list " ;
2020-04-27 13:06:42 -03:00
folder_specific_paste_action - > set_enabled ( should_get_enabled ) ;
2019-12-08 02:39:45 -03:00
directory_context_menu - > popup ( event . screen_position ( ) ) ;
2020-04-27 13:06:42 -03:00
} else {
2020-07-13 21:58:21 -03:00
file_context_menu = GUI : : Menu : : construct ( " Directory View File " ) ;
file_context_menu - > add_action ( copy_action ) ;
2020-12-28 12:50:51 -03:00
file_context_menu - > add_action ( cut_action ) ;
2020-07-13 21:58:21 -03:00
file_context_menu - > add_action ( paste_action ) ;
2020-09-13 16:38:44 -03:00
file_context_menu - > add_action ( directory_view . delete_action ( ) ) ;
2020-12-22 12:57:59 -03:00
file_context_menu - > add_action ( shortcut_action ) ;
2020-07-13 21:58:21 -03:00
file_context_menu - > add_separator ( ) ;
2020-08-04 09:09:42 -03:00
2021-04-25 10:36:27 -03:00
if ( node . full_path ( ) . ends_with ( " .zip " , AK : : CaseSensitivity : : CaseInsensitive ) ) {
file_context_menu - > add_action ( unzip_archive_action ) ;
file_context_menu - > add_separator ( ) ;
}
2021-03-03 08:00:32 -03:00
bool added_launch_file_handlers = add_launch_handler_actions_to_menu ( file_context_menu , directory_view , node . full_path ( ) , file_context_menu_action_default_action , current_file_handlers ) ;
if ( added_launch_file_handlers )
2020-07-13 21:58:21 -03:00
file_context_menu - > add_separator ( ) ;
file_context_menu - > add_action ( properties_action ) ;
file_context_menu - > popup ( event . screen_position ( ) , file_context_menu_action_default_action ) ;
2020-04-27 13:06:42 -03:00
}
2019-12-08 02:39:45 -03:00
} else {
directory_view_context_menu - > popup ( event . screen_position ( ) ) ;
}
2019-09-13 17:00:47 -03:00
} ;
2020-07-10 10:51:15 -03:00
tree_view . on_selection = [ & ] ( const GUI : : ModelIndex & index ) {
if ( directories_model - > m_previously_selected_index . is_valid ( ) )
directories_model - > update_node_on_selection ( directories_model - > m_previously_selected_index , false ) ;
directories_model - > update_node_on_selection ( index , true ) ;
directories_model - > m_previously_selected_index = index ;
} ;
2020-03-04 15:07:55 -03:00
tree_view . on_selection_change = [ & ] {
2020-12-10 01:18:29 -03:00
focus_dependent_delete_action - > set_enabled ( ( ! tree_view . selection ( ) . is_empty ( ) & & tree_view . is_focused ( ) )
| | ! directory_view . current_view ( ) . selection ( ) . is_empty ( ) ) ;
2020-04-19 10:11:43 -03:00
if ( tree_view . selection ( ) . is_empty ( ) )
return ;
2020-03-04 15:07:55 -03:00
auto path = directories_model - > full_path ( tree_view . selection ( ) . first ( ) ) ;
if ( directory_view . path ( ) = = path )
2019-12-12 06:49:17 -03:00
return ;
2020-09-19 09:09:59 -03:00
TemporaryChange change ( is_reacting_to_tree_view_selection_change , true ) ;
2020-03-04 15:07:55 -03:00
directory_view . open ( path ) ;
copy_action - > set_enabled ( ! tree_view . selection ( ) . is_empty ( ) ) ;
2020-12-28 12:50:51 -03:00
cut_action - > set_enabled ( ! tree_view . selection ( ) . is_empty ( ) ) ;
2020-09-13 16:38:44 -03:00
directory_view . delete_action ( ) . set_enabled ( ! tree_view . selection ( ) . is_empty ( ) ) ;
2019-12-12 06:49:17 -03:00
} ;
2020-12-10 04:07:01 -03:00
tree_view . on_focus_change = [ & ] ( [[maybe_unused]] const bool has_focus, [[maybe_unused]] const GUI : : FocusSource source ) {
2020-12-10 01:18:29 -03:00
focus_dependent_delete_action - > set_enabled ( ( ! tree_view . selection ( ) . is_empty ( ) & & has_focus )
2020-12-10 04:07:01 -03:00
| | ! directory_view . current_view ( ) . selection ( ) . is_empty ( ) ) ;
2020-12-10 01:18:29 -03:00
} ;
2020-03-04 15:07:55 -03:00
tree_view . on_context_menu_request = [ & ] ( const GUI : : ModelIndex & index , const GUI : : ContextMenuEvent & event ) {
2019-12-12 06:49:17 -03:00
if ( index . is_valid ( ) ) {
tree_view_directory_context_menu - > popup ( event . screen_position ( ) ) ;
}
} ;
2021-01-08 14:59:50 -03:00
auto copy_urls_to_directory = [ & ] ( const Vector < URL > & urls , const String & directory ) {
2020-12-09 03:07:30 -03:00
if ( urls . is_empty ( ) ) {
2021-01-08 14:59:50 -03:00
dbgln ( " No files to copy " ) ;
2020-12-09 03:07:30 -03:00
return ;
}
2021-01-08 14:59:50 -03:00
bool had_accepted_copy = false ;
2020-12-09 03:07:30 -03:00
for ( auto & url_to_copy : urls ) {
2021-01-08 14:59:50 -03:00
if ( ! url_to_copy . is_valid ( ) | | url_to_copy . path ( ) = = directory )
2020-12-09 03:07:30 -03:00
continue ;
2021-01-08 14:59:50 -03:00
auto new_path = String : : formatted ( " {}/{} " , directory , LexicalPath ( url_to_copy . path ( ) ) . basename ( ) ) ;
2020-12-09 03:07:30 -03:00
if ( url_to_copy . path ( ) = = new_path )
continue ;
2021-02-20 21:56:28 -03:00
if ( auto result = Core : : File : : copy_file_or_directory ( url_to_copy . path ( ) , new_path ) ; result . is_error ( ) ) {
auto error_message = String : : formatted ( " Could not copy {} into {}: \n {} " , url_to_copy . to_string ( ) , new_path , result . error ( ) . error_code ) ;
2020-12-09 03:07:30 -03:00
GUI : : MessageBox : : show ( window , error_message , " File Manager " , GUI : : MessageBox : : Type : : Error ) ;
} else {
2021-01-08 14:59:50 -03:00
had_accepted_copy = true ;
2020-12-09 03:07:30 -03:00
}
}
2021-01-08 14:59:50 -03:00
if ( had_accepted_copy )
2020-12-09 03:07:30 -03:00
refresh_tree_view ( ) ;
} ;
2021-04-13 11:18:20 -03:00
breadcrumbbar . on_segment_drop = [ & ] ( size_t segment_index , const GUI : : DropEvent & event ) {
2021-01-08 14:59:50 -03:00
if ( ! event . mime_data ( ) . has_urls ( ) )
return ;
2021-04-13 11:18:20 -03:00
copy_urls_to_directory ( event . mime_data ( ) . urls ( ) , breadcrumbbar . segment_data ( segment_index ) ) ;
2021-01-08 14:59:50 -03:00
} ;
2021-04-13 11:18:20 -03:00
breadcrumbbar . on_segment_drag_enter = [ & ] ( size_t , GUI : : DragEvent & event ) {
2021-01-09 07:04:13 -03:00
if ( event . mime_types ( ) . contains_slow ( " text/uri-list " ) )
event . accept ( ) ;
} ;
2021-04-13 11:18:20 -03:00
breadcrumbbar . on_doubleclick = [ & ] ( const GUI : : MouseEvent & ) {
2021-01-09 00:08:40 -03:00
go_to_location_action - > activate ( ) ;
} ;
2021-03-11 14:43:16 -03:00
tree_view . on_drop = [ & ] ( const GUI : : ModelIndex & index , GUI : : DropEvent & event ) {
2021-01-08 14:59:50 -03:00
if ( ! event . mime_data ( ) . has_urls ( ) )
return ;
auto & target_node = directories_model - > node ( index ) ;
if ( ! target_node . is_directory ( ) )
return ;
copy_urls_to_directory ( event . mime_data ( ) . urls ( ) , target_node . full_path ( ) ) ;
2021-03-11 14:43:16 -03:00
event . accept ( ) ;
2021-01-08 14:59:50 -03:00
} ;
2020-03-04 15:07:55 -03:00
directory_view . open ( initial_location ) ;
directory_view . set_focus ( true ) ;
2019-02-09 06:22:04 -02:00
2020-09-05 11:16:01 -03:00
paste_action - > set_enabled ( GUI : : Clipboard : : the ( ) . mime_type ( ) = = " text/uri-list " & & access ( initial_location . characters ( ) , W_OK ) = = 0 ) ;
2020-04-26 13:20:57 -03:00
2019-02-19 22:39:46 -03:00
window - > show ( ) ;
2019-02-09 06:22:04 -02:00
2020-10-02 18:14:37 -03:00
// Read directory read mode from config.
2019-11-04 13:27:56 -03:00
auto dir_view_mode = config - > read_entry ( " DirectoryView " , " ViewMode " , " Icon " ) ;
2020-04-30 21:09:04 -03:00
if ( dir_view_mode . contains ( " Table " ) ) {
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Table ) ;
2019-11-04 13:27:56 -03:00
view_as_table_action - > set_checked ( true ) ;
2020-01-10 13:17:14 -03:00
} else if ( dir_view_mode . contains ( " Columns " ) ) {
2020-03-04 15:07:55 -03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Columns ) ;
2020-01-10 13:17:14 -03:00
view_as_columns_action - > set_checked ( true ) ;
2019-11-04 13:27:56 -03:00
} else {
2020-03-04 15:07:55 -03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Icon ) ;
2019-11-04 13:27:56 -03:00
view_as_icons_action - > set_checked ( true ) ;
}
2021-02-28 15:54:03 -03:00
if ( ! entry_focused_on_init . is_empty ( ) ) {
auto matches = directory_view . current_view ( ) . model ( ) - > matches ( entry_focused_on_init , GUI : : Model : : MatchesFlag : : MatchFull | GUI : : Model : : MatchesFlag : : FirstMatchOnly ) ;
if ( ! matches . is_empty ( ) )
directory_view . current_view ( ) . set_cursor ( matches . first ( ) , GUI : : AbstractView : : SelectionUpdate : : Set ) ;
}
2019-11-09 06:29:03 -03:00
// Write window position to config file on close request.
window - > on_close_request = [ & ] {
config - > write_num_entry ( " Window " , " Left " , window - > x ( ) ) ;
config - > write_num_entry ( " Window " , " Top " , window - > y ( ) ) ;
config - > write_num_entry ( " Window " , " Width " , window - > width ( ) ) ;
2020-10-02 18:14:37 -03:00
config - > write_num_entry ( " Window " , " Height " , window - > height ( ) ) ;
2019-11-09 06:29:03 -03:00
config - > sync ( ) ;
2020-02-02 11:07:41 -03:00
return GUI : : Window : : CloseRequestDecision : : Close ;
2019-11-09 06:29:03 -03:00
} ;
2019-11-20 17:52:15 -03:00
2020-07-04 11:52:01 -03:00
return GUI : : Application : : the ( ) - > exec ( ) ;
2020-04-22 16:10:38 -03:00
}