2020-01-18 11:38:21 +03:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-09-17 15:34:47 +03:00
# include "DesktopWidget.h"
2019-06-07 12:48:03 +03:00
# include "DirectoryView.h"
2019-09-10 16:21:58 +03:00
# include "FileUtils.h"
2021-01-02 02:31:30 +03:00
# include "PropertiesWindow.h"
2020-05-26 14:52:44 +03:00
# include <AK/LexicalPath.h>
2019-09-10 16:21:58 +03:00
# include <AK/StringBuilder.h>
2020-02-13 23:55:05 +03:00
# include <AK/URL.h>
2020-12-20 14:17:59 +03:00
# include <Applications/FileManager/FileManagerWindowGML.h>
2021-03-05 22:43:39 +03:00
# include <LibCore/ArgsParser.h>
2020-02-06 17:04:03 +03:00
# include <LibCore/ConfigFile.h>
2021-02-21 03:56:28 +03:00
# include <LibCore/File.h>
2020-02-14 15:18:34 +03:00
# include <LibCore/MimeData.h>
2020-04-19 20:57:05 +03:00
# include <LibCore/StandardPaths.h>
2020-04-26 22:30:01 +03:00
# include <LibDesktop/Launcher.h>
2020-02-06 22:33:02 +03:00
# include <LibGUI/Action.h>
# include <LibGUI/ActionGroup.h>
# include <LibGUI/Application.h>
# include <LibGUI/BoxLayout.h>
2020-12-14 22:14:50 +03:00
# include <LibGUI/BreadcrumbBar.h>
2020-02-06 22:33:02 +03:00
# include <LibGUI/Clipboard.h>
2020-08-14 23:17:46 +03:00
# include <LibGUI/Desktop.h>
2020-09-16 21:57:41 +03:00
# include <LibGUI/FileIconProvider.h>
2020-02-06 22:33:02 +03:00
# include <LibGUI/FileSystemModel.h>
# include <LibGUI/InputBox.h>
# include <LibGUI/Label.h>
2020-02-15 03:56:30 +03:00
# include <LibGUI/Menu.h>
2020-02-06 22:33:02 +03:00
# include <LibGUI/MenuBar.h>
# include <LibGUI/MessageBox.h>
2020-04-18 23:04:41 +03:00
# include <LibGUI/Painter.h>
2020-02-06 22:33:02 +03:00
# include <LibGUI/ProgressBar.h>
# include <LibGUI/Splitter.h>
# include <LibGUI/StatusBar.h>
# include <LibGUI/TextEditor.h>
# include <LibGUI/ToolBar.h>
2020-04-23 18:44:49 +03:00
# include <LibGUI/ToolBarContainer.h>
2020-02-06 22:33:02 +03:00
# include <LibGUI/TreeView.h>
# include <LibGUI/Widget.h>
# include <LibGUI/Window.h>
2020-04-18 23:04:41 +03:00
# include <LibGfx/Palette.h>
2020-08-10 21:29:08 +03:00
# include <pthread.h>
2020-08-04 15:09:42 +03:00
# include <serenity.h>
2019-03-01 17:47:07 +03:00
# include <signal.h>
2020-06-28 20:40:10 +03:00
# include <spawn.h>
2019-02-09 11:22:04 +03:00
# include <stdio.h>
2020-03-08 14:05:14 +03:00
# include <string.h>
2019-06-07 12:48:03 +03:00
# include <unistd.h>
2019-02-09 11:22:04 +03:00
2020-09-17 16:26:00 +03:00
using namespace FileManager ;
2020-08-17 20:52:01 +03:00
static int run_in_desktop_mode ( RefPtr < Core : : ConfigFile > ) ;
2021-02-28 21:54:03 +03:00
static int run_in_windowed_mode ( RefPtr < Core : : ConfigFile > , String initial_location , String entry_focused_on_init ) ;
2020-12-28 18:50:51 +03:00
static void do_copy ( const Vector < String > & selected_file_paths , FileUtils : : FileOperation file_operation ) ;
2020-12-10 10:07:01 +03:00
static void do_paste ( const String & target_directory , GUI : : Window * window ) ;
2020-12-22 18:57:59 +03:00
static void do_create_link ( const Vector < String > & selected_file_paths , GUI : : Window * window ) ;
2020-12-10 10: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 14: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 23:04:41 +03:00
2019-02-11 16:56:23 +03:00
int main ( int argc , char * * argv )
2019-02-09 11:22:04 +03:00
{
2021-01-16 19:42:31 +03:00
if ( pledge ( " stdio thread recvfd sendfd accept unix cpath rpath wpath fattr proc exec sigaction " , nullptr ) < 0 ) {
2020-01-12 00:13:38 +03:00
perror ( " pledge " ) ;
return 1 ;
}
2019-03-01 17: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 14:34:39 +03:00
RefPtr < Core : : ConfigFile > config = Core : : ConfigFile : : get_for_app ( " FileManager " ) ;
2019-11-04 19:27:56 +03:00
2021-03-05 22: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 15:05:19 +03:00
auto app = GUI : : Application : : construct ( argc , argv ) ;
2019-02-09 11:22:04 +03:00
2021-01-16 19:42:31 +03:00
if ( pledge ( " stdio thread recvfd sendfd accept cpath rpath wpath fattr proc exec unix " , nullptr ) < 0 ) {
2020-01-12 13:59:11 +03:00
perror ( " pledge " ) ;
return 1 ;
}
2021-03-05 22:43:39 +03:00
if ( is_desktop_mode )
2020-08-17 20:52:01 +03:00
return run_in_desktop_mode ( move ( config ) ) ;
2020-04-18 23:04:41 +03:00
// our initial location is defined as, in order of precedence:
2021-03-05 22:43:39 +03:00
// 1. the command-line path argument (e.g. FileManager /bin)
2020-04-18 23:04:41 +03:00
// 2. the user's home directory
// 3. the root directory
2021-03-05 22: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 23:38:03 +03:00
}
2020-04-18 23:04:41 +03:00
if ( initial_location . is_empty ( ) )
2020-04-19 20:57:05 +03:00
initial_location = Core : : StandardPaths : : home_directory ( ) ;
2020-04-18 23:04:41 +03:00
if ( initial_location . is_empty ( ) )
initial_location = " / " ;
2021-02-28 21:54:03 +03:00
String focused_entry ;
2021-03-05 22:43:39 +03:00
if ( is_selection_mode ) {
LexicalPath path ( initial_location ) ;
initial_location = path . dirname ( ) ;
focused_entry = path . basename ( ) ;
}
2021-02-28 21:54:03 +03:00
return run_in_windowed_mode ( move ( config ) , initial_location , focused_entry ) ;
2020-04-18 23:04:41 +03:00
}
2020-12-28 18:50:51 +03:00
void do_copy ( const Vector < String > & selected_file_paths , FileUtils : : FileOperation file_operation )
2020-12-10 10:07:01 +03:00
{
if ( selected_file_paths . is_empty ( ) )
2021-02-23 22:42:32 +03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-10 10:07:01 +03:00
StringBuilder copy_text ;
2020-12-28 18: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 10: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 18: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 10: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-21 03: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 10:07:01 +03:00
GUI : : MessageBox : : show ( window , error_message , " File Manager " , GUI : : MessageBox : : Type : : Error ) ;
2020-12-28 18:50:51 +03:00
} else if ( should_delete_src ) {
FileUtils : : delete_path ( url . path ( ) , window ) ;
2020-12-10 10:07:01 +03:00
}
}
}
2020-12-22 18: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 11:38:11 +03:00
auto destination = String : : formatted ( " {}/{} " , Core : : StandardPaths : : desktop_directory ( ) , LexicalPath { path } . basename ( ) ) ;
2021-02-21 03: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 18:57:59 +03:00
GUI : : MessageBox : : Type : : Error ) ;
}
}
2020-12-10 10:07:01 +03:00
void show_properties ( const String & container_dir_path , const String & path , const Vector < String > & selected , GUI : : Window * window )
{
2021-01-02 02:31:30 +03:00
RefPtr < PropertiesWindow > properties ;
2020-12-10 10:07:01 +03:00
if ( selected . is_empty ( ) ) {
2021-01-02 02:31:30 +03:00
properties = window - > add < PropertiesWindow > ( path , true ) ;
2020-12-10 10:07:01 +03:00
} else {
2021-01-02 02:31:30 +03:00
properties = window - > add < PropertiesWindow > ( selected . first ( ) , access ( container_dir_path . characters ( ) , W_OK ) ! = 0 ) ;
2020-12-10 10:07:01 +03:00
}
2021-01-02 02:31:30 +03:00
properties - > on_close = [ properties = properties . ptr ( ) ] {
properties - > remove_from_parent ( ) ;
} ;
properties - > center_on_screen ( ) ;
properties - > show ( ) ;
2020-12-10 10:07:01 +03:00
}
2021-03-03 14: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-21 02:09:48 +03:00
int run_in_desktop_mode ( [[maybe_unused]] RefPtr < Core : : ConfigFile > config )
2020-04-18 23:04:41 +03:00
{
2020-08-10 21: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 23: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 15:34:47 +03:00
auto & desktop_widget = window - > set_main_widget < FileManager : : DesktopWidget > ( ) ;
2020-04-18 23:04:41 +03:00
desktop_widget . set_layout < GUI : : VerticalBoxLayout > ( ) ;
2020-12-21 02:09:48 +03:00
[[maybe_unused]] auto & directory_view = desktop_widget . add < DirectoryView > ( DirectoryView : : Mode : : Desktop ) ;
2020-04-18 23:04:41 +03:00
2020-12-10 10: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 22:42:32 +03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-10 10:07:01 +03:00
2020-12-28 18:50:51 +03:00
do_copy ( paths , FileUtils : : FileOperation : : Copy ) ;
2020-12-10 10:07:01 +03:00
} ,
window ) ;
copy_action - > set_enabled ( false ) ;
2020-12-28 18: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 22:42:32 +03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-28 18:50:51 +03:00
do_copy ( paths , FileUtils : : FileOperation : : Cut ) ;
} ,
window ) ;
cut_action - > set_enabled ( false ) ;
2020-12-10 10:07:01 +03:00
directory_view . on_selection_change = [ & ] ( const GUI : : AbstractView & view ) {
copy_action - > set_enabled ( ! view . selection ( ) . is_empty ( ) ) ;
2020-12-28 18:50:51 +03:00
cut_action - > set_enabled ( ! view . selection ( ) . is_empty ( ) ) ;
2020-12-10 10:07:01 +03:00
} ;
auto properties_action
= GUI : : Action : : create (
2021-01-05 01:06:02 +03:00
" Properties " , { Mod_Alt , Key_Return } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/properties.png " ) , [ & ] ( const GUI : : Action & ) {
2020-12-10 10:07:01 +03:00
String path = directory_view . path ( ) ;
Vector < String > selected = directory_view . selected_file_paths ( ) ;
show_properties ( path , path , selected , directory_view . window ( ) ) ;
} ,
window ) ;
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 21:27:35 +03:00
auto desktop_view_context_menu = GUI : : Menu : : construct ( " Directory View " ) ;
2021-02-25 10:45:38 +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 20:59:11 +03:00
Desktop : : Launcher : : open ( URL : : create_with_file_protocol ( directory_view . path ( ) ) ) ;
2020-04-22 22:10:38 +03:00
} ) ;
2021-01-05 01:22:38 +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 22:30:01 +03:00
Desktop : : Launcher : : open ( URL : : create_with_file_protocol ( " /bin/DisplaySettings " ) ) ;
2020-04-22 21:46:10 +03:00
} ) ;
2020-08-17 21:06:21 +03:00
desktop_view_context_menu - > add_action ( directory_view . mkdir_action ( ) ) ;
2020-08-17 21:10:19 +03:00
desktop_view_context_menu - > add_action ( directory_view . touch_action ( ) ) ;
2020-12-10 10:07:01 +03:00
desktop_view_context_menu - > add_action ( paste_action ) ;
2020-08-17 21:06:21 +03:00
desktop_view_context_menu - > add_separator ( ) ;
2020-04-22 22:10:38 +03:00
desktop_view_context_menu - > add_action ( file_manager_action ) ;
2020-09-13 15:58:23 +03:00
desktop_view_context_menu - > add_action ( directory_view . open_terminal_action ( ) ) ;
2020-04-22 22:10:38 +03:00
desktop_view_context_menu - > add_separator ( ) ;
2020-04-22 21:46:10 +03:00
desktop_view_context_menu - > add_action ( display_properties_action ) ;
2020-04-22 21:27:35 +03:00
2020-12-10 10:07:01 +03:00
auto desktop_context_menu = GUI : : Menu : : construct ( " Directory View Directory " ) ;
desktop_context_menu - > add_action ( copy_action ) ;
2020-12-28 18:50:51 +03:00
desktop_context_menu - > add_action ( cut_action ) ;
2020-12-10 10: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 14: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 20:52:01 +03:00
directory_view . on_context_menu_request = [ & ] ( const GUI : : ModelIndex & index , const GUI : : ContextMenuEvent & event ) {
2021-03-03 14: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 ( ) ;
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 ) ;
file_context_menu - > popup ( event . screen_position ( ) ) ;
}
} else {
2020-04-22 21:27:35 +03:00
desktop_view_context_menu - > popup ( event . screen_position ( ) ) ;
2021-03-03 14:00:32 +03:00
}
2020-04-22 21:27:35 +03:00
} ;
2020-08-14 23: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 23:04:41 +03:00
window - > show ( ) ;
2020-07-04 17:52:01 +03:00
return GUI : : Application : : the ( ) - > exec ( ) ;
2020-04-18 23:04:41 +03:00
}
2021-02-28 21:54:03 +03:00
int run_in_windowed_mode ( RefPtr < Core : : ConfigFile > config , String initial_location , String entry_focused_on_init )
2020-04-18 23:04:41 +03:00
{
2020-02-02 17:07:41 +03:00
auto window = GUI : : Window : : construct ( ) ;
2019-05-27 14:52:28 +03:00
window - > set_title ( " File Manager " ) ;
2019-11-20 23:52:15 +03:00
2019-11-09 12: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-03 00:14:37 +03:00
auto height = config - > read_num_entry ( " Window " , " Height " , 480 ) ;
window - > set_rect ( { left , top , width , height } ) ;
2019-11-20 23:52:15 +03:00
2020-03-03 23:42:48 +03:00
auto & widget = window - > set_main_widget < GUI : : Widget > ( ) ;
2019-03-02 11:16:57 +03:00
2020-12-20 14:17:59 +03:00
widget . load_from_gml ( file_manager_window_gml ) ;
2020-04-23 18:44:49 +03:00
2021-02-13 01:39:57 +03:00
auto & toolbar_container = * widget . find_descendant_of_type_named < GUI : : ToolBarContainer > ( " toolbar_container " ) ;
2021-01-01 10:57:48 +03:00
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 21:07:55 +03:00
location_toolbar . layout ( ) - > set_margins ( { 6 , 3 , 6 , 3 } ) ;
2019-03-21 00:01:02 +03:00
2021-01-01 10:57:48 +03:00
auto & location_textbox = * widget . find_descendant_of_type_named < GUI : : TextBox > ( " location_textbox " ) ;
2019-03-03 02:34:40 +03:00
2021-01-01 10:57:48 +03:00
auto & breadcrumb_toolbar = * widget . find_descendant_of_type_named < GUI : : ToolBar > ( " breadcrumb_toolbar " ) ;
2021-01-15 21:37:27 +03:00
breadcrumb_toolbar . layout ( ) - > set_margins ( { 6 , 0 , 6 , 0 } ) ;
2021-01-01 10:57:48 +03:00
auto & breadcrumb_bar = * widget . find_descendant_of_type_named < GUI : : BreadcrumbBar > ( " breadcrumb_bar " ) ;
2020-12-14 22:14:50 +03:00
2021-01-01 10: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 14:17:59 +03:00
2020-09-16 20:56:58 +03:00
auto directories_model = GUI : : FileSystemModel : : create ( { } , GUI : : FileSystemModel : : Mode : : DirectoriesOnly ) ;
2020-03-04 21:07:55 +03:00
tree_view . set_model ( directories_model ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : Icon , true ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : Size , true ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : Owner , true ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : Group , true ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : Permissions , true ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : ModificationTime , true ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : Inode , true ) ;
tree_view . set_column_hidden ( GUI : : FileSystemModel : : Column : : SymlinkTarget , true ) ;
2020-09-19 15:09:59 +03:00
bool is_reacting_to_tree_view_selection_change = false ;
2020-08-17 20:52:01 +03:00
auto & directory_view = splitter . add < DirectoryView > ( DirectoryView : : Mode : : Normal ) ;
2020-03-04 21:07:55 +03:00
2020-12-14 22:14:50 +03:00
location_textbox . on_escape_pressed = [ & ] {
directory_view . set_focus ( true ) ;
} ;
2020-09-16 20:56:58 +03:00
// Open the root directory. FIXME: This is awkward.
tree_view . toggle_index ( directories_model - > index ( 0 , 0 , { } ) ) ;
2021-01-01 10:57:48 +03:00
auto & statusbar = * widget . find_descendant_of_type_named < GUI : : StatusBar > ( " statusbar " ) ;
2020-03-04 21:07:55 +03:00
2021-01-01 10:57:48 +03:00
auto & progressbar = * widget . find_descendant_of_type_named < GUI : : ProgressBar > ( " progressbar " ) ;
2020-03-04 21:07:55 +03:00
progressbar . set_format ( GUI : : ProgressBar : : Format : : ValueSlashMax ) ;
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-03 02:34:40 +03:00
} ;
2019-12-03 03:54:29 +03:00
auto refresh_tree_view = [ & ] {
2020-01-10 18:58:00 +03:00
directories_model - > update ( ) ;
2019-12-03 03:54:29 +03:00
2020-03-04 21:07:55 +03:00
auto current_path = directory_view . path ( ) ;
2019-12-03 03:54:29 +03:00
2019-12-12 12:49:17 +03:00
struct stat st ;
// If the directory no longer exists, we find a parent that does.
2020-01-28 00:11:26 +03:00
while ( stat ( current_path . characters ( ) , & st ) ! = 0 ) {
2020-03-04 21:07:55 +03:00
directory_view . open_parent_directory ( ) ;
current_path = directory_view . path ( ) ;
2020-01-10 18:58:00 +03:00
if ( current_path = = directories_model - > root_path ( ) ) {
2019-12-12 12:49:17 +03:00
break ;
}
}
2020-01-10 18:58:00 +03:00
// Reselect the existing folder in the tree.
2020-02-02 17:07:41 +03:00
auto new_index = directories_model - > index ( current_path , GUI : : FileSystemModel : : Column : : Name ) ;
2020-12-08 19: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-03 03:54:29 +03:00
2020-03-04 21:07:55 +03:00
directory_view . refresh ( ) ;
2019-12-03 03:54:29 +03:00
} ;
2020-02-02 17: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 12:49:17 +03:00
2020-02-06 13:56:38 +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 21:07:55 +03:00
directory_view . open_parent_directory ( ) ;
2019-03-02 04:20:11 +03:00
} ) ;
2021-02-13 01: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 ) ;
layout_toolbar_action = GUI : : Action : : create_checkable ( " Toolbar " , [ & ] ( auto & action ) {
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 ) ;
layout_location_action = GUI : : Action : : create_checkable ( " Location bar " , [ & ] ( auto & action ) {
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 ) ;
layout_statusbar_action = GUI : : Action : : create_checkable ( " Status bar " , [ & ] ( auto & action ) {
action . is_checked ( ) ? statusbar . set_visible ( true ) : statusbar . set_visible ( false ) ;
config - > write_bool_entry ( " Layout " , " ShowStatusBar " , action . is_checked ( ) ) ;
config - > sync ( ) ;
} ) ;
auto show_statusbar = config - > read_bool_entry ( " Layout " , " ShowStatusBar " , true ) ;
layout_statusbar_action - > set_checked ( show_statusbar ) ;
statusbar . set_visible ( show_statusbar ) ;
layout_folderpane_action = GUI : : Action : : create_checkable ( " Folder pane " , { Mod_Ctrl , Key_P } , [ & ] ( auto & action ) {
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 17: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 22:09:56 +03:00
2020-07-15 18:35:15 +03:00
view_as_icons_action = GUI : : Action : : create_checkable (
" Icon view " , { Mod_Ctrl , KeyCode : : Key_1 } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/icon-view.png " ) , [ & ] ( const GUI : : Action & ) {
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Icon ) ;
config - > write_entry ( " DirectoryView " , " ViewMode " , " Icon " ) ;
2020-02-13 23:54:27 +03:00
config - > sync ( ) ;
} ,
window ) ;
2019-03-23 05:53:51 +03:00
2020-07-15 18:35:15 +03:00
view_as_table_action = GUI : : Action : : create_checkable (
" Table view " , { Mod_Ctrl , KeyCode : : Key_2 } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/table-view.png " ) , [ & ] ( const GUI : : Action & ) {
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Table ) ;
config - > write_entry ( " DirectoryView " , " ViewMode " , " Table " ) ;
2020-02-13 23:54:27 +03:00
config - > sync ( ) ;
} ,
window ) ;
2019-07-09 23:10:03 +03:00
2020-04-21 18:19:27 +03:00
view_as_columns_action = GUI : : Action : : create_checkable (
2020-07-15 18:35:15 +03:00
" Columns view " , { Mod_Ctrl , KeyCode : : Key_3 } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/columns-view.png " ) , [ & ] ( const GUI : : Action & ) {
2020-03-04 21:07:55 +03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Columns ) ;
2020-02-13 23:54:27 +03:00
config - > write_entry ( " DirectoryView " , " ViewMode " , " Columns " ) ;
config - > sync ( ) ;
} ,
window ) ;
2020-01-10 19:17:14 +03:00
2020-02-02 17:07:41 +03:00
auto view_type_action_group = make < GUI : : ActionGroup > ( ) ;
2019-07-09 23:10:03 +03:00
view_type_action_group - > set_exclusive ( true ) ;
view_type_action_group - > add_action ( * view_as_icons_action ) ;
2020-07-15 18:35:15 +03:00
view_type_action_group - > add_action ( * view_as_table_action ) ;
2020-01-10 19:17:14 +03:00
view_type_action_group - > add_action ( * view_as_columns_action ) ;
2019-11-20 23:52:15 +03:00
2019-12-12 12:49:17 +03:00
auto tree_view_selected_file_paths = [ & ] {
Vector < String > paths ;
auto & view = tree_view ;
2020-03-04 21:07:55 +03:00
view . selection ( ) . for_each_index ( [ & ] ( const GUI : : ModelIndex & index ) {
2020-01-10 18:58:00 +03:00
paths . append ( directories_model - > full_path ( index ) ) ;
2019-12-12 12:49:17 +03:00
} ) ;
return paths ;
} ;
2020-02-02 17:07:41 +03:00
auto select_all_action = GUI : : Action : : create ( " Select all " , { Mod_Ctrl , KeyCode : : Key_A } , [ & ] ( const GUI : : Action & ) {
2020-03-04 21:07:55 +03:00
directory_view . current_view ( ) . select_all ( ) ;
2020-01-07 12:29:21 +03:00
} ) ;
2020-02-13 23:54:27 +03:00
auto copy_action = GUI : : CommonActions : : make_copy_action (
2020-08-17 20:52:01 +03:00
[ & ] ( auto & ) {
auto paths = directory_view . selected_file_paths ( ) ;
2020-04-27 01:03:17 +03:00
2020-12-10 10:07:01 +03:00
if ( paths . is_empty ( ) )
2020-02-13 23:54:27 +03:00
paths = tree_view_selected_file_paths ( ) ;
2020-04-27 01:03:17 +03:00
2020-02-13 23:54:27 +03:00
if ( paths . is_empty ( ) )
2021-02-23 22:42:32 +03:00
VERIFY_NOT_REACHED ( ) ;
2020-04-27 01:03:17 +03:00
2020-12-28 18:50:51 +03:00
do_copy ( paths , FileUtils : : FileOperation : : Copy ) ;
2020-12-10 10:07:01 +03:00
refresh_tree_view ( ) ;
2020-02-13 23:54:27 +03:00
} ,
window ) ;
2019-09-13 23:09:01 +03:00
copy_action - > set_enabled ( false ) ;
2019-09-10 16:21:58 +03:00
2020-12-28 18: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 22:42:32 +03:00
VERIFY_NOT_REACHED ( ) ;
2020-12-28 18:50:51 +03:00
do_copy ( paths , FileUtils : : FileOperation : : Cut ) ;
refresh_tree_view ( ) ;
} ,
window ) ;
cut_action - > set_enabled ( false ) ;
2020-12-22 18:57:59 +03:00
auto shortcut_action
= GUI : : Action : : create (
" Create desktop shortcut " ,
{ } ,
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 ) ;
2019-09-14 10:20:20 +03:00
auto properties_action
2020-02-13 23:54:27 +03:00
= GUI : : Action : : create (
2021-01-05 01:06:02 +03:00
" Properties " , { Mod_Alt , Key_Return } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/properties.png " ) , [ & ] ( const GUI : : Action & action ) {
2020-04-27 20:03:13 +03:00
String container_dir_path ;
2020-02-13 23:54:27 +03:00
String path ;
Vector < String > selected ;
2020-03-04 21:07:55 +03:00
if ( action . activator ( ) = = directory_context_menu | | directory_view . active_widget ( ) - > is_focused ( ) ) {
path = directory_view . path ( ) ;
2020-04-27 20:03:13 +03:00
container_dir_path = path ;
2020-08-17 20:52:01 +03:00
selected = directory_view . selected_file_paths ( ) ;
2020-02-13 23:54:27 +03:00
} else {
2020-03-04 21:07:55 +03:00
path = directories_model - > full_path ( tree_view . selection ( ) . first ( ) ) ;
2020-05-26 14:52:44 +03:00
container_dir_path = LexicalPath ( path ) . basename ( ) ;
2020-02-13 23:54:27 +03:00
selected = tree_view_selected_file_paths ( ) ;
}
2020-12-10 10:07:01 +03:00
show_properties ( container_dir_path , path , selected , directory_view . window ( ) ) ;
2020-02-13 23:54:27 +03:00
} ,
window ) ;
2019-11-20 23:52:15 +03:00
2020-04-27 19:06:42 +03:00
auto paste_action = GUI : : CommonActions : : make_paste_action (
[ & ] ( const GUI : : Action & action ) {
2020-12-10 10: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 19:06:42 +03:00
} ,
window ) ;
auto folder_specific_paste_action = GUI : : CommonActions : : make_paste_action (
[ & ] ( const GUI : : Action & action ) {
2020-12-10 10: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 19:06:42 +03:00
} ,
window ) ;
2020-02-13 23:54:27 +03:00
auto go_back_action = GUI : : CommonActions : : make_go_back_action (
[ & ] ( auto & ) {
2020-03-04 21:07:55 +03:00
directory_view . open_previous_directory ( ) ;
2020-02-13 23:54:27 +03:00
} ,
window ) ;
auto go_forward_action = GUI : : CommonActions : : make_go_forward_action (
[ & ] ( auto & ) {
2020-03-04 21:07:55 +03:00
directory_view . open_next_directory ( ) ;
2020-02-13 23:54:27 +03:00
} ,
window ) ;
auto go_home_action = GUI : : CommonActions : : make_go_home_action (
[ & ] ( auto & ) {
2020-04-19 20:57:05 +03:00
directory_view . open ( Core : : StandardPaths : : home_directory ( ) ) ;
2020-02-13 23:54:27 +03:00
} ,
window ) ;
2019-07-21 10:19:09 +03:00
2020-05-14 23:51:15 +03:00
GUI : : Clipboard : : the ( ) . on_change = [ & ] ( const String & data_type ) {
2020-04-27 19:06:42 +03:00
auto current_location = directory_view . path ( ) ;
2020-05-15 22:35:03 +03:00
paste_action - > set_enabled ( data_type = = " text/uri-list " & & access ( current_location . characters ( ) , W_OK ) = = 0 ) ;
2020-04-27 19:06:42 +03:00
} ;
2020-09-13 22: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 19:51:53 +03:00
refresh_tree_view ( ) ;
2020-09-13 22: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 19:51:53 +03:00
refresh_tree_view ( ) ;
} ) ;
2020-12-10 07:18:29 +03:00
focus_dependent_delete_action - > set_enabled ( false ) ;
2020-12-08 19:51:53 +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 & ) {
directory_view . mkdir_action ( ) . activate ( ) ;
refresh_tree_view ( ) ;
} ) ;
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 & ) {
directory_view . touch_action ( ) . activate ( ) ;
refresh_tree_view ( ) ;
2020-09-13 22:38:44 +03:00
} ) ;
2020-04-21 17:01:00 +03:00
auto menubar = GUI : : MenuBar : : construct ( ) ;
2019-02-14 10:52:12 +03:00
2020-04-04 13:18:40 +03:00
auto & app_menu = menubar - > add_menu ( " File Manager " ) ;
2020-12-08 19:51:53 +03:00
app_menu . add_action ( mkdir_action ) ;
app_menu . add_action ( touch_action ) ;
2020-04-04 13:18:40 +03:00
app_menu . add_action ( copy_action ) ;
2020-12-28 18:50:51 +03:00
app_menu . add_action ( cut_action ) ;
2020-04-04 13:18:40 +03:00
app_menu . add_action ( paste_action ) ;
2020-09-13 22:38:44 +03:00
app_menu . add_action ( focus_dependent_delete_action ) ;
2020-09-13 15:58:23 +03:00
app_menu . add_action ( directory_view . open_terminal_action ( ) ) ;
2020-04-04 13:18:40 +03:00
app_menu . add_separator ( ) ;
2020-04-05 16:42:56 +03:00
app_menu . add_action ( properties_action ) ;
app_menu . add_separator ( ) ;
2020-04-04 13:18:40 +03:00
app_menu . add_action ( GUI : : CommonActions : : make_quit_action ( [ ] ( auto & ) {
2020-07-04 17:52:01 +03:00
GUI : : Application : : the ( ) - > quit ( ) ;
2019-02-14 10:52:12 +03:00
} ) ) ;
2020-04-04 13:18:40 +03:00
2020-10-08 23:34:48 +03:00
auto action_show_dotfiles = GUI : : Action : : create_checkable ( " Show dotfiles " , { Mod_Ctrl , Key_H } , [ & ] ( auto & action ) {
directory_view . set_should_show_dotfiles ( action . is_checked ( ) ) ;
2020-12-08 19:51:53 +03:00
refresh_tree_view ( ) ;
2021-02-13 01:37:07 +03:00
config - > write_bool_entry ( " DirectoryView " , " ShowDotFiles " , action . is_checked ( ) ) ;
config - > sync ( ) ;
2020-10-08 23:34:48 +03:00
} ) ;
2021-02-13 01: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 ) ;
2020-04-04 13:18:40 +03:00
auto & view_menu = menubar - > add_menu ( " View " ) ;
2021-02-13 01:39:57 +03:00
auto & layout_menu = view_menu . add_submenu ( " Layout " ) ;
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 13: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 19:46:37 +03:00
view_menu . add_separator ( ) ;
2020-10-08 23:34:48 +03:00
view_menu . add_action ( action_show_dotfiles ) ;
2020-04-04 13:18:40 +03:00
2021-01-09 06:08:40 +03:00
auto go_to_location_action = GUI : : Action : : create ( " Go to location... " , { Mod_Ctrl , Key_L } , [ & ] ( auto & ) {
2021-02-13 01:39:57 +03:00
toolbar_container . set_visible ( true ) ;
2021-01-09 06:08:40 +03:00
location_toolbar . set_visible ( true ) ;
breadcrumb_toolbar . set_visible ( false ) ;
location_textbox . select_all ( ) ;
location_textbox . set_focus ( true ) ;
} ) ;
2020-04-04 13:18:40 +03:00
auto & go_menu = menubar - > add_menu ( " Go " ) ;
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 06:08:40 +03:00
go_menu . add_action ( go_to_location_action ) ;
2020-04-04 13:18:40 +03:00
auto & help_menu = menubar - > add_menu ( " Help " ) ;
2021-02-25 00: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 10:52:12 +03:00
2020-07-04 17:52:01 +03:00
GUI : : Application : : the ( ) - > set_menubar ( move ( menubar ) ) ;
2019-02-14 10:52:12 +03:00
2020-03-04 21: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-28 05:38:23 +03:00
2020-03-04 21:07:55 +03:00
main_toolbar . add_separator ( ) ;
2020-12-08 19:51:53 +03:00
main_toolbar . add_action ( mkdir_action ) ;
main_toolbar . add_action ( touch_action ) ;
2020-03-04 21:07:55 +03:00
main_toolbar . add_action ( copy_action ) ;
2020-12-28 18:50:51 +03:00
main_toolbar . add_action ( cut_action ) ;
2020-03-04 21:07:55 +03:00
main_toolbar . add_action ( paste_action ) ;
2020-09-13 22:38:44 +03:00
main_toolbar . add_action ( focus_dependent_delete_action ) ;
2020-09-13 15:58:23 +03:00
main_toolbar . add_action ( directory_view . open_terminal_action ( ) ) ;
2019-02-20 04:39:46 +03:00
2020-03-04 21: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-25 03:29:45 +03:00
2021-03-07 18: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 21: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 22:37:25 +03:00
2020-10-05 15:59:50 +03:00
window - > set_title ( String : : formatted ( " {} - File Manager " , new_path ) ) ;
2020-03-04 21:07:55 +03:00
location_textbox . set_text ( new_path ) ;
2020-09-19 15:09:59 +03:00
2020-12-14 22:14:50 +03:00
{
LexicalPath lexical_path ( new_path ) ;
auto segment_index_of_new_path_in_breadcrumb_bar = [ & ] ( ) - > Optional < size_t > {
for ( size_t i = 0 ; i < breadcrumb_bar . segment_count ( ) ; + + i ) {
if ( breadcrumb_bar . segment_data ( i ) = = new_path )
return i ;
}
return { } ;
} ( ) ;
if ( segment_index_of_new_path_in_breadcrumb_bar . has_value ( ) ) {
breadcrumb_bar . set_selected_segment ( segment_index_of_new_path_in_breadcrumb_bar . value ( ) ) ;
} else {
breadcrumb_bar . clear_segments ( ) ;
2021-02-20 16:23:41 +03:00
breadcrumb_bar . append_segment ( " / " , GUI : : FileIconProvider : : icon_for_path ( " / " ) . bitmap_for_size ( 16 ) , " / " , " / " ) ;
2020-12-14 22: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-02-20 16:23:41 +03:00
breadcrumb_bar . append_segment ( part , GUI : : FileIconProvider : : icon_for_path ( builder . string_view ( ) ) . bitmap_for_size ( 16 ) , builder . string_view ( ) , builder . string_view ( ) ) ;
2020-12-14 22:14:50 +03:00
}
breadcrumb_bar . set_selected_segment ( breadcrumb_bar . segment_count ( ) - 1 ) ;
2020-12-15 15:16:26 +03:00
breadcrumb_bar . on_segment_click = [ & ] ( size_t segment_index ) {
directory_view . open ( breadcrumb_bar . segment_data ( segment_index ) ) ;
2020-12-14 22:14:50 +03:00
} ;
}
}
2020-09-19 15: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 12:49:17 +03:00
}
2019-05-24 00:15:57 +03:00
2020-04-26 16:56:07 +03:00
struct stat st ;
if ( lstat ( new_path . characters ( ) , & st ) ) {
perror ( " stat " ) ;
return ;
}
2020-09-05 17:16:01 +03:00
paste_action - > set_enabled ( can_write_in_path & & GUI : : Clipboard : : the ( ) . mime_type ( ) = = " text/uri-list " ) ;
2020-04-26 16:56:07 +03:00
go_forward_action - > set_enabled ( directory_view . path_history_position ( ) < directory_view . path_history_size ( ) - 1 ) ;
2020-03-04 21:07:55 +03:00
go_back_action - > set_enabled ( directory_view . path_history_position ( ) > 0 ) ;
2020-04-26 16:23:33 +03:00
open_parent_directory_action - > set_enabled ( new_path ! = " / " ) ;
2021-03-07 18: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 11:22:04 +03:00
} ;
2021-03-07 18:04:59 +03:00
directory_view . on_accepted_drop = [ & ] {
2020-12-08 19:51:53 +03:00
refresh_tree_view ( ) ;
} ;
2020-03-04 21:07:55 +03:00
directory_view . on_status_message = [ & ] ( const StringView & message ) {
statusbar . set_text ( message ) ;
2019-02-10 13:07:13 +03:00
} ;
2020-03-04 21:07:55 +03:00
directory_view . on_thumbnail_progress = [ & ] ( int done , int total ) {
2019-03-25 06:25:25 +03:00
if ( done = = total ) {
2020-03-04 21:07:55 +03:00
progressbar . set_visible ( false ) ;
2019-03-25 06:25:25 +03:00
return ;
}
2020-03-04 21:07:55 +03:00
progressbar . set_range ( 0 , total ) ;
progressbar . set_value ( done ) ;
progressbar . set_visible ( true ) ;
2019-03-25 06:25:25 +03:00
} ;
2020-03-04 21:07:55 +03:00
directory_view . on_selection_change = [ & ] ( GUI : : AbstractView & view ) {
2020-08-14 13:04:03 +03:00
auto & selection = view . selection ( ) ;
2020-04-27 19:24:19 +03:00
copy_action - > set_enabled ( ! selection . is_empty ( ) ) ;
2020-12-28 18:50:51 +03:00
cut_action - > set_enabled ( ! selection . is_empty ( ) ) ;
2020-12-10 07: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 23:09:01 +03:00
} ;
2019-12-08 08:39:45 +03:00
directory_context_menu - > add_action ( copy_action ) ;
2020-12-28 18:50:51 +03:00
directory_context_menu - > add_action ( cut_action ) ;
2020-04-27 19:06:42 +03:00
directory_context_menu - > add_action ( folder_specific_paste_action ) ;
2020-09-13 22:38:44 +03:00
directory_context_menu - > add_action ( directory_view . delete_action ( ) ) ;
2020-12-22 18:57:59 +03:00
directory_context_menu - > add_action ( shortcut_action ) ;
2019-12-08 08:39:45 +03:00
directory_context_menu - > add_separator ( ) ;
directory_context_menu - > add_action ( properties_action ) ;
2020-12-08 19:51:53 +03:00
directory_view_context_menu - > add_action ( mkdir_action ) ;
directory_view_context_menu - > add_action ( touch_action ) ;
2020-04-27 01:11:01 +03:00
directory_view_context_menu - > add_action ( paste_action ) ;
2020-09-13 15:58:23 +03:00
directory_view_context_menu - > add_action ( directory_view . open_terminal_action ( ) ) ;
2020-04-05 16:42:56 +03:00
directory_view_context_menu - > add_separator ( ) ;
2020-10-08 23:34:48 +03:00
directory_view_context_menu - > add_action ( action_show_dotfiles ) ;
directory_view_context_menu - > add_separator ( ) ;
2020-04-05 16:42:56 +03:00
directory_view_context_menu - > add_action ( properties_action ) ;
2019-12-08 08:39:45 +03:00
2019-12-12 12:49:17 +03:00
tree_view_directory_context_menu - > add_action ( copy_action ) ;
2020-12-28 18:50:51 +03:00
tree_view_directory_context_menu - > add_action ( cut_action ) ;
2019-12-12 12:49:17 +03:00
tree_view_directory_context_menu - > add_action ( paste_action ) ;
2020-09-13 22:48:16 +03:00
tree_view_directory_context_menu - > add_action ( tree_view_delete_action ) ;
2019-12-12 12: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 19: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 12:49:17 +03:00
2020-07-14 03: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 20:58:42 +03:00
directory_view . on_context_menu_request = [ & ] ( const GUI : : ModelIndex & index , const GUI : : ContextMenuEvent & event ) {
2019-12-08 08:39:45 +03:00
if ( index . is_valid ( ) ) {
2020-08-17 23:49:52 +03:00
auto & node = directory_view . node ( index ) ;
2019-12-08 08:39:45 +03:00
2020-04-27 19:06:42 +03:00
if ( node . is_directory ( ) ) {
2020-09-05 17: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 19:06:42 +03:00
folder_specific_paste_action - > set_enabled ( should_get_enabled ) ;
2019-12-08 08:39:45 +03:00
directory_context_menu - > popup ( event . screen_position ( ) ) ;
2020-04-27 19:06:42 +03:00
} else {
2020-07-14 03:58:21 +03:00
file_context_menu = GUI : : Menu : : construct ( " Directory View File " ) ;
file_context_menu - > add_action ( copy_action ) ;
2020-12-28 18:50:51 +03:00
file_context_menu - > add_action ( cut_action ) ;
2020-07-14 03:58:21 +03:00
file_context_menu - > add_action ( paste_action ) ;
2020-09-13 22:38:44 +03:00
file_context_menu - > add_action ( directory_view . delete_action ( ) ) ;
2020-12-22 18:57:59 +03:00
file_context_menu - > add_action ( shortcut_action ) ;
2020-07-14 03:58:21 +03:00
file_context_menu - > add_separator ( ) ;
2020-08-04 15:09:42 +03:00
2021-03-03 14: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-14 03: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 19:06:42 +03:00
}
2019-12-08 08:39:45 +03:00
} else {
directory_view_context_menu - > popup ( event . screen_position ( ) ) ;
}
2019-09-13 23:00:47 +03:00
} ;
2020-07-10 16: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 21:07:55 +03:00
tree_view . on_selection_change = [ & ] {
2020-12-10 07: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 16:11:43 +03:00
if ( tree_view . selection ( ) . is_empty ( ) )
return ;
2020-03-04 21:07:55 +03:00
auto path = directories_model - > full_path ( tree_view . selection ( ) . first ( ) ) ;
if ( directory_view . path ( ) = = path )
2019-12-12 12:49:17 +03:00
return ;
2020-09-19 15:09:59 +03:00
TemporaryChange change ( is_reacting_to_tree_view_selection_change , true ) ;
2020-03-04 21:07:55 +03:00
directory_view . open ( path ) ;
copy_action - > set_enabled ( ! tree_view . selection ( ) . is_empty ( ) ) ;
2020-12-28 18:50:51 +03:00
cut_action - > set_enabled ( ! tree_view . selection ( ) . is_empty ( ) ) ;
2020-09-13 22:38:44 +03:00
directory_view . delete_action ( ) . set_enabled ( ! tree_view . selection ( ) . is_empty ( ) ) ;
2019-12-12 12:49:17 +03:00
} ;
2020-12-10 10:07:01 +03:00
tree_view . on_focus_change = [ & ] ( [[maybe_unused]] const bool has_focus, [[maybe_unused]] const GUI : : FocusSource source ) {
2020-12-10 07:18:29 +03:00
focus_dependent_delete_action - > set_enabled ( ( ! tree_view . selection ( ) . is_empty ( ) & & has_focus )
2020-12-10 10:07:01 +03:00
| | ! directory_view . current_view ( ) . selection ( ) . is_empty ( ) ) ;
2020-12-10 07:18:29 +03:00
} ;
2020-03-04 21:07:55 +03:00
tree_view . on_context_menu_request = [ & ] ( const GUI : : ModelIndex & index , const GUI : : ContextMenuEvent & event ) {
2019-12-12 12:49:17 +03:00
if ( index . is_valid ( ) ) {
tree_view_directory_context_menu - > popup ( event . screen_position ( ) ) ;
}
} ;
2021-01-08 20:59:50 +03:00
auto copy_urls_to_directory = [ & ] ( const Vector < URL > & urls , const String & directory ) {
2020-12-09 09:07:30 +03:00
if ( urls . is_empty ( ) ) {
2021-01-08 20:59:50 +03:00
dbgln ( " No files to copy " ) ;
2020-12-09 09:07:30 +03:00
return ;
}
2021-01-08 20:59:50 +03:00
bool had_accepted_copy = false ;
2020-12-09 09:07:30 +03:00
for ( auto & url_to_copy : urls ) {
2021-01-08 20:59:50 +03:00
if ( ! url_to_copy . is_valid ( ) | | url_to_copy . path ( ) = = directory )
2020-12-09 09:07:30 +03:00
continue ;
2021-01-08 20:59:50 +03:00
auto new_path = String : : formatted ( " {}/{} " , directory , LexicalPath ( url_to_copy . path ( ) ) . basename ( ) ) ;
2020-12-09 09:07:30 +03:00
if ( url_to_copy . path ( ) = = new_path )
continue ;
2021-02-21 03: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 09:07:30 +03:00
GUI : : MessageBox : : show ( window , error_message , " File Manager " , GUI : : MessageBox : : Type : : Error ) ;
} else {
2021-01-08 20:59:50 +03:00
had_accepted_copy = true ;
2020-12-09 09:07:30 +03:00
}
}
2021-01-08 20:59:50 +03:00
if ( had_accepted_copy )
2020-12-09 09:07:30 +03:00
refresh_tree_view ( ) ;
} ;
2021-01-09 13:04:13 +03:00
breadcrumb_bar . on_segment_drop = [ & ] ( size_t segment_index , const GUI : : DropEvent & event ) {
2021-01-08 20:59:50 +03:00
if ( ! event . mime_data ( ) . has_urls ( ) )
return ;
copy_urls_to_directory ( event . mime_data ( ) . urls ( ) , breadcrumb_bar . segment_data ( segment_index ) ) ;
} ;
2021-01-09 13:04:13 +03:00
breadcrumb_bar . on_segment_drag_enter = [ & ] ( size_t , GUI : : DragEvent & event ) {
if ( event . mime_types ( ) . contains_slow ( " text/uri-list " ) )
event . accept ( ) ;
} ;
2021-01-09 06:08:40 +03:00
breadcrumb_bar . on_doubleclick = [ & ] ( const GUI : : MouseEvent & ) {
go_to_location_action - > activate ( ) ;
} ;
2021-01-08 20:59:50 +03:00
tree_view . on_drop = [ & ] ( const GUI : : ModelIndex & index , const GUI : : DropEvent & event ) {
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 ( ) ) ;
} ;
2020-03-04 21:07:55 +03:00
directory_view . open ( initial_location ) ;
directory_view . set_focus ( true ) ;
2019-02-09 11:22:04 +03:00
2020-09-05 17: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 19:20:57 +03:00
2019-02-20 04:39:46 +03:00
window - > show ( ) ;
2019-02-09 11:22:04 +03:00
2020-10-03 00:14:37 +03:00
// Read directory read mode from config.
2019-11-04 19:27:56 +03:00
auto dir_view_mode = config - > read_entry ( " DirectoryView " , " ViewMode " , " Icon " ) ;
2020-05-01 03:09:04 +03:00
if ( dir_view_mode . contains ( " Table " ) ) {
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Table ) ;
2019-11-04 19:27:56 +03:00
view_as_table_action - > set_checked ( true ) ;
2020-01-10 19:17:14 +03:00
} else if ( dir_view_mode . contains ( " Columns " ) ) {
2020-03-04 21:07:55 +03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Columns ) ;
2020-01-10 19:17:14 +03:00
view_as_columns_action - > set_checked ( true ) ;
2019-11-04 19:27:56 +03:00
} else {
2020-03-04 21:07:55 +03:00
directory_view . set_view_mode ( DirectoryView : : ViewMode : : Icon ) ;
2019-11-04 19:27:56 +03:00
view_as_icons_action - > set_checked ( true ) ;
}
2021-02-28 21: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 12: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-03 00:14:37 +03:00
config - > write_num_entry ( " Window " , " Height " , window - > height ( ) ) ;
2019-11-09 12:29:03 +03:00
config - > sync ( ) ;
2020-02-02 17:07:41 +03:00
return GUI : : Window : : CloseRequestDecision : : Close ;
2019-11-09 12:29:03 +03:00
} ;
2019-11-20 23:52:15 +03:00
2020-07-04 17:52:01 +03:00
return GUI : : Application : : the ( ) - > exec ( ) ;
2020-04-22 22:10:38 +03:00
}