2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* filesystem_dock.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2016-07-21 15:34:57 +02:00
# include "filesystem_dock.h"
2017-01-16 08:04:19 +01:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2021-06-11 14:51:48 +02:00
# include "core/io/dir_access.h"
# include "core/io/file_access.h"
2018-09-11 18:13:45 +02:00
# include "core/io/resource_loader.h"
2018-01-05 20:45:54 +01:00
# include "core/os/keyboard.h"
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
2020-11-07 23:33:38 +01:00
# include "core/templates/list.h"
2023-04-07 18:59:49 +02:00
# include "editor/create_dialog.h"
2023-04-15 12:15:57 +02:00
# include "editor/directory_create_dialog.h"
2022-02-12 02:46:22 +01:00
# include "editor/editor_feature_profile.h"
# include "editor/editor_node.h"
# include "editor/editor_resource_preview.h"
# include "editor/editor_scale.h"
# include "editor/editor_settings.h"
2023-04-07 18:59:49 +02:00
# include "editor/gui/editor_dir_dialog.h"
2022-11-11 20:12:48 +01:00
# include "editor/import/resource_importer_scene.h"
2022-02-14 14:00:03 +01:00
# include "editor/import_dock.h"
2022-07-20 23:44:06 +02:00
# include "editor/plugins/editor_resource_tooltip_plugins.h"
2022-06-12 02:11:52 +02:00
# include "editor/scene_create_dialog.h"
2022-02-12 02:46:22 +01:00
# include "editor/scene_tree_dock.h"
2022-02-14 14:00:03 +01:00
# include "editor/shader_create_dialog.h"
2023-04-07 18:59:49 +02:00
# include "scene/gui/item_list.h"
2022-02-14 14:00:03 +01:00
# include "scene/gui/label.h"
2023-04-07 18:59:49 +02:00
# include "scene/gui/line_edit.h"
# include "scene/gui/progress_bar.h"
2022-07-20 23:44:06 +02:00
# include "scene/gui/texture_rect.h"
2020-03-04 02:51:12 +01:00
# include "scene/main/window.h"
2019-08-15 19:47:21 +02:00
# include "scene/resources/packed_scene.h"
2020-03-03 14:36:29 +01:00
# include "servers/display_server.h"
2016-07-06 19:04:21 +02:00
2022-07-20 23:44:06 +02:00
Control * FileSystemTree : : make_custom_tooltip ( const String & p_text ) const {
TreeItem * item = get_item_at_position ( get_local_mouse_position ( ) ) ;
if ( ! item ) {
return nullptr ;
}
return FileSystemDock : : get_singleton ( ) - > create_tooltip_for_path ( item - > get_metadata ( 0 ) ) ;
}
Control * FileSystemList : : make_custom_tooltip ( const String & p_text ) const {
int idx = get_item_at_position ( get_local_mouse_position ( ) ) ;
if ( idx = = - 1 ) {
return nullptr ;
}
return FileSystemDock : : get_singleton ( ) - > create_tooltip_for_path ( get_item_metadata ( idx ) ) ;
}
2023-05-26 23:04:14 +02:00
void FileSystemList : : _line_editor_submit ( String p_text ) {
popup_editor - > hide ( ) ;
emit_signal ( SNAME ( " item_edited " ) ) ;
queue_redraw ( ) ;
}
bool FileSystemList : : edit_selected ( ) {
ERR_FAIL_COND_V_MSG ( ! is_anything_selected ( ) , false , " No item selected. " ) ;
int s = get_current ( ) ;
ensure_current_is_visible ( ) ;
Rect2 rect ;
Rect2 popup_rect ;
Vector2 ofs ;
Vector2 icon_size = get_item_icon ( s ) - > get_size ( ) ;
// Handles the different icon modes (TOP/LEFT).
switch ( get_icon_mode ( ) ) {
case ItemList : : ICON_MODE_LEFT :
rect = get_item_rect ( s , true ) ;
ofs = Vector2 ( 0 , Math : : floor ( ( MAX ( line_editor - > get_minimum_size ( ) . height , rect . size . height ) - rect . size . height ) / 2 ) ) ;
popup_rect . position = get_screen_position ( ) + rect . position - ofs ;
popup_rect . size = rect . size ;
// Adjust for icon position and size.
popup_rect . size . x - = icon_size . x ;
popup_rect . position . x + = icon_size . x ;
break ;
case ItemList : : ICON_MODE_TOP :
rect = get_item_rect ( s , false ) ;
popup_rect . position = get_screen_position ( ) + rect . position ;
popup_rect . size = rect . size ;
// Adjust for icon position and size.
popup_rect . size . y - = icon_size . y ;
popup_rect . position . y + = icon_size . y ;
break ;
}
popup_editor - > set_position ( popup_rect . position ) ;
popup_editor - > set_size ( popup_rect . size ) ;
String name = get_item_text ( s ) ;
line_editor - > set_text ( name ) ;
line_editor - > select ( 0 , name . rfind ( " . " ) ) ;
popup_editor - > popup ( ) ;
popup_editor - > child_controls_changed ( ) ;
line_editor - > grab_focus ( ) ;
return true ;
}
String FileSystemList : : get_edit_text ( ) {
return line_editor - > get_text ( ) ;
}
void FileSystemList : : _text_editor_popup_modal_close ( ) {
if ( Input : : get_singleton ( ) - > is_key_pressed ( Key : : ESCAPE ) | |
Input : : get_singleton ( ) - > is_key_pressed ( Key : : KP_ENTER ) | |
Input : : get_singleton ( ) - > is_key_pressed ( Key : : ENTER ) ) {
return ;
}
_line_editor_submit ( line_editor - > get_text ( ) ) ;
}
void FileSystemList : : _bind_methods ( ) {
ADD_SIGNAL ( MethodInfo ( " item_edited " ) ) ;
}
FileSystemList : : FileSystemList ( ) {
popup_editor = memnew ( Popup ) ;
add_child ( popup_editor ) ;
popup_editor_vb = memnew ( VBoxContainer ) ;
popup_editor_vb - > add_theme_constant_override ( " separation " , 0 ) ;
popup_editor_vb - > set_anchors_and_offsets_preset ( PRESET_FULL_RECT ) ;
popup_editor - > add_child ( popup_editor_vb ) ;
line_editor = memnew ( LineEdit ) ;
line_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
popup_editor_vb - > add_child ( line_editor ) ;
line_editor - > connect ( " text_submitted " , callable_mp ( this , & FileSystemList : : _line_editor_submit ) ) ;
popup_editor - > connect ( " popup_hide " , callable_mp ( this , & FileSystemList : : _text_editor_popup_modal_close ) ) ;
}
2021-11-17 21:08:55 +01:00
FileSystemDock * FileSystemDock : : singleton = nullptr ;
2020-10-07 21:56:53 +02:00
Ref < Texture2D > FileSystemDock : : _get_tree_item_icon ( bool p_is_valid , String p_file_type ) {
2019-06-11 20:43:37 +02:00
Ref < Texture2D > file_icon ;
2020-10-07 21:56:53 +02:00
if ( ! p_is_valid ) {
2021-07-17 23:22:52 +02:00
file_icon = get_theme_icon ( SNAME ( " ImportFail " ) , SNAME ( " EditorIcons " ) ) ;
2018-08-23 17:00:30 +02:00
} else {
2021-07-17 23:22:52 +02:00
file_icon = ( has_theme_icon ( p_file_type , SNAME ( " EditorIcons " ) ) ) ? get_theme_icon ( p_file_type , SNAME ( " EditorIcons " ) ) : get_theme_icon ( SNAME ( " File " ) , SNAME ( " EditorIcons " ) ) ;
2018-08-23 17:00:30 +02:00
}
return file_icon ;
}
2019-11-21 15:40:11 +01:00
bool FileSystemDock : : _create_tree ( TreeItem * p_parent , EditorFileSystemDirectory * p_dir , Vector < String > & uncollapsed_paths , bool p_select_in_favorites , bool p_unfold_path ) {
2018-09-13 21:49:56 +02:00
bool parent_should_expand = false ;
2019-08-22 06:22:52 +02:00
// Create a tree item for the subdirectory.
2018-08-23 17:00:30 +02:00
TreeItem * subdirectory_item = tree - > create_item ( p_parent ) ;
2017-03-05 16:44:50 +01:00
String dname = p_dir - > get_name ( ) ;
2021-12-09 10:42:46 +01:00
if ( dname . is_empty ( ) ) {
2017-03-05 16:44:50 +01:00
dname = " res:// " ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
2018-08-23 17:00:30 +02:00
subdirectory_item - > set_text ( 0 , dname ) ;
2022-04-19 12:27:18 +02:00
subdirectory_item - > set_structured_text_bidi_override ( 0 , TextServer : : STRUCTURED_TEXT_FILE ) ;
2021-07-17 23:22:52 +02:00
subdirectory_item - > set_icon ( 0 , get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) ) ;
2022-09-06 19:09:32 +02:00
subdirectory_item - > set_icon_modulate ( 0 , get_theme_color ( SNAME ( " folder_icon_color " ) , SNAME ( " FileDialog " ) ) ) ;
2018-08-23 17:00:30 +02:00
subdirectory_item - > set_selectable ( 0 , true ) ;
2015-08-24 01:15:56 +02:00
String lpath = p_dir - > get_path ( ) ;
2018-08-23 17:00:30 +02:00
subdirectory_item - > set_metadata ( 0 , lpath ) ;
2023-05-11 04:17:03 +02:00
if ( ! p_select_in_favorites & & ( current_path = = lpath | | ( ( display_mode = = DISPLAY_MODE_SPLIT ) & & current_path . get_base_dir ( ) = = lpath ) ) ) {
2018-08-23 17:00:30 +02:00
subdirectory_item - > select ( 0 ) ;
2021-01-03 12:01:03 +01:00
// Keep select an item when re-created a tree
// To prevent crashing when nothing is selected.
subdirectory_item - > set_as_cursor ( 0 ) ;
2015-08-24 01:15:56 +02:00
}
2023-05-11 04:17:03 +02:00
if ( p_unfold_path & & current_path . begins_with ( lpath ) & & current_path ! = lpath ) {
2019-11-21 15:40:11 +01:00
subdirectory_item - > set_collapsed ( false ) ;
} else {
subdirectory_item - > set_collapsed ( uncollapsed_paths . find ( lpath ) < 0 ) ;
}
2018-09-13 21:49:56 +02:00
if ( searched_string . length ( ) > 0 & & dname . to_lower ( ) . find ( searched_string ) > = 0 ) {
parent_should_expand = true ;
}
2017-09-03 22:35:18 +02:00
2019-08-22 06:22:52 +02:00
// Create items for all subdirectories.
2020-10-22 23:38:41 +02:00
bool reversed = file_sort = = FILE_SORT_NAME_REVERSE ;
for ( int i = reversed ? p_dir - > get_subdir_count ( ) - 1 : 0 ;
reversed ? i > = 0 : i < p_dir - > get_subdir_count ( ) ;
reversed ? i - - : i + + ) {
2019-11-21 15:40:11 +01:00
parent_should_expand = ( _create_tree ( subdirectory_item , p_dir - > get_subdir ( i ) , uncollapsed_paths , p_select_in_favorites , p_unfold_path ) | | parent_should_expand ) ;
2020-05-14 16:41:43 +02:00
}
2018-08-23 17:00:30 +02:00
2019-08-22 06:22:52 +02:00
// Create all items for the files in the subdirectory.
2019-02-25 23:39:49 +01:00
if ( display_mode = = DISPLAY_MODE_TREE_ONLY ) {
2022-10-18 16:43:37 +02:00
String main_scene = GLOBAL_GET ( " application/run/main_scene " ) ;
2020-10-07 21:56:53 +02:00
// Build the list of the files to display.
List < FileInfo > file_list ;
2018-08-23 17:00:30 +02:00
for ( int i = 0 ; i < p_dir - > get_file_count ( ) ; i + + ) {
2019-04-09 00:18:03 +02:00
String file_type = p_dir - > get_file_type ( i ) ;
2021-09-23 23:09:15 +02:00
if ( file_type ! = " TextFile " & & _is_file_type_disabled_by_feature_profile ( file_type ) ) {
2019-08-22 06:22:52 +02:00
// If type is disabled, file won't be displayed.
2019-04-09 00:18:03 +02:00
continue ;
}
2018-08-23 17:00:30 +02:00
2020-10-07 21:56:53 +02:00
String file_name = p_dir - > get_file ( i ) ;
2018-09-13 21:49:56 +02:00
if ( searched_string . length ( ) > 0 ) {
if ( file_name . to_lower ( ) . find ( searched_string ) < 0 ) {
2019-08-22 06:22:52 +02:00
// The searched string is not in the file name, we skip it.
2018-09-13 21:49:56 +02:00
continue ;
} else {
2019-08-22 06:22:52 +02:00
// We expand all parents.
2018-09-13 21:49:56 +02:00
parent_should_expand = true ;
}
}
2020-10-07 21:56:53 +02:00
FileInfo fi ;
fi . name = p_dir - > get_file ( i ) ;
fi . type = p_dir - > get_file_type ( i ) ;
fi . import_broken = ! p_dir - > get_file_import_is_valid ( i ) ;
2020-10-22 23:38:41 +02:00
fi . modified_time = p_dir - > get_file_modified_time ( i ) ;
2020-10-07 21:56:53 +02:00
file_list . push_back ( fi ) ;
}
// Sort the file list if needed.
2020-10-22 23:38:41 +02:00
_sort_file_info_list ( file_list ) ;
2020-10-07 21:56:53 +02:00
// Build the tree.
2021-07-24 15:46:25 +02:00
for ( const FileInfo & fi : file_list ) {
2018-08-23 17:00:30 +02:00
TreeItem * file_item = tree - > create_item ( subdirectory_item ) ;
2020-10-07 21:56:53 +02:00
file_item - > set_text ( 0 , fi . name ) ;
2022-04-19 12:27:18 +02:00
file_item - > set_structured_text_bidi_override ( 0 , TextServer : : STRUCTURED_TEXT_FILE ) ;
2020-10-07 21:56:53 +02:00
file_item - > set_icon ( 0 , _get_tree_item_icon ( ! fi . import_broken , fi . type ) ) ;
2022-08-30 02:34:01 +02:00
String file_metadata = lpath . path_join ( fi . name ) ;
2018-08-23 17:00:30 +02:00
file_item - > set_metadata ( 0 , file_metadata ) ;
2023-05-11 04:17:03 +02:00
if ( ! p_select_in_favorites & & current_path = = file_metadata ) {
2018-08-23 17:00:30 +02:00
file_item - > select ( 0 ) ;
2018-09-13 19:06:40 +02:00
file_item - > set_as_cursor ( 0 ) ;
2018-08-23 17:00:30 +02:00
}
2019-10-29 19:24:38 +01:00
if ( main_scene = = file_metadata ) {
2021-07-17 23:22:52 +02:00
file_item - > set_custom_color ( 0 , get_theme_color ( SNAME ( " accent_color " ) , SNAME ( " Editor " ) ) ) ;
2019-10-29 19:24:38 +01:00
}
2018-09-12 13:10:49 +02:00
Array udata ;
udata . push_back ( tree_update_id ) ;
udata . push_back ( file_item ) ;
EditorResourcePreview : : get_singleton ( ) - > queue_resource_preview ( file_metadata , this , " _tree_thumbnail_done " , udata ) ;
2018-08-23 17:00:30 +02:00
}
2019-12-28 20:07:56 +01:00
} else if ( display_mode = = DISPLAY_MODE_SPLIT ) {
2023-05-11 04:17:03 +02:00
if ( lpath . get_base_dir ( ) = = current_path . get_base_dir ( ) ) {
2019-12-28 20:07:56 +01:00
subdirectory_item - > select ( 0 ) ;
subdirectory_item - > set_as_cursor ( 0 ) ;
}
2018-08-23 17:00:30 +02:00
}
2016-07-08 09:15:31 +02:00
2018-09-13 21:49:56 +02:00
if ( searched_string . length ( ) > 0 ) {
if ( parent_should_expand ) {
subdirectory_item - > set_collapsed ( false ) ;
2018-09-13 23:28:21 +02:00
} else if ( dname ! = " res:// " ) {
2018-09-13 21:49:56 +02:00
subdirectory_item - > get_parent ( ) - > remove_child ( subdirectory_item ) ;
2020-01-15 21:44:43 +01:00
memdelete ( subdirectory_item ) ;
2018-09-13 21:49:56 +02:00
}
}
return parent_should_expand ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 04:17:03 +02:00
Vector < String > FileSystemDock : : get_uncollapsed_paths ( ) const {
2017-09-03 22:35:18 +02:00
Vector < String > uncollapsed_paths ;
2018-09-13 23:28:21 +02:00
TreeItem * root = tree - > get_root ( ) ;
if ( root ) {
2021-03-07 21:07:30 +01:00
TreeItem * favorites_item = root - > get_first_child ( ) ;
2018-09-29 00:11:26 +02:00
if ( ! favorites_item - > is_collapsed ( ) ) {
uncollapsed_paths . push_back ( favorites_item - > get_metadata ( 0 ) ) ;
}
2023-05-11 04:17:03 +02:00
// BFS to find all uncollapsed paths of the resource directory.
TreeItem * res_subtree = root - > get_first_child ( ) - > get_next ( ) ;
if ( res_subtree ) {
List < TreeItem * > queue ;
queue . push_back ( res_subtree ) ;
2018-09-13 23:28:21 +02:00
2023-05-11 04:17:03 +02:00
while ( ! queue . is_empty ( ) ) {
TreeItem * ti = queue . back ( ) - > get ( ) ;
queue . pop_back ( ) ;
if ( ! ti - > is_collapsed ( ) & & ti - > get_child_count ( ) > 0 ) {
Variant path = ti - > get_metadata ( 0 ) ;
if ( path ) {
uncollapsed_paths . push_back ( path ) ;
2017-09-03 22:35:18 +02:00
}
}
2023-05-11 04:17:03 +02:00
for ( int i = 0 ; i < ti - > get_child_count ( ) ; i + + ) {
queue . push_back ( ti - > get_child ( i ) ) ;
}
2017-09-03 22:35:18 +02:00
}
}
}
2018-09-13 23:28:21 +02:00
return uncollapsed_paths ;
}
2019-11-21 15:40:11 +01:00
void FileSystemDock : : _update_tree ( const Vector < String > & p_uncollapsed_paths , bool p_uncollapse_root , bool p_select_in_favorites , bool p_unfold_path ) {
2019-08-22 06:22:52 +02:00
// Recreate the tree.
2014-02-10 02:10:30 +01:00
tree - > clear ( ) ;
2018-09-12 13:10:49 +02:00
tree_update_id + + ;
2017-03-05 16:44:50 +01:00
updating_tree = true ;
2015-08-24 01:15:56 +02:00
TreeItem * root = tree - > create_item ( ) ;
2018-08-23 17:00:30 +02:00
2019-08-22 06:22:52 +02:00
// Handles the favorites.
2022-09-29 11:53:28 +02:00
TreeItem * favorites_item = tree - > create_item ( root ) ;
favorites_item - > set_icon ( 0 , get_theme_icon ( SNAME ( " Favorites " ) , SNAME ( " EditorIcons " ) ) ) ;
favorites_item - > set_text ( 0 , TTR ( " Favorites: " ) ) ;
favorites_item - > set_metadata ( 0 , " Favorites " ) ;
favorites_item - > set_collapsed ( p_uncollapsed_paths . find ( " Favorites " ) < 0 ) ;
2017-09-03 22:35:18 +02:00
2018-09-18 14:02:59 +02:00
Vector < String > favorite_paths = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
2022-03-23 23:28:51 +01:00
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2022-03-23 23:28:51 +01:00
bool fav_changed = false ;
for ( int i = favorite_paths . size ( ) - 1 ; i > = 0 ; i - - ) {
2022-04-06 22:38:16 +02:00
if ( da - > dir_exists ( favorite_paths [ i ] ) | | da - > file_exists ( favorite_paths [ i ] ) ) {
continue ;
2022-03-23 23:28:51 +01:00
}
2022-04-06 22:38:16 +02:00
favorite_paths . remove_at ( i ) ;
fav_changed = true ;
2022-03-23 23:28:51 +01:00
}
if ( fav_changed ) {
EditorSettings : : get_singleton ( ) - > set_favorites ( favorite_paths ) ;
}
2017-09-03 22:35:18 +02:00
for ( int i = 0 ; i < favorite_paths . size ( ) ; i + + ) {
2023-02-01 10:49:05 +01:00
String favorite = favorite_paths [ i ] ;
if ( ! favorite . begins_with ( " res:// " ) ) {
2015-08-24 01:15:56 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
2021-07-17 23:22:52 +02:00
Ref < Texture2D > folder_icon = get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) ;
2022-09-06 19:09:32 +02:00
const Color folder_color = get_theme_color ( SNAME ( " folder_icon_color " ) , SNAME ( " FileDialog " ) ) ;
2018-08-23 17:00:30 +02:00
2018-09-13 21:49:56 +02:00
String text ;
2019-06-11 20:43:37 +02:00
Ref < Texture2D > icon ;
2019-08-20 00:08:40 +02:00
Color color ;
2023-02-01 10:49:05 +01:00
if ( favorite = = " res:// " ) {
2018-09-13 21:49:56 +02:00
text = " / " ;
icon = folder_icon ;
2019-08-20 00:08:40 +02:00
color = folder_color ;
2023-02-01 10:49:05 +01:00
} else if ( favorite . ends_with ( " / " ) ) {
text = favorite . substr ( 0 , favorite . length ( ) - 1 ) . get_file ( ) ;
2018-09-13 21:49:56 +02:00
icon = folder_icon ;
2019-08-20 00:08:40 +02:00
color = folder_color ;
2018-08-23 17:00:30 +02:00
} else {
2023-02-01 10:49:05 +01:00
text = favorite . get_file ( ) ;
2018-08-23 17:00:30 +02:00
int index ;
2023-02-01 10:49:05 +01:00
EditorFileSystemDirectory * dir = EditorFileSystem : : get_singleton ( ) - > find_file ( favorite , & index ) ;
2018-08-23 17:00:30 +02:00
if ( dir ) {
2020-10-07 21:56:53 +02:00
icon = _get_tree_item_icon ( dir - > get_file_import_is_valid ( index ) , dir - > get_file_type ( index ) ) ;
2018-08-23 17:00:30 +02:00
} else {
2021-07-17 23:22:52 +02:00
icon = get_theme_icon ( SNAME ( " File " ) , SNAME ( " EditorIcons " ) ) ;
2018-08-23 17:00:30 +02:00
}
2019-08-20 00:08:40 +02:00
color = Color ( 1 , 1 , 1 ) ;
2018-08-23 17:00:30 +02:00
}
2018-09-13 21:49:56 +02:00
if ( searched_string . length ( ) = = 0 | | text . to_lower ( ) . find ( searched_string ) > = 0 ) {
2022-09-29 11:53:28 +02:00
TreeItem * ti = tree - > create_item ( favorites_item ) ;
2018-09-13 21:49:56 +02:00
ti - > set_text ( 0 , text ) ;
ti - > set_icon ( 0 , icon ) ;
2019-08-24 17:13:48 +02:00
ti - > set_icon_modulate ( 0 , color ) ;
2023-02-01 10:49:05 +01:00
ti - > set_tooltip_text ( 0 , favorite ) ;
2018-09-13 21:49:56 +02:00
ti - > set_selectable ( 0 , true ) ;
2023-02-01 10:49:05 +01:00
ti - > set_metadata ( 0 , favorite ) ;
2023-05-11 04:17:03 +02:00
if ( p_select_in_favorites & & favorite = = current_path ) {
2019-01-17 20:40:38 +01:00
ti - > select ( 0 ) ;
ti - > set_as_cursor ( 0 ) ;
}
2023-02-01 10:49:05 +01:00
if ( ! favorite . ends_with ( " / " ) ) {
2018-09-29 00:11:26 +02:00
Array udata ;
udata . push_back ( tree_update_id ) ;
udata . push_back ( ti ) ;
2023-02-01 10:49:05 +01:00
EditorResourcePreview : : get_singleton ( ) - > queue_resource_preview ( favorite , this , " _tree_thumbnail_done " , udata ) ;
2018-09-29 00:11:26 +02:00
}
2018-09-13 21:49:56 +02:00
}
}
2018-09-13 23:28:21 +02:00
Vector < String > uncollapsed_paths = p_uncollapsed_paths ;
2018-02-01 02:53:31 +01:00
if ( p_uncollapse_root ) {
uncollapsed_paths . push_back ( " res:// " ) ;
}
2019-08-22 06:22:52 +02:00
// Create the remaining of the tree.
2019-11-21 15:40:11 +01:00
_create_tree ( root , EditorFileSystem : : get_singleton ( ) - > get_filesystem ( ) , uncollapsed_paths , p_select_in_favorites , p_unfold_path ) ;
2017-12-16 14:52:51 +01:00
tree - > ensure_cursor_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
updating_tree = false ;
2014-02-10 02:10:30 +01:00
}
2019-02-25 23:39:49 +01:00
void FileSystemDock : : set_display_mode ( DisplayMode p_display_mode ) {
display_mode = p_display_mode ;
_update_display_mode ( false ) ;
}
2018-10-22 10:31:50 +02:00
void FileSystemDock : : _update_display_mode ( bool p_force ) {
2019-08-22 06:22:52 +02:00
// Compute the new display mode.
2019-02-25 23:39:49 +01:00
if ( p_force | | old_display_mode ! = display_mode ) {
2019-06-26 15:08:25 +02:00
button_toggle_display_mode - > set_pressed ( display_mode = = DISPLAY_MODE_SPLIT ) ;
2018-09-14 13:59:19 +02:00
switch ( display_mode ) {
2018-09-13 17:35:44 +02:00
case DISPLAY_MODE_TREE_ONLY :
2018-08-13 19:05:31 +02:00
tree - > show ( ) ;
tree - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2019-02-25 23:39:49 +01:00
if ( display_mode = = DISPLAY_MODE_TREE_ONLY ) {
2020-10-07 21:56:53 +02:00
toolbar2_hbc - > show ( ) ;
2018-09-13 21:49:56 +02:00
} else {
2020-10-07 21:56:53 +02:00
toolbar2_hbc - > hide ( ) ;
2018-09-13 21:49:56 +02:00
}
2016-05-16 01:25:51 +02:00
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2018-08-13 19:05:31 +02:00
file_list_vb - > hide ( ) ;
break ;
2016-05-16 01:25:51 +02:00
2018-09-13 17:35:44 +02:00
case DISPLAY_MODE_SPLIT :
2018-08-13 19:05:31 +02:00
tree - > show ( ) ;
tree - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
tree - > ensure_cursor_is_visible ( ) ;
2020-10-07 21:56:53 +02:00
toolbar2_hbc - > hide ( ) ;
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2016-05-16 01:25:51 +02:00
2018-08-13 19:05:31 +02:00
file_list_vb - > show ( ) ;
2018-09-28 13:26:36 +02:00
_update_file_list ( true ) ;
2018-08-13 19:05:31 +02:00
break ;
}
2019-02-25 23:39:49 +01:00
old_display_mode = display_mode ;
2018-08-13 19:05:31 +02:00
}
}
2016-05-16 01:25:51 +02:00
2018-08-13 19:05:31 +02:00
void FileSystemDock : : _notification ( int p_what ) {
switch ( p_what ) {
2020-09-03 13:22:16 +02:00
case NOTIFICATION_TRANSLATION_CHANGED :
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED :
2014-11-06 01:20:42 +01:00
case NOTIFICATION_ENTER_TREE : {
2020-05-14 16:41:43 +02:00
if ( initialized ) {
2015-08-24 01:15:56 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-03-05 16:44:50 +01:00
initialized = true ;
2020-02-21 18:28:45 +01:00
EditorFeatureProfileManager : : get_singleton ( ) - > connect ( " current_feature_profile_changed " , callable_mp ( this , & FileSystemDock : : _feature_profile_changed ) ) ;
2014-02-10 02:10:30 +01:00
2020-02-21 18:28:45 +01:00
EditorFileSystem : : get_singleton ( ) - > connect ( " filesystem_changed " , callable_mp ( this , & FileSystemDock : : _fs_changed ) ) ;
EditorResourcePreview : : get_singleton ( ) - > connect ( " preview_invalidated " , callable_mp ( this , & FileSystemDock : : _preview_invalidated ) ) ;
2014-02-10 02:10:30 +01:00
2022-02-06 14:12:19 +01:00
button_reload - > set_icon ( get_theme_icon ( SNAME ( " Reload " ) , SNAME ( " EditorIcons " ) ) ) ;
button_toggle_display_mode - > set_icon ( get_theme_icon ( SNAME ( " Panels2 " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-02-21 18:28:45 +01:00
button_file_list_display_mode - > connect ( " pressed " , callable_mp ( this , & FileSystemDock : : _toggle_file_display ) ) ;
2018-09-14 00:16:43 +02:00
2020-02-21 18:28:45 +01:00
files - > connect ( " item_activated " , callable_mp ( this , & FileSystemDock : : _file_list_activate_file ) ) ;
button_hist_next - > connect ( " pressed " , callable_mp ( this , & FileSystemDock : : _fw_history ) ) ;
button_hist_prev - > connect ( " pressed " , callable_mp ( this , & FileSystemDock : : _bw_history ) ) ;
2020-10-07 21:56:53 +02:00
2022-02-06 14:12:19 +01:00
tree_search_box - > set_right_icon ( get_theme_icon ( SNAME ( " Search " ) , SNAME ( " EditorIcons " ) ) ) ;
2018-09-13 21:49:56 +02:00
tree_search_box - > set_clear_button_enabled ( true ) ;
2022-02-06 14:12:19 +01:00
tree_button_sort - > set_icon ( get_theme_icon ( SNAME ( " Sort " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-10-07 21:56:53 +02:00
2022-02-06 14:12:19 +01:00
file_list_search_box - > set_right_icon ( get_theme_icon ( SNAME ( " Search " ) , SNAME ( " EditorIcons " ) ) ) ;
2018-09-13 21:49:56 +02:00
file_list_search_box - > set_clear_button_enabled ( true ) ;
2022-02-06 14:12:19 +01:00
file_list_button_sort - > set_icon ( get_theme_icon ( SNAME ( " Sort " ) , SNAME ( " EditorIcons " ) ) ) ;
2017-03-05 16:44:50 +01:00
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
2022-02-06 14:12:19 +01:00
button_hist_next - > set_icon ( get_theme_icon ( SNAME ( " Back " ) , SNAME ( " EditorIcons " ) ) ) ;
button_hist_prev - > set_icon ( get_theme_icon ( SNAME ( " Forward " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-02-06 14:12:19 +01:00
button_hist_next - > set_icon ( get_theme_icon ( SNAME ( " Forward " ) , SNAME ( " EditorIcons " ) ) ) ;
button_hist_prev - > set_icon ( get_theme_icon ( SNAME ( " Back " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-09-03 13:22:16 +02:00
}
2020-02-21 18:28:45 +01:00
file_list_popup - > connect ( " id_pressed " , callable_mp ( this , & FileSystemDock : : _file_list_rmb_option ) ) ;
tree_popup - > connect ( " id_pressed " , callable_mp ( this , & FileSystemDock : : _tree_rmb_option ) ) ;
2017-03-05 16:44:50 +01:00
2023-05-11 04:17:03 +02:00
current_path_line_edit - > connect ( " text_submitted " , callable_mp ( this , & FileSystemDock : : _navigate_to_path ) . bind ( false ) ) ;
2014-02-10 02:10:30 +01:00
2022-10-18 16:43:37 +02:00
always_show_folders = bool ( EDITOR_GET ( " docks/filesystem/always_show_folders " ) ) ;
2018-08-23 17:00:30 +02:00
2019-03-03 00:12:02 +01:00
set_file_list_display_mode ( FileSystemDock : : FILE_LIST_DISPLAY_LIST ) ;
2018-09-21 09:42:41 +02:00
_update_display_mode ( ) ;
2015-08-24 01:15:56 +02:00
if ( EditorFileSystem : : get_singleton ( ) - > is_scanning ( ) ) {
2017-01-21 13:07:29 +01:00
_set_scanning_mode ( ) ;
2017-09-03 22:35:18 +02:00
} else {
2018-09-13 23:28:21 +02:00
_update_tree ( Vector < String > ( ) , true ) ;
2014-02-10 02:10:30 +01:00
}
2015-08-24 01:15:56 +02:00
} break ;
2019-08-22 06:22:52 +02:00
2015-08-24 01:15:56 +02:00
case NOTIFICATION_PROCESS : {
if ( EditorFileSystem : : get_singleton ( ) - > is_scanning ( ) ) {
2017-03-05 16:44:50 +01:00
scanning_progress - > set_value ( EditorFileSystem : : get_singleton ( ) - > get_scanning_progress ( ) * 100 ) ;
2015-08-24 01:15:56 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
2016-05-16 01:25:51 +02:00
case NOTIFICATION_DRAG_BEGIN : {
Dictionary dd = get_viewport ( ) - > gui_get_drag_data ( ) ;
2017-03-05 16:44:50 +01:00
if ( tree - > is_visible_in_tree ( ) & & dd . has ( " type " ) ) {
2019-10-20 19:39:21 +02:00
if ( dd . has ( " favorite " ) ) {
2020-05-14 16:41:43 +02:00
if ( ( String ( dd [ " favorite " ] ) = = " all " ) ) {
2019-10-20 19:39:21 +02:00
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_INBETWEEN ) ;
2020-05-14 16:41:43 +02:00
}
2019-10-20 19:39:21 +02:00
} else if ( ( String ( dd [ " type " ] ) = = " files " ) | | ( String ( dd [ " type " ] ) = = " files_and_dirs " ) | | ( String ( dd [ " type " ] ) = = " resource " ) ) {
2018-08-23 17:00:30 +02:00
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_ON_ITEM | Tree : : DROP_MODE_INBETWEEN ) ;
2022-03-03 21:36:56 +01:00
} else if ( ( String ( dd [ " type " ] ) = = " nodes " ) ) {
holding_branch = true ;
TreeItem * item = tree - > get_next_selected ( tree - > get_root ( ) ) ;
while ( item ) {
tree_items_selected_on_drag_begin . push_back ( item ) ;
item = tree - > get_next_selected ( item ) ;
}
list_items_selected_on_drag_begin = files - > get_selected_items ( ) ;
2016-05-24 04:24:17 +02:00
}
2016-05-16 01:25:51 +02:00
}
} break ;
2019-08-22 06:22:52 +02:00
case NOTIFICATION_DRAG_END : {
2016-05-16 01:25:51 +02:00
tree - > set_drop_mode_flags ( 0 ) ;
2022-03-03 21:36:56 +01:00
if ( holding_branch ) {
holding_branch = false ;
_reselect_items_selected_on_drag_begin ( true ) ;
}
2014-02-10 02:10:30 +01:00
} break ;
2019-08-22 06:22:52 +02:00
2018-10-22 10:31:50 +02:00
case NOTIFICATION_THEME_CHANGED : {
2023-05-18 00:09:44 +02:00
overwrite_dialog_scroll - > add_theme_style_override ( " panel " , get_theme_stylebox ( " panel " , " Tree " ) ) ;
2018-10-29 14:20:31 +01:00
if ( is_visible_in_tree ( ) ) {
2018-10-25 12:20:45 +02:00
_update_display_mode ( true ) ;
}
2018-10-22 10:31:50 +02:00
} break ;
2019-08-22 06:22:52 +02:00
2015-12-15 17:39:13 +01:00
case EditorSettings : : NOTIFICATION_EDITOR_SETTINGS_CHANGED : {
2019-08-22 06:22:52 +02:00
// Update icons.
2022-02-06 14:12:19 +01:00
button_reload - > set_icon ( get_theme_icon ( SNAME ( " Reload " ) , SNAME ( " EditorIcons " ) ) ) ;
button_toggle_display_mode - > set_icon ( get_theme_icon ( SNAME ( " Panels2 " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
2022-02-06 14:12:19 +01:00
button_hist_next - > set_icon ( get_theme_icon ( SNAME ( " Back " ) , SNAME ( " EditorIcons " ) ) ) ;
button_hist_prev - > set_icon ( get_theme_icon ( SNAME ( " Forward " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-02-06 14:12:19 +01:00
button_hist_next - > set_icon ( get_theme_icon ( SNAME ( " Forward " ) , SNAME ( " EditorIcons " ) ) ) ;
button_hist_prev - > set_icon ( get_theme_icon ( SNAME ( " Back " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-09-03 13:22:16 +02:00
}
2019-03-05 19:05:53 +01:00
if ( file_list_display_mode = = FILE_LIST_DISPLAY_LIST ) {
2021-07-17 23:22:52 +02:00
button_file_list_display_mode - > set_icon ( get_theme_icon ( SNAME ( " FileThumbnail " ) , SNAME ( " EditorIcons " ) ) ) ;
2018-10-22 10:31:50 +02:00
} else {
2021-07-17 23:22:52 +02:00
button_file_list_display_mode - > set_icon ( get_theme_icon ( SNAME ( " FileList " ) , SNAME ( " EditorIcons " ) ) ) ;
2018-10-22 10:31:50 +02:00
}
2017-08-30 01:03:13 +02:00
2022-02-06 14:12:19 +01:00
tree_search_box - > set_right_icon ( get_theme_icon ( SNAME ( " Search " ) , SNAME ( " EditorIcons " ) ) ) ;
2018-09-13 21:49:56 +02:00
tree_search_box - > set_clear_button_enabled ( true ) ;
2022-02-06 14:12:19 +01:00
tree_button_sort - > set_icon ( get_theme_icon ( SNAME ( " Sort " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-10-07 21:56:53 +02:00
2022-02-06 14:12:19 +01:00
file_list_search_box - > set_right_icon ( get_theme_icon ( SNAME ( " Search " ) , SNAME ( " EditorIcons " ) ) ) ;
2018-09-13 21:49:56 +02:00
file_list_search_box - > set_clear_button_enabled ( true ) ;
2022-02-06 14:12:19 +01:00
file_list_button_sort - > set_icon ( get_theme_icon ( SNAME ( " Sort " ) , SNAME ( " EditorIcons " ) ) ) ;
2017-08-30 01:03:13 +02:00
2019-08-22 06:22:52 +02:00
// Update always show folders.
2022-10-18 16:43:37 +02:00
bool new_always_show_folders = bool ( EDITOR_GET ( " docks/filesystem/always_show_folders " ) ) ;
2018-08-23 17:00:30 +02:00
if ( new_always_show_folders ! = always_show_folders ) {
always_show_folders = new_always_show_folders ;
2018-09-28 13:26:36 +02:00
_update_file_list ( true ) ;
2018-08-23 17:00:30 +02:00
}
2019-08-22 06:22:52 +02:00
// Change full tree mode.
2018-08-13 19:05:31 +02:00
_update_display_mode ( ) ;
2015-12-15 17:39:13 +01:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
2018-08-23 17:00:30 +02:00
void FileSystemDock : : _tree_multi_selected ( Object * p_item , int p_column , bool p_selected ) {
2019-08-22 06:22:52 +02:00
// Update the import dock.
2018-09-24 14:26:26 +02:00
import_dock_needs_update = true ;
2021-07-17 23:22:52 +02:00
call_deferred ( SNAME ( " _update_import_dock " ) ) ;
2015-08-24 01:15:56 +02:00
2019-08-22 06:22:52 +02:00
// Return if we don't select something new.
2020-05-14 16:41:43 +02:00
if ( ! p_selected ) {
2018-08-23 17:00:30 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-08-23 17:00:30 +02:00
2019-08-22 06:22:52 +02:00
// Tree item selected.
2018-09-29 00:11:26 +02:00
TreeItem * selected = tree - > get_selected ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! selected ) {
2018-08-23 17:00:30 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-09-29 00:11:26 +02:00
2021-03-07 21:07:30 +01:00
TreeItem * favorites_item = tree - > get_root ( ) - > get_first_child ( ) ;
2018-10-19 22:43:48 +02:00
if ( selected - > get_parent ( ) = = favorites_item & & ! String ( selected - > get_metadata ( 0 ) ) . ends_with ( " / " ) ) {
2019-08-22 06:22:52 +02:00
// Go to the favorites if we click in the favorites and the path has changed.
2023-05-11 04:17:03 +02:00
current_path = " Favorites " ;
2018-09-29 00:11:26 +02:00
} else {
2023-05-11 04:17:03 +02:00
current_path = selected - > get_metadata ( 0 ) ;
2019-08-22 06:22:52 +02:00
// Note: the "Favorites" item also leads to this path.
2018-09-29 00:11:26 +02:00
}
2018-08-23 17:00:30 +02:00
2023-05-11 04:17:03 +02:00
// Display the current path.
_set_current_path_line_edit_text ( current_path ) ;
2017-09-03 22:35:18 +02:00
_push_to_history ( ) ;
2016-05-16 01:25:51 +02:00
2019-08-22 06:22:52 +02:00
// Update the file list.
2018-09-13 17:35:44 +02:00
if ( ! updating_tree & & display_mode = = DISPLAY_MODE_SPLIT ) {
2018-09-28 13:26:36 +02:00
_update_file_list ( false ) ;
2015-08-24 01:15:56 +02:00
}
}
2022-05-10 22:25:36 +02:00
Vector < String > FileSystemDock : : get_selected_paths ( ) const {
return _tree_get_selected ( false ) ;
}
String FileSystemDock : : get_current_path ( ) const {
2023-05-11 04:17:03 +02:00
return current_path ;
2022-05-10 22:25:36 +02:00
}
String FileSystemDock : : get_current_directory ( ) const {
2023-05-11 04:17:03 +02:00
if ( current_path . ends_with ( " / " ) ) {
return current_path ;
2020-05-14 16:41:43 +02:00
} else {
2023-05-11 04:17:03 +02:00
return current_path . get_base_dir ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-05-11 04:17:03 +02:00
void FileSystemDock : : _set_current_path_line_edit_text ( const String & p_path ) {
2018-09-29 00:11:26 +02:00
if ( p_path = = " Favorites " ) {
2023-05-11 04:17:03 +02:00
current_path_line_edit - > set_text ( TTR ( " Favorites " ) ) ;
2018-09-29 00:11:26 +02:00
} else {
2023-05-11 04:17:03 +02:00
current_path_line_edit - > set_text ( current_path ) ;
2018-09-29 00:11:26 +02:00
}
}
2019-01-17 20:40:38 +01:00
void FileSystemDock : : _navigate_to_path ( const String & p_path , bool p_select_in_favorites ) {
2018-09-29 00:11:26 +02:00
if ( p_path = = " Favorites " ) {
2023-05-11 04:17:03 +02:00
current_path = p_path ;
2017-01-14 18:14:46 +01:00
} else {
2018-09-29 00:11:26 +02:00
String target_path = p_path ;
// If the path is a file, do not only go to the directory in the tree, also select the file in the file list.
if ( target_path . ends_with ( " / " ) ) {
target_path = target_path . substr ( 0 , target_path . length ( ) - 1 ) ;
}
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2022-03-10 15:27:09 +01:00
if ( da - > file_exists ( p_path ) ) {
2023-05-11 04:17:03 +02:00
current_path = target_path ;
2022-03-10 15:27:09 +01:00
} else if ( da - > dir_exists ( p_path ) ) {
2023-05-11 04:17:03 +02:00
current_path = target_path + " / " ;
2018-09-29 00:11:26 +02:00
} else {
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( vformat ( " Cannot navigate to '%s' as it has not been found in the file system! " , p_path ) ) ;
2018-09-29 00:11:26 +02:00
}
2017-01-14 18:14:46 +01:00
}
2023-05-11 04:17:03 +02:00
_set_current_path_line_edit_text ( current_path ) ;
2017-09-03 22:35:18 +02:00
_push_to_history ( ) ;
2017-01-14 18:14:46 +01:00
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) , false , p_select_in_favorites , true ) ;
2018-09-13 17:35:44 +02:00
if ( display_mode = = DISPLAY_MODE_SPLIT ) {
2018-09-28 13:26:36 +02:00
_update_file_list ( false ) ;
2021-11-30 17:46:36 +01:00
files - > get_v_scroll_bar ( ) - > set_value ( 0 ) ;
2017-09-03 22:35:18 +02:00
}
2017-01-14 18:14:46 +01:00
2018-08-23 17:00:30 +02:00
String file_name = p_path . get_file ( ) ;
2020-12-15 13:04:21 +01:00
if ( ! file_name . is_empty ( ) ) {
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < files - > get_item_count ( ) ; i + + ) {
2017-01-14 18:14:46 +01:00
if ( files - > get_item_text ( i ) = = file_name ) {
2017-03-05 16:44:50 +01:00
files - > select ( i , true ) ;
2017-01-14 18:14:46 +01:00
files - > ensure_current_is_visible ( ) ;
break ;
}
}
}
}
2019-01-17 20:40:38 +01:00
void FileSystemDock : : navigate_to_path ( const String & p_path ) {
2019-09-25 13:14:45 +02:00
file_list_search_box - > clear ( ) ;
2019-01-17 20:40:38 +01:00
_navigate_to_path ( p_path ) ;
}
2019-06-11 20:43:37 +02:00
void FileSystemDock : : _file_list_thumbnail_done ( const String & p_path , const Ref < Texture2D > & p_preview , const Ref < Texture2D > & p_small_preview , const Variant & p_udata ) {
2023-05-11 04:17:03 +02:00
if ( ( file_list_vb - > is_visible_in_tree ( ) | | current_path = = p_path . get_base_dir ( ) ) & & p_preview . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
Array uarr = p_udata ;
int idx = uarr [ 0 ] ;
String file = uarr [ 1 ] ;
2018-09-28 13:26:36 +02:00
if ( idx < files - > get_item_count ( ) & & files - > get_item_text ( idx ) = = file & & files - > get_item_metadata ( idx ) = = p_path ) {
if ( file_list_display_mode = = FILE_LIST_DISPLAY_LIST ) {
2020-05-14 16:41:43 +02:00
if ( p_small_preview . is_valid ( ) ) {
2018-09-28 13:26:36 +02:00
files - > set_item_icon ( idx , p_small_preview ) ;
2020-05-14 16:41:43 +02:00
}
2018-09-28 13:26:36 +02:00
} else {
files - > set_item_icon ( idx , p_preview ) ;
}
}
2015-08-24 01:15:56 +02:00
}
}
2019-06-11 20:43:37 +02:00
void FileSystemDock : : _tree_thumbnail_done ( const String & p_path , const Ref < Texture2D > & p_preview , const Ref < Texture2D > & p_small_preview , const Variant & p_udata ) {
2018-09-12 13:10:49 +02:00
if ( p_small_preview . is_valid ( ) ) {
Array uarr = p_udata ;
if ( tree_update_id = = ( int ) uarr [ 0 ] ) {
TreeItem * file_item = Object : : cast_to < TreeItem > ( uarr [ 1 ] ) ;
if ( file_item ) {
file_item - > set_icon ( 0 , p_small_preview ) ;
}
}
}
}
2019-03-05 07:55:08 +01:00
void FileSystemDock : : _toggle_file_display ( ) {
_set_file_display ( file_list_display_mode ! = FILE_LIST_DISPLAY_LIST ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " display_mode_changed " ) ) ;
2019-02-27 21:36:12 +01:00
}
2015-08-24 01:15:56 +02:00
2019-02-27 21:36:12 +01:00
void FileSystemDock : : _set_file_display ( bool p_active ) {
if ( p_active ) {
2018-08-13 19:05:31 +02:00
file_list_display_mode = FILE_LIST_DISPLAY_LIST ;
2021-07-17 23:22:52 +02:00
button_file_list_display_mode - > set_icon ( get_theme_icon ( SNAME ( " FileThumbnail " ) , SNAME ( " EditorIcons " ) ) ) ;
2022-08-25 12:42:17 +02:00
button_file_list_display_mode - > set_tooltip_text ( TTR ( " View items as a grid of thumbnails. " ) ) ;
2015-08-24 01:15:56 +02:00
} else {
2018-08-13 19:05:31 +02:00
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS ;
2021-07-17 23:22:52 +02:00
button_file_list_display_mode - > set_icon ( get_theme_icon ( SNAME ( " FileList " ) , SNAME ( " EditorIcons " ) ) ) ;
2022-08-25 12:42:17 +02:00
button_file_list_display_mode - > set_tooltip_text ( TTR ( " View items as a list. " ) ) ;
2015-08-24 01:15:56 +02:00
}
2016-08-16 18:25:42 +02:00
2018-09-28 13:26:36 +02:00
_update_file_list ( true ) ;
2015-08-24 01:15:56 +02:00
}
2019-04-09 00:18:03 +02:00
bool FileSystemDock : : _is_file_type_disabled_by_feature_profile ( const StringName & p_class ) {
Ref < EditorFeatureProfile > profile = EditorFeatureProfileManager : : get_singleton ( ) - > get_current_profile ( ) ;
if ( profile . is_null ( ) ) {
return false ;
}
StringName class_name = p_class ;
while ( class_name ! = StringName ( ) ) {
if ( profile - > is_class_disabled ( class_name ) ) {
return true ;
}
class_name = ClassDB : : get_parent_class ( class_name ) ;
}
return false ;
}
2017-03-05 16:44:50 +01:00
void FileSystemDock : : _search ( EditorFileSystemDirectory * p_path , List < FileInfo > * matches , int p_max_items ) {
2020-05-14 16:41:43 +02:00
if ( matches - > size ( ) > p_max_items ) {
2016-05-16 01:25:51 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-05-16 01:25:51 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_path - > get_subdir_count ( ) ; i + + ) {
_search ( p_path - > get_subdir ( i ) , matches , p_max_items ) ;
2016-05-16 01:25:51 +02:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_path - > get_file_count ( ) ; i + + ) {
2016-05-16 01:25:51 +02:00
String file = p_path - > get_file ( i ) ;
2022-02-03 17:03:38 +01:00
if ( file . to_lower ( ) . contains ( searched_string ) ) {
2016-05-16 01:25:51 +02:00
FileInfo fi ;
2017-03-05 16:44:50 +01:00
fi . name = file ;
fi . type = p_path - > get_file_type ( i ) ;
fi . path = p_path - > get_file_path ( i ) ;
2017-08-30 01:17:34 +02:00
fi . import_broken = ! p_path - > get_file_import_is_valid ( i ) ;
2020-10-22 23:38:41 +02:00
fi . modified_time = p_path - > get_file_modified_time ( i ) ;
2016-05-27 19:18:40 +02:00
2019-04-09 00:18:03 +02:00
if ( _is_file_type_disabled_by_feature_profile ( fi . type ) ) {
2019-08-22 06:22:52 +02:00
// This type is disabled, will not appear here.
2019-04-09 00:18:03 +02:00
continue ;
}
2016-05-16 01:25:51 +02:00
matches - > push_back ( fi ) ;
2020-05-14 16:41:43 +02:00
if ( matches - > size ( ) > p_max_items ) {
2016-05-16 01:25:51 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-05-16 01:25:51 +02:00
}
}
}
2020-10-22 23:38:41 +02:00
struct FileSystemDock : : FileInfoTypeComparator {
bool operator ( ) ( const FileInfo & p_a , const FileInfo & p_b ) const {
// Uses the extension, then the icon name to distinguish file types.
String icon_path_a = " " ;
String icon_path_b = " " ;
Ref < Texture2D > icon_a = EditorNode : : get_singleton ( ) - > get_class_icon ( p_a . type ) ;
if ( icon_a . is_valid ( ) ) {
icon_path_a = icon_a - > get_name ( ) ;
}
Ref < Texture2D > icon_b = EditorNode : : get_singleton ( ) - > get_class_icon ( p_b . type ) ;
if ( icon_b . is_valid ( ) ) {
icon_path_b = icon_b - > get_name ( ) ;
}
return NaturalNoCaseComparator ( ) ( p_a . name . get_extension ( ) + icon_path_a + p_a . name . get_basename ( ) , p_b . name . get_extension ( ) + icon_path_b + p_b . name . get_basename ( ) ) ;
}
} ;
struct FileSystemDock : : FileInfoModifiedTimeComparator {
bool operator ( ) ( const FileInfo & p_a , const FileInfo & p_b ) const {
return p_a . modified_time > p_b . modified_time ;
}
} ;
void FileSystemDock : : _sort_file_info_list ( List < FileSystemDock : : FileInfo > & r_file_list ) {
// Sort the file list if needed.
switch ( file_sort ) {
case FILE_SORT_TYPE :
r_file_list . sort_custom < FileInfoTypeComparator > ( ) ;
break ;
case FILE_SORT_TYPE_REVERSE :
r_file_list . sort_custom < FileInfoTypeComparator > ( ) ;
2021-03-14 08:21:32 +01:00
r_file_list . reverse ( ) ;
2020-10-22 23:38:41 +02:00
break ;
case FILE_SORT_MODIFIED_TIME :
r_file_list . sort_custom < FileInfoModifiedTimeComparator > ( ) ;
break ;
case FILE_SORT_MODIFIED_TIME_REVERSE :
r_file_list . sort_custom < FileInfoModifiedTimeComparator > ( ) ;
2021-03-14 08:21:32 +01:00
r_file_list . reverse ( ) ;
2020-10-22 23:38:41 +02:00
break ;
case FILE_SORT_NAME_REVERSE :
2021-10-23 09:51:26 +02:00
r_file_list . sort ( ) ;
2021-03-14 08:21:32 +01:00
r_file_list . reverse ( ) ;
2020-10-22 23:38:41 +02:00
break ;
default : // FILE_SORT_NAME
2021-10-23 09:51:26 +02:00
r_file_list . sort ( ) ;
2020-10-22 23:38:41 +02:00
break ;
}
}
2018-09-28 13:26:36 +02:00
void FileSystemDock : : _update_file_list ( bool p_keep_selection ) {
2019-08-22 06:22:52 +02:00
// Register the previously selected items.
2022-05-19 17:00:06 +02:00
HashSet < String > cselection ;
2015-08-24 01:15:56 +02:00
if ( p_keep_selection ) {
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < files - > get_item_count ( ) ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( files - > is_selected ( i ) ) {
2015-08-24 01:15:56 +02:00
cselection . insert ( files - > get_item_text ( i ) ) ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
}
}
files - > clear ( ) ;
2023-05-11 04:17:03 +02:00
_set_current_path_line_edit_text ( current_path ) ;
2016-05-16 01:25:51 +02:00
2023-05-11 04:17:03 +02:00
String directory = current_path ;
2018-08-23 17:00:30 +02:00
String file = " " ;
2015-08-24 01:15:56 +02:00
2022-10-18 16:43:37 +02:00
int thumbnail_size = EDITOR_GET ( " docks/filesystem/thumbnail_size " ) ;
2017-03-05 16:44:50 +01:00
thumbnail_size * = EDSCALE ;
2019-06-11 20:43:37 +02:00
Ref < Texture2D > folder_thumbnail ;
Ref < Texture2D > file_thumbnail ;
Ref < Texture2D > file_thumbnail_broken ;
2015-08-24 01:15:56 +02:00
2018-08-13 19:05:31 +02:00
bool use_thumbnails = ( file_list_display_mode = = FILE_LIST_DISPLAY_THUMBNAILS ) ;
2015-08-24 01:15:56 +02:00
2017-09-03 22:35:18 +02:00
if ( use_thumbnails ) {
2019-08-22 06:22:52 +02:00
// Thumbnails mode.
2015-08-24 01:15:56 +02:00
files - > set_max_columns ( 0 ) ;
files - > set_icon_mode ( ItemList : : ICON_MODE_TOP ) ;
2017-03-05 16:44:50 +01:00
files - > set_fixed_column_width ( thumbnail_size * 3 / 2 ) ;
2015-08-24 01:15:56 +02:00
files - > set_max_text_lines ( 2 ) ;
2017-03-05 16:44:50 +01:00
files - > set_fixed_icon_size ( Size2 ( thumbnail_size , thumbnail_size ) ) ;
2015-08-24 01:15:56 +02:00
2017-09-08 09:32:43 +02:00
if ( thumbnail_size < 64 ) {
2022-02-06 14:12:19 +01:00
folder_thumbnail = get_theme_icon ( SNAME ( " FolderMediumThumb " ) , SNAME ( " EditorIcons " ) ) ;
file_thumbnail = get_theme_icon ( SNAME ( " FileMediumThumb " ) , SNAME ( " EditorIcons " ) ) ;
file_thumbnail_broken = get_theme_icon ( SNAME ( " FileDeadMediumThumb " ) , SNAME ( " EditorIcons " ) ) ;
2017-09-08 09:32:43 +02:00
} else {
2022-02-06 14:12:19 +01:00
folder_thumbnail = get_theme_icon ( SNAME ( " FolderBigThumb " ) , SNAME ( " EditorIcons " ) ) ;
file_thumbnail = get_theme_icon ( SNAME ( " FileBigThumb " ) , SNAME ( " EditorIcons " ) ) ;
file_thumbnail_broken = get_theme_icon ( SNAME ( " FileDeadBigThumb " ) , SNAME ( " EditorIcons " ) ) ;
2015-08-24 01:15:56 +02:00
}
} else {
2019-08-22 06:22:52 +02:00
// No thumbnails.
2015-08-24 01:15:56 +02:00
files - > set_icon_mode ( ItemList : : ICON_MODE_LEFT ) ;
files - > set_max_columns ( 1 ) ;
files - > set_max_text_lines ( 1 ) ;
files - > set_fixed_column_width ( 0 ) ;
2016-06-12 21:51:27 +02:00
files - > set_fixed_icon_size ( Size2 ( ) ) ;
2014-10-15 00:44:41 +02:00
}
2014-02-10 02:10:30 +01:00
2021-07-17 23:22:52 +02:00
Ref < Texture2D > folder_icon = ( use_thumbnails ) ? folder_thumbnail : get_theme_icon ( SNAME ( " folder " ) , SNAME ( " FileDialog " ) ) ;
2022-09-06 19:09:32 +02:00
const Color folder_color = get_theme_color ( SNAME ( " folder_icon_color " ) , SNAME ( " FileDialog " ) ) ;
2014-02-10 02:10:30 +01:00
2019-08-22 06:22:52 +02:00
// Build the FileInfo list.
2020-10-07 21:56:53 +02:00
List < FileInfo > file_list ;
2023-05-11 04:17:03 +02:00
if ( current_path = = " Favorites " ) {
2019-08-22 06:22:52 +02:00
// Display the favorites.
2022-09-29 11:53:28 +02:00
Vector < String > favorites_list = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
for ( const String & favorite : favorites_list ) {
2018-09-29 00:11:26 +02:00
String text ;
2019-06-11 20:43:37 +02:00
Ref < Texture2D > icon ;
2018-09-29 00:11:26 +02:00
if ( favorite = = " res:// " ) {
text = " / " ;
icon = folder_icon ;
if ( searched_string . length ( ) = = 0 | | text . to_lower ( ) . find ( searched_string ) > = 0 ) {
files - > add_item ( text , icon , true ) ;
2022-03-12 01:06:45 +01:00
files - > set_item_metadata ( - 1 , favorite ) ;
2018-09-29 00:11:26 +02:00
}
} else if ( favorite . ends_with ( " / " ) ) {
text = favorite . substr ( 0 , favorite . length ( ) - 1 ) . get_file ( ) ;
icon = folder_icon ;
if ( searched_string . length ( ) = = 0 | | text . to_lower ( ) . find ( searched_string ) > = 0 ) {
files - > add_item ( text , icon , true ) ;
2022-03-12 01:06:45 +01:00
files - > set_item_metadata ( - 1 , favorite ) ;
2018-09-29 00:11:26 +02:00
}
} else {
int index ;
EditorFileSystemDirectory * efd = EditorFileSystem : : get_singleton ( ) - > find_file ( favorite , & index ) ;
FileInfo fi ;
fi . name = favorite . get_file ( ) ;
fi . path = favorite ;
if ( efd ) {
fi . type = efd - > get_file_type ( index ) ;
fi . import_broken = ! efd - > get_file_import_is_valid ( index ) ;
2020-10-22 23:38:41 +02:00
fi . modified_time = efd - > get_file_modified_time ( index ) ;
2018-09-29 00:11:26 +02:00
} else {
fi . type = " " ;
fi . import_broken = true ;
2020-10-22 23:38:41 +02:00
fi . modified_time = 0 ;
2018-09-29 00:11:26 +02:00
}
2016-05-16 01:25:51 +02:00
2018-09-29 00:11:26 +02:00
if ( searched_string . length ( ) = = 0 | | fi . name . to_lower ( ) . find ( searched_string ) > = 0 ) {
2020-10-07 21:56:53 +02:00
file_list . push_back ( fi ) ;
2018-09-29 00:11:26 +02:00
}
}
}
} else {
2019-08-22 06:22:52 +02:00
// Get infos on the directory + file.
2018-09-29 00:11:26 +02:00
if ( directory . ends_with ( " / " ) & & directory ! = " res:// " ) {
directory = directory . substr ( 0 , directory . length ( ) - 1 ) ;
}
EditorFileSystemDirectory * efd = EditorFileSystem : : get_singleton ( ) - > get_filesystem_path ( directory ) ;
if ( ! efd ) {
2023-05-11 04:17:03 +02:00
directory = current_path . get_base_dir ( ) ;
file = current_path . get_file ( ) ;
2018-09-29 00:11:26 +02:00
efd = EditorFileSystem : : get_singleton ( ) - > get_filesystem_path ( directory ) ;
2015-08-24 01:15:56 +02:00
}
2020-05-14 16:41:43 +02:00
if ( ! efd ) {
2018-09-29 00:11:26 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
2018-09-29 00:11:26 +02:00
if ( searched_string . length ( ) > 0 ) {
2019-08-22 06:22:52 +02:00
// Display the search results.
2021-03-22 14:44:47 +01:00
// Limit the number of results displayed to avoid an infinite loop.
_search ( EditorFileSystem : : get_singleton ( ) - > get_filesystem ( ) , & file_list , 10000 ) ;
2018-09-29 00:11:26 +02:00
} else {
2018-10-16 22:08:00 +02:00
if ( display_mode = = DISPLAY_MODE_TREE_ONLY | | always_show_folders ) {
2019-08-22 06:22:52 +02:00
// Display folders in the list.
2018-09-29 00:11:26 +02:00
if ( directory ! = " res:// " ) {
files - > add_item ( " .. " , folder_icon , true ) ;
2016-05-16 01:25:51 +02:00
2018-09-29 00:11:26 +02:00
String bd = directory . get_base_dir ( ) ;
2020-05-14 16:41:43 +02:00
if ( bd ! = " res:// " & & ! bd . ends_with ( " / " ) ) {
2018-09-29 00:11:26 +02:00
bd + = " / " ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
2022-03-12 01:06:45 +01:00
files - > set_item_metadata ( - 1 , bd ) ;
files - > set_item_selectable ( - 1 , false ) ;
files - > set_item_icon_modulate ( - 1 , folder_color ) ;
2018-09-29 00:11:26 +02:00
}
2015-08-24 01:15:56 +02:00
2020-10-22 23:38:41 +02:00
bool reversed = file_sort = = FILE_SORT_NAME_REVERSE ;
for ( int i = reversed ? efd - > get_subdir_count ( ) - 1 : 0 ;
reversed ? i > = 0 : i < efd - > get_subdir_count ( ) ;
reversed ? i - - : i + + ) {
2018-09-29 00:11:26 +02:00
String dname = efd - > get_subdir ( i ) - > get_name ( ) ;
files - > add_item ( dname , folder_icon , true ) ;
2022-08-30 02:34:01 +02:00
files - > set_item_metadata ( - 1 , directory . path_join ( dname ) + " / " ) ;
2022-03-12 01:06:45 +01:00
files - > set_item_icon_modulate ( - 1 , folder_color ) ;
2018-09-29 00:11:26 +02:00
if ( cselection . has ( dname ) ) {
files - > select ( files - > get_item_count ( ) - 1 , false ) ;
}
}
}
2019-08-22 06:22:52 +02:00
// Display the folder content.
2018-09-29 00:11:26 +02:00
for ( int i = 0 ; i < efd - > get_file_count ( ) ; i + + ) {
FileInfo fi ;
fi . name = efd - > get_file ( i ) ;
2022-08-30 02:34:01 +02:00
fi . path = directory . path_join ( fi . name ) ;
2018-09-29 00:11:26 +02:00
fi . type = efd - > get_file_type ( i ) ;
fi . import_broken = ! efd - > get_file_import_is_valid ( i ) ;
2020-10-22 23:38:41 +02:00
fi . modified_time = efd - > get_file_modified_time ( i ) ;
2018-09-29 00:11:26 +02:00
2020-10-07 21:56:53 +02:00
file_list . push_back ( fi ) ;
2018-09-29 00:11:26 +02:00
}
2016-05-16 01:25:51 +02:00
}
2020-10-07 21:56:53 +02:00
}
// Sort the file list if needed.
2020-10-22 23:38:41 +02:00
_sort_file_info_list ( file_list ) ;
2015-08-24 01:15:56 +02:00
2019-08-22 06:22:52 +02:00
// Fills the ItemList control node from the FileInfos.
2022-10-18 16:43:37 +02:00
String main_scene = GLOBAL_GET ( " application/run/main_scene " ) ;
2021-07-16 05:45:57 +02:00
for ( FileInfo & E : file_list ) {
FileInfo * finfo = & ( E ) ;
2017-09-03 22:35:18 +02:00
String fname = finfo - > name ;
String fpath = finfo - > path ;
String ftype = finfo - > type ;
2015-08-24 01:15:56 +02:00
2019-06-11 20:43:37 +02:00
Ref < Texture2D > type_icon ;
Ref < Texture2D > big_icon ;
2015-08-24 01:15:56 +02:00
2019-05-05 15:21:38 +02:00
String tooltip = fpath ;
2016-05-27 19:18:40 +02:00
2019-08-22 06:22:52 +02:00
// Select the icons.
2017-09-03 22:35:18 +02:00
if ( ! finfo - > import_broken ) {
2022-02-06 14:12:19 +01:00
type_icon = ( has_theme_icon ( ftype , SNAME ( " EditorIcons " ) ) ) ? get_theme_icon ( ftype , SNAME ( " EditorIcons " ) ) : get_theme_icon ( SNAME ( " Object " ) , SNAME ( " EditorIcons " ) ) ;
2017-09-03 22:35:18 +02:00
big_icon = file_thumbnail ;
2017-08-30 01:17:34 +02:00
} else {
2022-02-06 14:12:19 +01:00
type_icon = get_theme_icon ( SNAME ( " ImportFail " ) , SNAME ( " EditorIcons " ) ) ;
2017-08-30 01:17:34 +02:00
big_icon = file_thumbnail_broken ;
2018-01-06 14:32:21 +01:00
tooltip + = " \n " + TTR ( " Status: Import of file failed. Please fix file and reimport manually. " ) ;
2016-05-27 19:18:40 +02:00
}
2019-08-22 06:22:52 +02:00
// Add the item to the ItemList.
2017-09-03 22:35:18 +02:00
int item_index ;
2015-08-24 01:15:56 +02:00
if ( use_thumbnails ) {
2017-08-30 01:17:34 +02:00
files - > add_item ( fname , big_icon , true ) ;
2017-09-03 22:35:18 +02:00
item_index = files - > get_item_count ( ) - 1 ;
files - > set_item_metadata ( item_index , fpath ) ;
files - > set_item_tag_icon ( item_index , type_icon ) ;
2018-09-28 13:26:36 +02:00
2015-08-24 01:15:56 +02:00
} else {
2017-03-05 16:44:50 +01:00
files - > add_item ( fname , type_icon , true ) ;
2017-09-03 22:35:18 +02:00
item_index = files - > get_item_count ( ) - 1 ;
files - > set_item_metadata ( item_index , fpath ) ;
2015-08-24 01:15:56 +02:00
}
2020-01-07 18:09:31 +01:00
if ( fpath = = main_scene ) {
2021-07-17 23:22:52 +02:00
files - > set_item_custom_fg_color ( item_index , get_theme_color ( SNAME ( " accent_color " ) , SNAME ( " Editor " ) ) ) ;
2020-01-07 18:09:31 +01:00
}
2019-08-22 06:22:52 +02:00
// Generate the preview.
2018-09-28 13:26:36 +02:00
if ( ! finfo - > import_broken ) {
Array udata ;
udata . resize ( 2 ) ;
udata [ 0 ] = item_index ;
udata [ 1 ] = fname ;
EditorResourcePreview : : get_singleton ( ) - > queue_resource_preview ( fpath , this , " _file_list_thumbnail_done " , udata ) ;
}
2019-08-22 06:22:52 +02:00
// Select the items.
2020-05-14 16:41:43 +02:00
if ( cselection . has ( fname ) ) {
2017-09-03 22:35:18 +02:00
files - > select ( item_index , false ) ;
2020-05-14 16:41:43 +02:00
}
2016-05-27 19:18:40 +02:00
2021-12-09 10:42:46 +01:00
if ( ! p_keep_selection & & ! file . is_empty ( ) & & fname = = file ) {
2018-08-23 17:00:30 +02:00
files - > select ( item_index , true ) ;
files - > ensure_current_is_visible ( ) ;
}
2019-08-22 06:22:52 +02:00
// Tooltip.
2017-09-03 22:35:18 +02:00
if ( finfo - > sources . size ( ) ) {
for ( int j = 0 ; j < finfo - > sources . size ( ) ; j + + ) {
tooltip + = " \n Source: " + finfo - > sources [ j ] ;
}
}
files - > set_item_tooltip ( item_index , tooltip ) ;
2015-08-24 01:15:56 +02:00
}
}
2019-07-10 11:54:12 +02:00
void FileSystemDock : : _select_file ( const String & p_path , bool p_select_in_favorites ) {
2018-08-23 17:00:30 +02:00
String fpath = p_path ;
2017-09-03 22:35:18 +02:00
if ( fpath . ends_with ( " / " ) ) {
if ( fpath ! = " res:// " ) {
fpath = fpath . substr ( 0 , fpath . length ( ) - 1 ) ;
2017-10-09 15:59:48 +02:00
}
2018-09-29 00:11:26 +02:00
} else if ( fpath ! = " Favorites " ) {
2021-03-23 15:20:14 +01:00
if ( FileAccess : : exists ( fpath + " .import " ) ) {
Ref < ConfigFile > config ;
2021-06-18 00:03:09 +02:00
config . instantiate ( ) ;
2021-03-23 15:20:14 +01:00
Error err = config - > load ( fpath + " .import " ) ;
if ( err = = OK ) {
if ( config - > has_section_key ( " remap " , " importer " ) ) {
String importer = config - > get_value ( " remap " , " importer " ) ;
if ( importer = = " keep " ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Importing has been disabled for this file, so it can't be opened for editing. " ) ) ;
return ;
}
}
}
}
2022-07-21 01:00:58 +02:00
String resource_type = ResourceLoader : : get_resource_type ( fpath ) ;
if ( resource_type = = " PackedScene " ) {
2021-03-19 13:57:52 +01:00
bool is_imported = false ;
{
List < String > importer_exts ;
2022-04-12 16:07:09 +02:00
ResourceImporterScene : : get_scene_singleton ( ) - > get_recognized_extensions ( & importer_exts ) ;
2021-03-19 13:57:52 +01:00
String extension = fpath . get_extension ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : importer_exts ) {
2021-07-16 05:45:57 +02:00
if ( extension . nocasecmp_to ( E ) = = 0 ) {
2021-03-19 13:57:52 +01:00
is_imported = true ;
break ;
}
}
}
if ( is_imported ) {
2022-04-12 16:07:09 +02:00
ResourceImporterScene : : get_scene_singleton ( ) - > show_advanced_options ( fpath ) ;
} else {
EditorNode : : get_singleton ( ) - > open_request ( fpath ) ;
}
2022-07-21 01:00:58 +02:00
} else if ( resource_type = = " AnimationLibrary " ) {
2022-04-12 16:07:09 +02:00
bool is_imported = false ;
{
List < String > importer_exts ;
ResourceImporterScene : : get_animation_singleton ( ) - > get_recognized_extensions ( & importer_exts ) ;
String extension = fpath . get_extension ( ) ;
for ( const String & E : importer_exts ) {
if ( extension . nocasecmp_to ( E ) = = 0 ) {
is_imported = true ;
break ;
}
}
}
if ( is_imported ) {
ResourceImporterScene : : get_animation_singleton ( ) - > show_advanced_options ( fpath ) ;
2021-03-19 13:57:52 +01:00
} else {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > open_request ( fpath ) ;
2021-03-19 13:57:52 +01:00
}
2022-07-21 01:00:58 +02:00
} else if ( ResourceLoader : : is_imported ( fpath ) ) {
// If the importer has advanced settings, show them.
int order ;
bool can_threads ;
String name ;
Error err = ResourceFormatImporter : : get_singleton ( ) - > get_import_order_threads_and_importer ( fpath , order , can_threads , name ) ;
bool used_advanced_settings = false ;
if ( err = = OK ) {
Ref < ResourceImporter > importer = ResourceFormatImporter : : get_singleton ( ) - > get_importer_by_name ( name ) ;
if ( importer . is_valid ( ) & & importer - > has_advanced_options ( ) ) {
importer - > show_advanced_options ( fpath ) ;
used_advanced_settings = true ;
}
}
if ( ! used_advanced_settings ) {
EditorNode : : get_singleton ( ) - > load_resource ( fpath ) ;
}
2017-10-09 15:59:48 +02:00
} else {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > load_resource ( fpath ) ;
2017-10-09 15:59:48 +02:00
}
}
2019-01-17 20:40:38 +01:00
_navigate_to_path ( fpath , p_select_in_favorites ) ;
2015-08-24 01:15:56 +02:00
}
2018-08-23 17:00:30 +02:00
void FileSystemDock : : _tree_activate_file ( ) {
TreeItem * selected = tree - > get_selected ( ) ;
if ( selected ) {
2022-09-29 11:53:28 +02:00
String file_path = selected - > get_metadata ( 0 ) ;
2019-01-17 20:40:38 +01:00
TreeItem * parent = selected - > get_parent ( ) ;
2020-04-02 01:20:12 +02:00
bool is_favorite = parent ! = nullptr & & parent - > get_metadata ( 0 ) = = " Favorites " ;
2018-08-23 17:00:30 +02:00
2022-09-29 11:53:28 +02:00
if ( ( ! is_favorite & & file_path . ends_with ( " / " ) ) | | file_path = = " Favorites " ) {
2018-09-29 00:11:26 +02:00
bool collapsed = selected - > is_collapsed ( ) ;
selected - > set_collapsed ( ! collapsed ) ;
2019-01-17 20:40:38 +01:00
} else {
2022-09-29 11:53:28 +02:00
_select_file ( file_path , is_favorite & & ! file_path . ends_with ( " / " ) ) ;
2018-09-29 00:11:26 +02:00
}
2017-09-03 22:35:18 +02:00
}
2018-08-13 19:05:31 +02:00
}
2018-08-23 17:00:30 +02:00
2018-10-16 22:08:00 +02:00
void FileSystemDock : : _file_list_activate_file ( int p_idx ) {
_select_file ( files - > get_item_metadata ( p_idx ) ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
void FileSystemDock : : _preview_invalidated ( const String & p_path ) {
2023-05-11 04:17:03 +02:00
if ( file_list_display_mode = = FILE_LIST_DISPLAY_THUMBNAILS & & p_path . get_base_dir ( ) = = current_path & & searched_string . length ( ) = = 0 & & file_list_vb - > is_visible_in_tree ( ) ) {
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < files - > get_item_count ( ) ; i + + ) {
if ( files - > get_item_metadata ( i ) = = p_path ) {
2019-08-22 06:22:52 +02:00
// Re-request preview.
2016-07-03 18:15:15 +02:00
Array udata ;
udata . resize ( 2 ) ;
2017-03-05 16:44:50 +01:00
udata [ 0 ] = i ;
udata [ 1 ] = files - > get_item_text ( i ) ;
2018-09-12 13:10:49 +02:00
EditorResourcePreview : : get_singleton ( ) - > queue_resource_preview ( p_path , this , " _file_list_thumbnail_done " , udata ) ;
2016-07-03 18:15:15 +02:00
break ;
}
}
}
}
2016-07-21 15:34:57 +02:00
void FileSystemDock : : _fs_changed ( ) {
2017-03-05 16:44:50 +01:00
button_hist_prev - > set_disabled ( history_pos = = 0 ) ;
2017-09-03 22:35:18 +02:00
button_hist_next - > set_disabled ( history_pos = = history . size ( ) - 1 ) ;
2015-08-24 01:15:56 +02:00
scanning_vb - > hide ( ) ;
2016-05-16 01:25:51 +02:00
split_box - > show ( ) ;
2015-08-24 01:15:56 +02:00
2017-01-13 14:45:50 +01:00
if ( tree - > is_visible ( ) ) {
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2016-05-16 01:25:51 +02:00
}
2017-01-13 14:45:50 +01:00
if ( file_list_vb - > is_visible ( ) ) {
2018-09-28 13:26:36 +02:00
_update_file_list ( true ) ;
2015-08-24 01:15:56 +02:00
}
set_process ( false ) ;
}
2017-01-21 13:07:29 +01:00
void FileSystemDock : : _set_scanning_mode ( ) {
2015-08-24 01:15:56 +02:00
button_hist_prev - > set_disabled ( true ) ;
button_hist_next - > set_disabled ( true ) ;
2017-09-03 22:35:18 +02:00
split_box - > hide ( ) ;
2015-08-24 01:15:56 +02:00
scanning_vb - > show ( ) ;
set_process ( true ) ;
if ( EditorFileSystem : : get_singleton ( ) - > is_scanning ( ) ) {
2017-03-05 16:44:50 +01:00
scanning_progress - > set_value ( EditorFileSystem : : get_singleton ( ) - > get_scanning_progress ( ) * 100 ) ;
2015-08-24 01:15:56 +02:00
} else {
2017-01-04 05:16:14 +01:00
scanning_progress - > set_value ( 0 ) ;
2015-08-24 01:15:56 +02:00
}
}
2016-07-21 15:34:57 +02:00
void FileSystemDock : : _fw_history ( ) {
2020-05-14 16:41:43 +02:00
if ( history_pos < history . size ( ) - 1 ) {
2015-08-24 01:15:56 +02:00
history_pos + + ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
2017-09-03 22:35:18 +02:00
_update_history ( ) ;
2015-08-24 01:15:56 +02:00
}
2016-07-21 15:34:57 +02:00
void FileSystemDock : : _bw_history ( ) {
2020-05-14 16:41:43 +02:00
if ( history_pos > 0 ) {
2015-08-24 01:15:56 +02:00
history_pos - - ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
2017-09-03 22:35:18 +02:00
_update_history ( ) ;
}
void FileSystemDock : : _update_history ( ) {
2023-05-11 04:17:03 +02:00
current_path = history [ history_pos ] ;
_set_current_path_line_edit_text ( current_path ) ;
2016-05-16 01:25:51 +02:00
2017-01-13 14:45:50 +01:00
if ( tree - > is_visible ( ) ) {
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2015-08-24 01:15:56 +02:00
tree - > grab_focus ( ) ;
tree - > ensure_cursor_is_visible ( ) ;
2016-05-16 01:25:51 +02:00
}
2017-01-13 14:45:50 +01:00
if ( file_list_vb - > is_visible ( ) ) {
2018-09-28 13:26:36 +02:00
_update_file_list ( false ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
button_hist_prev - > set_disabled ( history_pos = = 0 ) ;
2017-09-03 22:35:18 +02:00
button_hist_next - > set_disabled ( history_pos = = history . size ( ) - 1 ) ;
2015-08-24 01:15:56 +02:00
}
2016-07-21 15:34:57 +02:00
void FileSystemDock : : _push_to_history ( ) {
2023-05-11 04:17:03 +02:00
if ( history [ history_pos ] ! = current_path ) {
2017-09-03 22:35:18 +02:00
history . resize ( history_pos + 1 ) ;
2023-05-11 04:17:03 +02:00
history . push_back ( current_path ) ;
2015-08-24 01:15:56 +02:00
history_pos + + ;
2017-09-03 22:35:18 +02:00
if ( history . size ( ) > history_max_size ) {
2021-07-04 00:17:03 +02:00
history . remove_at ( 0 ) ;
2017-09-03 22:35:18 +02:00
history_pos = history_max_size - 1 ;
}
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
button_hist_prev - > set_disabled ( history_pos = = 0 ) ;
2017-09-03 22:35:18 +02:00
button_hist_next - > set_disabled ( history_pos = = history . size ( ) - 1 ) ;
2015-08-24 01:15:56 +02:00
}
2022-09-29 11:53:28 +02:00
void FileSystemDock : : _get_all_items_in_dir ( EditorFileSystemDirectory * p_efsd , Vector < String > & r_files , Vector < String > & r_folders ) const {
if ( p_efsd = = nullptr ) {
2017-10-01 23:59:27 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-08-24 01:15:56 +02:00
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < p_efsd - > get_subdir_count ( ) ; i + + ) {
r_folders . push_back ( p_efsd - > get_subdir ( i ) - > get_path ( ) ) ;
_get_all_items_in_dir ( p_efsd - > get_subdir ( i ) , r_files , r_folders ) ;
2015-08-24 01:15:56 +02:00
}
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < p_efsd - > get_file_count ( ) ; i + + ) {
r_files . push_back ( p_efsd - > get_file_path ( i ) ) ;
2015-08-24 01:15:56 +02:00
}
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
void FileSystemDock : : _find_remaps ( EditorFileSystemDirectory * p_efsd , const HashMap < String , String > & r_renames , Vector < String > & r_to_remaps ) const {
for ( int i = 0 ; i < p_efsd - > get_subdir_count ( ) ; i + + ) {
_find_remaps ( p_efsd - > get_subdir ( i ) , r_renames , r_to_remaps ) ;
2015-08-24 01:15:56 +02:00
}
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < p_efsd - > get_file_count ( ) ; i + + ) {
Vector < String > deps = p_efsd - > get_file_deps ( i ) ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < deps . size ( ) ; j + + ) {
2022-09-29 11:53:28 +02:00
if ( r_renames . has ( deps [ j ] ) ) {
r_to_remaps . push_back ( p_efsd - > get_file_path ( i ) ) ;
2015-08-24 01:15:56 +02:00
break ;
}
}
}
}
2018-03-01 00:14:12 +01:00
void FileSystemDock : : _try_move_item ( const FileOrFolder & p_item , const String & p_new_path ,
2022-05-13 15:04:37 +02:00
HashMap < String , String > & p_file_renames , HashMap < String , String > & p_folder_renames ) {
2019-08-22 06:22:52 +02:00
// Ensure folder paths end with "/".
2017-10-01 23:59:27 +02:00
String old_path = ( p_item . is_file | | p_item . path . ends_with ( " / " ) ) ? p_item . path : ( p_item . path + " / " ) ;
String new_path = ( p_item . is_file | | p_new_path . ends_with ( " / " ) ) ? p_new_path : ( p_new_path + " / " ) ;
2015-08-24 01:15:56 +02:00
2017-10-01 23:59:27 +02:00
if ( new_path = = old_path ) {
2015-08-24 01:15:56 +02:00
return ;
2017-10-01 23:59:27 +02:00
} else if ( old_path = = " res:// " ) {
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Cannot move/rename resources root. " ) ) ;
return ;
} else if ( ! p_item . is_file & & new_path . begins_with ( old_path ) ) {
2019-08-22 06:22:52 +02:00
// This check doesn't erroneously catch renaming to a longer name as folder paths always end with "/".
2018-01-04 20:00:39 +01:00
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Cannot move a folder into itself. " ) + " \n " + old_path + " \n " ) ;
2015-08-24 01:15:56 +02:00
return ;
}
2019-08-22 06:22:52 +02:00
// Build a list of files which will have new paths as a result of this operation.
2018-03-01 00:14:12 +01:00
Vector < String > file_changed_paths ;
Vector < String > folder_changed_paths ;
2017-10-01 23:59:27 +02:00
if ( p_item . is_file ) {
2018-03-01 00:14:12 +01:00
file_changed_paths . push_back ( old_path ) ;
2017-10-01 23:59:27 +02:00
} else {
2018-03-01 00:14:12 +01:00
folder_changed_paths . push_back ( old_path ) ;
_get_all_items_in_dir ( EditorFileSystem : : get_singleton ( ) - > get_filesystem_path ( old_path ) , file_changed_paths , folder_changed_paths ) ;
2015-08-24 01:15:56 +02:00
}
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2018-08-24 09:35:07 +02:00
print_verbose ( " Moving " + old_path + " -> " + new_path ) ;
2017-10-01 23:59:27 +02:00
Error err = da - > rename ( old_path , new_path ) ;
if ( err = = OK ) {
2019-08-22 06:22:52 +02:00
// Move/Rename any corresponding import settings too.
2017-10-01 23:59:27 +02:00
if ( p_item . is_file & & FileAccess : : exists ( old_path + " .import " ) ) {
err = da - > rename ( old_path + " .import " , new_path + " .import " ) ;
if ( err ! = OK ) {
2018-01-04 20:00:39 +01:00
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Error moving: " ) + " \n " + old_path + " .import \n " ) ;
2017-10-01 23:59:27 +02:00
}
}
2015-08-24 01:15:56 +02:00
2019-08-22 06:22:52 +02:00
// Update scene if it is open.
2018-03-01 00:14:12 +01:00
for ( int i = 0 ; i < file_changed_paths . size ( ) ; + + i ) {
String new_item_path = p_item . is_file ? new_path : file_changed_paths [ i ] . replace_first ( old_path , new_path ) ;
2022-01-27 10:36:51 +01:00
if ( ResourceLoader : : get_resource_type ( new_item_path ) = = " PackedScene " & & EditorNode : : get_singleton ( ) - > is_scene_open ( file_changed_paths [ i ] ) ) {
EditorData * ed = & EditorNode : : get_singleton ( ) - > get_editor_data ( ) ;
2017-11-29 01:48:09 +01:00
for ( int j = 0 ; j < ed - > get_edited_scene_count ( ) ; j + + ) {
2018-03-01 00:14:12 +01:00
if ( ed - > get_scene_path ( j ) = = file_changed_paths [ i ] ) {
2021-09-30 16:30:55 +02:00
ed - > get_edited_scene_root ( j ) - > set_scene_file_path ( new_item_path ) ;
2023-05-11 04:17:03 +02:00
EditorNode : : get_singleton ( ) - > save_editor_layout_delayed ( ) ;
2017-11-29 01:48:09 +01:00
break ;
}
}
}
}
2019-08-22 06:22:52 +02:00
// Only treat as a changed dependency if it was successfully moved.
2018-03-01 00:14:12 +01:00
for ( int i = 0 ; i < file_changed_paths . size ( ) ; + + i ) {
p_file_renames [ file_changed_paths [ i ] ] = file_changed_paths [ i ] . replace_first ( old_path , new_path ) ;
2018-08-24 09:35:07 +02:00
print_verbose ( " Remap: " + file_changed_paths [ i ] + " -> " + p_file_renames [ file_changed_paths [ i ] ] ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " files_moved " ) , file_changed_paths [ i ] , p_file_renames [ file_changed_paths [ i ] ] ) ;
2018-03-01 00:14:12 +01:00
}
for ( int i = 0 ; i < folder_changed_paths . size ( ) ; + + i ) {
p_folder_renames [ folder_changed_paths [ i ] ] = folder_changed_paths [ i ] . replace_first ( old_path , new_path ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " folder_moved " ) , folder_changed_paths [ i ] , p_folder_renames [ folder_changed_paths [ i ] ] . substr ( 0 , p_folder_renames [ folder_changed_paths [ i ] ] . length ( ) - 1 ) ) ;
2017-10-01 23:59:27 +02:00
}
} else {
2018-01-04 20:00:39 +01:00
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Error moving: " ) + " \n " + old_path + " \n " ) ;
2015-08-24 01:15:56 +02:00
}
}
2017-12-01 12:13:50 +01:00
void FileSystemDock : : _try_duplicate_item ( const FileOrFolder & p_item , const String & p_new_path ) const {
2019-08-22 06:22:52 +02:00
// Ensure folder paths end with "/".
2017-12-01 12:13:50 +01:00
String old_path = ( p_item . is_file | | p_item . path . ends_with ( " / " ) ) ? p_item . path : ( p_item . path + " / " ) ;
String new_path = ( p_item . is_file | | p_new_path . ends_with ( " / " ) ) ? p_new_path : ( p_new_path + " / " ) ;
if ( new_path = = old_path ) {
return ;
} else if ( old_path = = " res:// " ) {
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Cannot move/rename resources root. " ) ) ;
return ;
} else if ( ! p_item . is_file & & new_path . begins_with ( old_path ) ) {
2019-08-22 06:22:52 +02:00
// This check doesn't erroneously catch renaming to a longer name as folder paths always end with "/".
2018-01-04 20:00:39 +01:00
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Cannot move a folder into itself. " ) + " \n " + old_path + " \n " ) ;
2017-12-01 12:13:50 +01:00
return ;
}
2023-05-11 04:17:03 +02:00
const_cast < FileSystemDock * > ( this ) - > current_path = new_path ;
2017-12-01 12:13:50 +01:00
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2022-10-01 14:27:29 +02:00
if ( p_item . is_file ) {
print_verbose ( " Duplicating " + old_path + " -> " + new_path ) ;
// Create the directory structure.
da - > make_dir_recursive ( new_path . get_base_dir ( ) ) ;
if ( FileAccess : : exists ( old_path + " .import " ) ) {
Error err = da - > copy ( old_path , new_path ) ;
2017-12-01 12:13:50 +01:00
if ( err ! = OK ) {
2022-10-01 14:27:29 +02:00
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Error duplicating: " ) + " \n " + old_path + " : " + error_names [ err ] + " \n " ) ;
return ;
2017-12-01 12:13:50 +01:00
}
2021-12-03 12:54:57 +01:00
// Remove uid from .import file to avoid conflict.
Ref < ConfigFile > cfg ;
cfg . instantiate ( ) ;
2022-10-01 14:27:29 +02:00
cfg - > load ( old_path + " .import " ) ;
2021-12-03 12:54:57 +01:00
cfg - > erase_section_key ( " remap " , " uid " ) ;
2022-10-01 14:27:29 +02:00
err = cfg - > save ( new_path + " .import " ) ;
if ( err ! = OK ) {
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Error duplicating: " ) + " \n " + old_path + " .import: " + error_names [ err ] + " \n " ) ;
return ;
}
} else {
// Files which do not use an uid can just be copied.
if ( ResourceLoader : : get_resource_uid ( old_path ) = = ResourceUID : : INVALID_ID ) {
Error err = da - > copy ( old_path , new_path ) ;
if ( err ! = OK ) {
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Error duplicating: " ) + " \n " + old_path + " : " + error_names [ err ] + " \n " ) ;
}
return ;
}
2021-12-03 12:54:57 +01:00
2022-10-01 14:27:29 +02:00
// Load the resource and save it again in the new location (this generates a new UID).
Error err ;
Ref < Resource > res = ResourceLoader : : load ( old_path , " " , ResourceFormatLoader : : CACHE_MODE_REUSE , & err ) ;
if ( err = = OK & & res . is_valid ( ) ) {
err = ResourceSaver : : save ( res , new_path , ResourceSaver : : FLAG_COMPRESS ) ;
if ( err ! = OK ) {
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Error duplicating: " ) + " " + vformat ( TTR ( " Failed to save resource at %s: %s " ) , new_path , error_names [ err ] ) ) ;
2021-12-03 12:54:57 +01:00
}
2022-10-01 14:27:29 +02:00
} else if ( err ! = OK ) {
// When loading files like text files the error is OK but the resource is still null.
// We can ignore such files.
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Error duplicating: " ) + " " + vformat ( TTR ( " Failed to load resource at %s: %s " ) , new_path , error_names [ err ] ) ) ;
2021-12-03 12:54:57 +01:00
}
2017-12-01 12:13:50 +01:00
}
} else {
2022-10-01 14:27:29 +02:00
// Recursively duplicate all files inside the folder.
Ref < DirAccess > old_dir = DirAccess : : open ( old_path ) ;
Ref < FileAccess > file_access = FileAccess : : create ( FileAccess : : ACCESS_RESOURCES ) ;
old_dir - > set_include_navigational ( false ) ;
old_dir - > list_dir_begin ( ) ;
for ( String f = old_dir - > _get_next ( ) ; ! f . is_empty ( ) ; f = old_dir - > _get_next ( ) ) {
if ( f . get_extension ( ) = = " import " ) {
continue ;
}
if ( file_access - > file_exists ( old_path + f ) ) {
_try_duplicate_item ( FileOrFolder ( old_path + f , true ) , new_path + f ) ;
} else if ( da - > dir_exists ( old_path + f ) ) {
_try_duplicate_item ( FileOrFolder ( old_path + f , false ) , new_path + f ) ;
}
}
old_dir - > list_dir_end ( ) ;
2017-12-01 12:13:50 +01:00
}
}
2022-05-13 15:04:37 +02:00
void FileSystemDock : : _update_resource_paths_after_move ( const HashMap < String , String > & p_renames ) const {
2019-08-22 06:22:52 +02:00
// Rename all resources loaded, be it subresources or actual resources.
2020-03-17 07:33:00 +01:00
List < Ref < Resource > > cached ;
2017-12-26 20:32:12 +01:00
ResourceCache : : get_cached_resources ( & cached ) ;
2021-07-26 17:50:35 +02:00
for ( Ref < Resource > & r : cached ) {
2017-12-26 20:32:12 +01:00
String base_path = r - > get_path ( ) ;
String extra_path ;
int sep_pos = r - > get_path ( ) . find ( " :: " ) ;
if ( sep_pos > = 0 ) {
extra_path = base_path . substr ( sep_pos , base_path . length ( ) ) ;
base_path = base_path . substr ( 0 , sep_pos ) ;
}
if ( p_renames . has ( base_path ) ) {
base_path = p_renames [ base_path ] ;
}
r - > set_path ( base_path + extra_path ) ;
}
for ( int i = 0 ; i < EditorNode : : get_editor_data ( ) . get_edited_scene_count ( ) ; i + + ) {
2022-09-29 11:53:28 +02:00
String file_path ;
2017-12-26 20:32:12 +01:00
if ( i = = EditorNode : : get_editor_data ( ) . get_edited_scene ( ) ) {
2020-05-14 16:41:43 +02:00
if ( ! get_tree ( ) - > get_edited_scene_root ( ) ) {
2017-12-26 20:32:12 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-12-26 20:32:12 +01:00
2022-09-29 11:53:28 +02:00
file_path = get_tree ( ) - > get_edited_scene_root ( ) - > get_scene_file_path ( ) ;
2017-12-26 20:32:12 +01:00
} else {
2022-09-29 11:53:28 +02:00
file_path = EditorNode : : get_editor_data ( ) . get_scene_path ( i ) ;
2017-12-26 20:32:12 +01:00
}
2022-09-29 11:53:28 +02:00
if ( p_renames . has ( file_path ) ) {
file_path = p_renames [ file_path ] ;
2017-12-26 20:32:12 +01:00
}
if ( i = = EditorNode : : get_editor_data ( ) . get_edited_scene ( ) ) {
2022-09-29 11:53:28 +02:00
get_tree ( ) - > get_edited_scene_root ( ) - > set_scene_file_path ( file_path ) ;
2017-12-26 20:32:12 +01:00
} else {
2022-09-29 11:53:28 +02:00
EditorNode : : get_editor_data ( ) . set_scene_path ( i , file_path ) ;
2017-12-26 20:32:12 +01:00
}
}
}
2022-05-13 15:04:37 +02:00
void FileSystemDock : : _update_dependencies_after_move ( const HashMap < String , String > & p_renames ) const {
2019-08-22 06:22:52 +02:00
// The following code assumes that the following holds:
2017-10-01 23:59:27 +02:00
// 1) EditorFileSystem contains the old paths/folder structure from before the rename/move.
// 2) ResourceLoader can use the new paths without needing to call rescan.
Vector < String > remaps ;
_find_remaps ( EditorFileSystem : : get_singleton ( ) - > get_filesystem ( ) , p_renames , remaps ) ;
for ( int i = 0 ; i < remaps . size ( ) ; + + i ) {
2019-08-22 06:22:52 +02:00
// Because we haven't called a rescan yet the found remap might still be an old path itself.
2017-10-01 23:59:27 +02:00
String file = p_renames . has ( remaps [ i ] ) ? p_renames [ remaps [ i ] ] : remaps [ i ] ;
2018-08-24 09:35:07 +02:00
print_verbose ( " Remapping dependencies for: " + file ) ;
2017-10-01 23:59:27 +02:00
Error err = ResourceLoader : : rename_dependencies ( file , p_renames ) ;
2017-11-29 01:48:09 +01:00
if ( err = = OK ) {
2020-05-14 16:41:43 +02:00
if ( ResourceLoader : : get_resource_type ( file ) = = " PackedScene " ) {
2022-12-04 17:28:30 +01:00
callable_mp ( EditorNode : : get_singleton ( ) , & EditorNode : : reload_scene ) . bind ( file ) . call_deferred ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-11-29 01:48:09 +01:00
} else {
2018-01-04 20:00:39 +01:00
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Unable to update dependencies: " ) + " \n " + remaps [ i ] + " \n " ) ;
2015-08-24 01:15:56 +02:00
}
2017-09-03 05:22:54 +02:00
}
2017-10-01 23:59:27 +02:00
}
2017-09-03 05:22:54 +02:00
2022-05-13 15:04:37 +02:00
void FileSystemDock : : _update_project_settings_after_move ( const HashMap < String , String > & p_renames ) const {
2019-08-22 06:22:52 +02:00
// Find all project settings of type FILE and replace them if needed.
2022-05-13 15:04:37 +02:00
const HashMap < StringName , PropertyInfo > prop_info = ProjectSettings : : get_singleton ( ) - > get_custom_property_info ( ) ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , PropertyInfo > & E : prop_info ) {
if ( E . value . hint = = PROPERTY_HINT_FILE ) {
String old_path = GLOBAL_GET ( E . key ) ;
2018-05-26 20:19:38 +02:00
if ( p_renames . has ( old_path ) ) {
2021-08-09 22:13:42 +02:00
ProjectSettings : : get_singleton ( ) - > set_setting ( E . key , p_renames [ old_path ] ) ;
2018-05-26 20:19:38 +02:00
}
} ;
}
2018-10-14 07:05:53 +02:00
// Also search for the file in autoload, as they are stored differently from normal files.
List < PropertyInfo > property_list ;
ProjectSettings : : get_singleton ( ) - > get_property_list ( & property_list ) ;
2021-07-16 05:45:57 +02:00
for ( const PropertyInfo & E : property_list ) {
if ( E . name . begins_with ( " autoload/ " ) ) {
2018-10-14 07:05:53 +02:00
// If the autoload resource paths has a leading "*", it indicates that it is a Singleton,
// so we have to handle both cases when updating.
2021-07-16 05:45:57 +02:00
String autoload = GLOBAL_GET ( E . name ) ;
2018-10-14 07:05:53 +02:00
String autoload_singleton = autoload . substr ( 1 , autoload . length ( ) ) ;
if ( p_renames . has ( autoload ) ) {
2021-07-16 05:45:57 +02:00
ProjectSettings : : get_singleton ( ) - > set_setting ( E . name , p_renames [ autoload ] ) ;
2018-10-14 07:05:53 +02:00
} else if ( autoload . begins_with ( " * " ) & & p_renames . has ( autoload_singleton ) ) {
2021-07-16 05:45:57 +02:00
ProjectSettings : : get_singleton ( ) - > set_setting ( E . name , " * " + p_renames [ autoload_singleton ] ) ;
2018-10-14 07:05:53 +02:00
}
}
}
2018-05-26 20:19:38 +02:00
ProjectSettings : : get_singleton ( ) - > save ( ) ;
}
2023-03-25 20:58:37 +01:00
String FileSystemDock : : _get_unique_name ( const FileOrFolder & p_entry , const String & p_at_path ) {
String new_path ;
String new_path_base ;
if ( p_entry . is_file ) {
new_path = p_at_path . path_join ( p_entry . path . get_file ( ) ) ;
new_path_base = new_path . get_basename ( ) + " (%d). " + new_path . get_extension ( ) ;
} else {
PackedStringArray path_split = p_entry . path . split ( " / " ) ;
new_path = p_at_path . path_join ( path_split [ path_split . size ( ) - 2 ] ) ;
new_path_base = new_path + " (%d) " ;
}
int exist_counter = 1 ;
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
while ( da - > file_exists ( new_path ) | | da - > dir_exists ( new_path ) ) {
exist_counter + + ;
new_path = vformat ( new_path_base , exist_counter ) ;
}
return new_path ;
}
2022-05-13 15:04:37 +02:00
void FileSystemDock : : _update_favorites_list_after_move ( const HashMap < String , String > & p_files_renames , const HashMap < String , String > & p_folders_renames ) const {
2022-09-29 11:53:28 +02:00
Vector < String > favorites_list = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
2018-09-18 14:02:59 +02:00
Vector < String > new_favorites ;
2018-03-01 00:14:12 +01:00
2022-09-29 11:53:28 +02:00
for ( const String & old_path : favorites_list ) {
2018-09-18 14:02:59 +02:00
if ( p_folders_renames . has ( old_path ) ) {
new_favorites . push_back ( p_folders_renames [ old_path ] ) ;
} else if ( p_files_renames . has ( old_path ) ) {
new_favorites . push_back ( p_files_renames [ old_path ] ) ;
2018-03-01 00:14:12 +01:00
} else {
2018-09-18 14:02:59 +02:00
new_favorites . push_back ( old_path ) ;
2018-03-01 00:14:12 +01:00
}
}
2018-09-18 14:02:59 +02:00
EditorSettings : : get_singleton ( ) - > set_favorites ( new_favorites ) ;
2018-03-01 00:14:12 +01:00
}
2022-05-13 15:04:37 +02:00
void FileSystemDock : : _save_scenes_after_move ( const HashMap < String , String > & p_renames ) const {
2019-06-04 05:36:23 +02:00
Vector < String > remaps ;
_find_remaps ( EditorFileSystem : : get_singleton ( ) - > get_filesystem ( ) , p_renames , remaps ) ;
Vector < String > new_filenames ;
for ( int i = 0 ; i < remaps . size ( ) ; + + i ) {
String file = p_renames . has ( remaps [ i ] ) ? p_renames [ remaps [ i ] ] : remaps [ i ] ;
if ( ResourceLoader : : get_resource_type ( file ) = = " PackedScene " ) {
new_filenames . push_back ( file ) ;
}
}
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > save_scene_list ( new_filenames ) ;
2019-06-04 05:36:23 +02:00
}
2019-08-15 19:47:21 +02:00
void FileSystemDock : : _make_scene_confirm ( ) {
2022-06-12 02:11:52 +02:00
const String scene_path = make_scene_dialog - > get_scene_path ( ) ;
2019-08-15 19:47:21 +02:00
2022-01-27 10:36:51 +01:00
int idx = EditorNode : : get_singleton ( ) - > new_scene ( ) ;
2022-06-12 02:11:52 +02:00
EditorNode : : get_singleton ( ) - > get_editor_data ( ) . set_scene_path ( idx , scene_path ) ;
EditorNode : : get_singleton ( ) - > set_edited_scene ( make_scene_dialog - > create_scene_root ( ) ) ;
EditorNode : : get_singleton ( ) - > save_scene_list ( { scene_path } ) ;
2019-08-15 19:47:21 +02:00
}
2023-01-23 10:01:28 +01:00
void FileSystemDock : : _resource_removed ( const Ref < Resource > & p_resource ) {
emit_signal ( SNAME ( " resource_removed " ) , p_resource ) ;
}
2020-03-17 01:40:15 +01:00
void FileSystemDock : : _file_removed ( String p_file ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " file_removed " ) , p_file ) ;
2021-01-16 16:30:56 +01:00
2021-02-09 15:40:55 +01:00
// Find the closest parent directory available, in case multiple items were deleted along the same path.
2023-05-11 04:17:03 +02:00
current_path = p_file . get_base_dir ( ) ;
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2023-05-11 04:17:03 +02:00
while ( ! da - > dir_exists ( current_path ) ) {
current_path = current_path . get_base_dir ( ) ;
2021-02-09 15:40:55 +01:00
}
2023-05-11 04:17:03 +02:00
current_path_line_edit - > set_text ( current_path ) ;
2018-11-13 20:17:33 +01:00
}
2020-03-17 01:40:15 +01:00
void FileSystemDock : : _folder_removed ( String p_folder ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " folder_removed " ) , p_folder ) ;
2021-01-16 16:30:56 +01:00
2021-02-09 15:40:55 +01:00
// Find the closest parent directory available, in case multiple items were deleted along the same path.
2023-05-11 04:17:03 +02:00
current_path = p_folder . get_base_dir ( ) ;
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2023-05-11 04:17:03 +02:00
while ( ! da - > dir_exists ( current_path ) ) {
current_path = current_path . get_base_dir ( ) ;
2021-02-09 15:40:55 +01:00
}
2023-05-11 04:17:03 +02:00
current_path_line_edit - > set_text ( current_path ) ;
EditorFileSystemDirectory * efd = EditorFileSystem : : get_singleton ( ) - > get_filesystem_path ( current_path ) ;
2021-02-27 21:43:26 +01:00
if ( efd ) {
efd - > force_update ( ) ;
}
2018-11-13 20:17:33 +01:00
}
2017-10-01 23:59:27 +02:00
void FileSystemDock : : _rename_operation_confirm ( ) {
2023-05-26 23:04:14 +02:00
String new_name ;
2022-11-26 15:58:25 +01:00
TreeItem * s = tree - > get_selected ( ) ;
int col_index = tree - > get_selected_column ( ) ;
2023-05-26 23:04:14 +02:00
if ( tree - > has_focus ( ) ) {
new_name = s - > get_text ( col_index ) . strip_edges ( ) ;
} else if ( files - > has_focus ( ) ) {
new_name = files - > get_edit_text ( ) . strip_edges ( ) ;
}
2022-11-26 15:58:25 +01:00
String old_name = to_rename . is_file ? to_rename . path . get_file ( ) : to_rename . path . left ( - 1 ) . get_file ( ) ;
bool rename_error = false ;
2017-10-01 23:59:27 +02:00
if ( new_name . length ( ) = = 0 ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " No name provided. " ) ) ;
2022-11-26 15:58:25 +01:00
rename_error = true ;
2022-02-03 17:03:38 +01:00
} else if ( new_name . contains ( " / " ) | | new_name . contains ( " \\ " ) | | new_name . contains ( " : " ) ) {
2017-10-01 23:59:27 +02:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Name contains invalid characters. " ) ) ;
2022-11-26 15:58:25 +01:00
rename_error = true ;
} else if ( new_name . begins_with ( " . " ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " This filename begins with a dot rendering the file invisible to the editor. \n If you want to rename it anyway, use your operating system's file manager. " ) ) ;
rename_error = true ;
2022-08-07 02:47:02 +02:00
} else if ( to_rename . is_file & & to_rename . path . get_extension ( ) ! = new_name . get_extension ( ) ) {
2022-01-16 19:08:40 +01:00
if ( ! EditorFileSystem : : get_singleton ( ) - > get_valid_extensions ( ) . find ( new_name . get_extension ( ) ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " This file extension is not recognized by the editor. \n If you want to rename it anyway, use your operating system's file manager. \n After renaming to an unknown extension, the file won't be shown in the editor anymore. " ) ) ;
2022-11-26 15:58:25 +01:00
rename_error = true ;
2022-01-16 19:08:40 +01:00
}
2015-08-24 01:15:56 +02:00
}
2023-05-26 23:04:14 +02:00
// Restore original name.
if ( rename_error & & tree - > has_focus ( ) ) {
2022-11-26 15:58:25 +01:00
s - > set_text ( col_index , old_name ) ;
return ;
2023-05-26 23:04:14 +02:00
} else if ( rename_error & & files - > has_focus ( ) ) {
return ;
2022-11-26 15:58:25 +01:00
}
String old_path = to_rename . path . ends_with ( " / " ) ? to_rename . path . left ( - 1 ) : to_rename . path ;
2022-08-30 02:34:01 +02:00
String new_path = old_path . get_base_dir ( ) . path_join ( new_name ) ;
2017-10-01 23:59:27 +02:00
if ( old_path = = new_path ) {
return ;
2015-08-24 01:15:56 +02:00
}
2019-04-19 20:54:33 +02:00
if ( EditorFileSystem : : get_singleton ( ) - > is_group_file ( old_path ) ) {
EditorFileSystem : : get_singleton ( ) - > move_group_file ( old_path , new_path ) ;
}
2019-08-22 06:22:52 +02:00
// Present a more user friendly warning for name conflict.
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2018-01-22 03:04:16 +01:00
# if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED)
2019-08-22 06:22:52 +02:00
// Workaround case insensitivity on Windows.
2018-01-22 03:04:16 +01:00
if ( ( da - > file_exists ( new_path ) | | da - > dir_exists ( new_path ) ) & & new_path . to_lower ( ) ! = old_path . to_lower ( ) ) {
# else
2017-10-01 23:59:27 +02:00
if ( da - > file_exists ( new_path ) | | da - > dir_exists ( new_path ) ) {
2018-01-22 03:04:16 +01:00
# endif
2017-10-01 23:59:27 +02:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " A file or folder with this name already exists. " ) ) ;
2022-11-26 15:58:25 +01:00
s - > set_text ( col_index , old_name ) ;
2017-10-01 23:59:27 +02:00
return ;
2015-08-24 01:15:56 +02:00
}
2022-05-13 15:04:37 +02:00
HashMap < String , String > file_renames ;
HashMap < String , String > folder_renames ;
2018-03-01 00:14:12 +01:00
_try_move_item ( to_rename , new_path , file_renames , folder_renames ) ;
2019-06-04 05:36:23 +02:00
2022-01-27 10:36:51 +01:00
int current_tab = EditorNode : : get_singleton ( ) - > get_current_tab ( ) ;
2019-07-16 05:50:03 +02:00
_save_scenes_after_move ( file_renames ) ; // save scenes before updating
2018-03-01 00:14:12 +01:00
_update_dependencies_after_move ( file_renames ) ;
_update_resource_paths_after_move ( file_renames ) ;
2018-05-26 20:19:38 +02:00
_update_project_settings_after_move ( file_renames ) ;
2018-09-18 14:02:59 +02:00
_update_favorites_list_after_move ( file_renames , folder_renames ) ;
2015-08-24 01:15:56 +02:00
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > set_current_tab ( current_tab ) ;
2019-06-04 05:36:23 +02:00
2018-08-24 09:35:07 +02:00
print_verbose ( " FileSystem: calling rescan. " ) ;
2017-10-01 23:59:27 +02:00
_rescan ( ) ;
2019-06-04 05:36:23 +02:00
print_verbose ( " FileSystem: saving moved scenes. " ) ;
_save_scenes_after_move ( file_renames ) ;
2021-01-16 16:30:56 +01:00
2023-05-11 04:17:03 +02:00
current_path = new_path ;
current_path_line_edit - > set_text ( current_path ) ;
2017-10-01 23:59:27 +02:00
}
2016-05-16 01:25:51 +02:00
2017-12-01 12:13:50 +01:00
void FileSystemDock : : _duplicate_operation_confirm ( ) {
String new_name = duplicate_dialog_text - > get_text ( ) . strip_edges ( ) ;
if ( new_name . length ( ) = = 0 ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " No name provided. " ) ) ;
return ;
2022-02-03 17:03:38 +01:00
} else if ( new_name . contains ( " / " ) | | new_name . contains ( " \\ " ) | | new_name . contains ( " : " ) ) {
2017-12-01 12:13:50 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Name contains invalid characters. " ) ) ;
return ;
}
2017-12-31 18:10:03 +01:00
String base_dir = to_duplicate . path . get_base_dir ( ) ;
2019-07-04 11:42:40 +02:00
// get_base_dir() returns "some/path" if the original path was "some/path/", so work it around.
if ( to_duplicate . path . ends_with ( " / " ) ) {
base_dir = base_dir . get_base_dir ( ) ;
2017-12-01 12:13:50 +01:00
}
2022-08-30 02:34:01 +02:00
String new_path = base_dir . path_join ( new_name ) ;
2019-07-04 11:42:40 +02:00
2019-08-22 06:22:52 +02:00
// Present a more user friendly warning for name conflict
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2017-12-01 12:13:50 +01:00
if ( da - > file_exists ( new_path ) | | da - > dir_exists ( new_path ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " A file or folder with this name already exists. " ) ) ;
return ;
}
2017-12-31 18:10:03 +01:00
_try_duplicate_item ( to_duplicate , new_path ) ;
2017-12-01 12:13:50 +01:00
2019-08-22 06:22:52 +02:00
// Rescan everything.
2018-08-24 09:35:07 +02:00
print_verbose ( " FileSystem: calling rescan. " ) ;
2017-12-01 12:13:50 +01:00
_rescan ( ) ;
}
2023-03-25 20:58:37 +01:00
void FileSystemDock : : _overwrite_dialog_action ( bool p_overwrite ) {
overwrite_dialog - > hide ( ) ;
_move_operation_confirm ( to_move_path , to_move_or_copy , p_overwrite ? OVERWRITE_REPLACE : OVERWRITE_RENAME ) ;
2018-05-29 14:33:11 +02:00
}
2020-12-10 12:53:56 +01:00
Vector < String > FileSystemDock : : _check_existing ( ) {
Vector < String > conflicting_items ;
2023-06-09 18:33:05 +02:00
for ( const FileOrFolder & item : to_move ) {
String old_path = item . path . trim_suffix ( " / " ) ;
String new_path = to_move_path . path_join ( old_path . get_file ( ) ) ;
2018-05-29 14:33:11 +02:00
2023-06-09 18:33:05 +02:00
if ( ( item . is_file & & FileAccess : : exists ( new_path ) ) | | ( ! item . is_file & & DirAccess : : exists ( new_path ) ) ) {
2020-12-10 12:53:56 +01:00
conflicting_items . push_back ( old_path ) ;
2018-05-29 14:33:11 +02:00
}
}
2020-12-10 12:53:56 +01:00
return conflicting_items ;
2018-05-29 14:33:11 +02:00
}
2023-03-25 20:58:37 +01:00
void FileSystemDock : : _move_dialog_confirm ( const String & p_path ) {
_move_operation_confirm ( p_path , move_dialog - > is_copy_pressed ( ) ) ;
}
void FileSystemDock : : _move_operation_confirm ( const String & p_to_path , bool p_copy , Overwrite p_overwrite ) {
if ( p_overwrite = = OVERWRITE_UNDECIDED ) {
2018-05-29 14:33:11 +02:00
to_move_path = p_to_path ;
2023-03-25 20:58:37 +01:00
to_move_or_copy = p_copy ;
2020-12-10 12:53:56 +01:00
Vector < String > conflicting_items = _check_existing ( ) ;
2020-12-15 13:04:21 +01:00
if ( ! conflicting_items . is_empty ( ) ) {
2019-08-22 06:22:52 +02:00
// Ask to do something.
2023-05-18 00:09:44 +02:00
overwrite_dialog_header - > set_text ( vformat (
TTR ( " The following files or folders conflict with items in the target location '%s': " ) , to_move_path ) ) ;
overwrite_dialog_file_list - > set_text ( String ( " \n " ) . join ( conflicting_items ) ) ;
overwrite_dialog_footer - > set_text (
p_copy ? TTR ( " Do you wish to overwrite them or rename the copied files? " )
: TTR ( " Do you wish to overwrite them or rename the moved files? " ) ) ;
2020-03-06 18:00:16 +01:00
overwrite_dialog - > popup_centered ( ) ;
2018-05-29 14:33:11 +02:00
return ;
}
}
2016-05-16 01:25:51 +02:00
2023-03-25 20:58:37 +01:00
Vector < String > new_paths ;
new_paths . resize ( to_move . size ( ) ) ;
2019-04-19 20:54:33 +02:00
for ( int i = 0 ; i < to_move . size ( ) ; i + + ) {
2023-03-25 20:58:37 +01:00
if ( p_overwrite = = OVERWRITE_RENAME ) {
new_paths . write [ i ] = _get_unique_name ( to_move [ i ] , p_to_path ) ;
} else {
new_paths . write [ i ] = p_to_path . path_join ( to_move [ i ] . path . get_file ( ) ) ;
2019-04-19 20:54:33 +02:00
}
}
2023-03-25 20:58:37 +01:00
if ( p_copy ) {
bool is_copied = false ;
for ( int i = 0 ; i < to_move . size ( ) ; i + + ) {
2023-06-09 18:33:05 +02:00
String old_path = to_move [ i ] . path ;
String new_path = new_paths [ i ] ;
if ( ! to_move [ i ] . is_file ) {
new_path = new_path . path_join ( old_path . trim_suffix ( " / " ) . get_file ( ) ) ;
}
2023-03-25 20:58:37 +01:00
if ( old_path ! = new_path ) {
2023-06-09 18:33:05 +02:00
_try_duplicate_item ( to_move [ i ] , new_path ) ;
2023-03-25 20:58:37 +01:00
is_copied = true ;
}
2018-06-19 00:43:16 +02:00
}
2015-08-24 01:15:56 +02:00
2023-03-25 20:58:37 +01:00
if ( is_copied ) {
_rescan ( ) ;
}
} else {
// Check groups.
for ( int i = 0 ; i < to_move . size ( ) ; i + + ) {
if ( to_move [ i ] . is_file & & EditorFileSystem : : get_singleton ( ) - > is_group_file ( to_move [ i ] . path ) ) {
EditorFileSystem : : get_singleton ( ) - > move_group_file ( to_move [ i ] . path , new_paths [ i ] ) ;
}
}
2017-12-26 20:32:12 +01:00
2023-03-25 20:58:37 +01:00
bool is_moved = false ;
HashMap < String , String > file_renames ;
HashMap < String , String > folder_renames ;
2019-06-04 05:36:23 +02:00
2023-03-25 20:58:37 +01:00
for ( int i = 0 ; i < to_move . size ( ) ; i + + ) {
2023-06-09 18:33:05 +02:00
String old_path = to_move [ i ] . path ;
String new_path = new_paths [ i ] ;
if ( ! to_move [ i ] . is_file ) {
new_path = new_path . path_join ( old_path . trim_suffix ( " / " ) . get_file ( ) ) ;
print_line ( new_path ) ;
}
2023-03-25 20:58:37 +01:00
if ( old_path ! = new_path ) {
_try_move_item ( to_move [ i ] , new_path , file_renames , folder_renames ) ;
is_moved = true ;
}
}
2019-06-04 05:36:23 +02:00
2023-03-25 20:58:37 +01:00
if ( is_moved ) {
int current_tab = EditorNode : : get_singleton ( ) - > get_current_tab ( ) ;
_save_scenes_after_move ( file_renames ) ; // Save scenes before updating.
_update_dependencies_after_move ( file_renames ) ;
_update_resource_paths_after_move ( file_renames ) ;
_update_project_settings_after_move ( file_renames ) ;
_update_favorites_list_after_move ( file_renames , folder_renames ) ;
2021-01-16 16:30:56 +01:00
2023-03-25 20:58:37 +01:00
EditorNode : : get_singleton ( ) - > set_current_tab ( current_tab ) ;
print_verbose ( " FileSystem: calling rescan. " ) ;
_rescan ( ) ;
print_verbose ( " FileSystem: saving moved scenes. " ) ;
_save_scenes_after_move ( file_renames ) ;
2023-05-11 04:17:03 +02:00
current_path = p_to_path ;
current_path_line_edit - > set_text ( current_path ) ;
2023-03-25 20:58:37 +01:00
}
2018-06-19 00:43:16 +02:00
}
2015-08-24 01:15:56 +02:00
}
2022-05-10 22:25:36 +02:00
Vector < String > FileSystemDock : : _tree_get_selected ( bool remove_self_inclusion ) const {
2019-08-22 06:22:52 +02:00
// Build a list of selected items with the active one at the first position.
2018-08-23 17:00:30 +02:00
Vector < String > selected_strings ;
2021-03-07 21:07:30 +01:00
TreeItem * favorites_item = tree - > get_root ( ) - > get_first_child ( ) ;
2018-08-23 17:00:30 +02:00
TreeItem * active_selected = tree - > get_selected ( ) ;
2018-09-29 00:11:26 +02:00
if ( active_selected & & active_selected ! = favorites_item ) {
2018-08-23 17:00:30 +02:00
selected_strings . push_back ( active_selected - > get_metadata ( 0 ) ) ;
}
TreeItem * selected = tree - > get_root ( ) ;
selected = tree - > get_next_selected ( selected ) ;
while ( selected ) {
2018-09-29 00:11:26 +02:00
if ( selected ! = active_selected & & selected ! = favorites_item ) {
2018-08-23 17:00:30 +02:00
selected_strings . push_back ( selected - > get_metadata ( 0 ) ) ;
}
selected = tree - > get_next_selected ( selected ) ;
}
2019-08-10 01:15:25 +02:00
if ( remove_self_inclusion ) {
selected_strings = _remove_self_included_paths ( selected_strings ) ;
}
return selected_strings ;
}
Vector < String > FileSystemDock : : _remove_self_included_paths ( Vector < String > selected_strings ) {
2019-08-22 06:22:52 +02:00
// Remove paths or files that are included into another.
2019-08-10 01:15:25 +02:00
if ( selected_strings . size ( ) > 1 ) {
2018-08-23 17:00:30 +02:00
selected_strings . sort_custom < NaturalNoCaseComparator > ( ) ;
String last_path = " " ;
for ( int i = 0 ; i < selected_strings . size ( ) ; i + + ) {
2021-12-09 10:42:46 +01:00
if ( ! last_path . is_empty ( ) & & selected_strings [ i ] . begins_with ( last_path ) ) {
2021-07-04 00:17:03 +02:00
selected_strings . remove_at ( i ) ;
2018-08-23 17:00:30 +02:00
i - - ;
}
if ( selected_strings [ i ] . ends_with ( " / " ) ) {
last_path = selected_strings [ i ] ;
}
}
}
return selected_strings ;
}
void FileSystemDock : : _tree_rmb_option ( int p_option ) {
2019-08-10 01:15:25 +02:00
Vector < String > selected_strings = _tree_get_selected ( false ) ;
2018-08-23 17:00:30 +02:00
2019-08-22 06:22:52 +02:00
// Execute the current option.
2017-03-05 16:44:50 +01:00
switch ( p_option ) {
2018-08-23 17:00:30 +02:00
case FOLDER_EXPAND_ALL :
case FOLDER_COLLAPSE_ALL : {
// Expand or collapse the folder
if ( selected_strings . size ( ) = = 1 ) {
2022-07-01 15:43:39 +02:00
tree - > get_selected ( ) - > set_collapsed_recursive ( p_option = = FOLDER_COLLAPSE_ALL ) ;
2018-03-28 11:34:46 +02:00
}
2018-08-23 17:00:30 +02:00
} break ;
default : {
_file_option ( p_option , selected_strings ) ;
} break ;
}
}
2018-03-28 11:34:46 +02:00
2018-08-23 17:00:30 +02:00
void FileSystemDock : : _file_list_rmb_option ( int p_option ) {
Vector < int > selected_id = files - > get_selected_items ( ) ;
Vector < String > selected ;
for ( int i = 0 ; i < selected_id . size ( ) ; i + + ) {
selected . push_back ( files - > get_item_metadata ( selected_id [ i ] ) ) ;
}
_file_option ( p_option , selected ) ;
}
2019-07-10 11:54:12 +02:00
void FileSystemDock : : _file_option ( int p_option , const Vector < String > & p_selected ) {
2019-08-22 06:22:52 +02:00
// The first one should be the active item.
2018-08-23 17:00:30 +02:00
switch ( p_option ) {
case FILE_SHOW_IN_EXPLORER : {
2019-08-22 06:22:52 +02:00
// Show the file/folder in the OS explorer.
2023-05-11 04:17:03 +02:00
String fpath = current_path ;
if ( current_path = = " Favorites " ) {
2019-04-06 22:49:32 +02:00
fpath = p_selected [ 0 ] ;
}
2018-08-23 17:00:30 +02:00
String dir = ProjectSettings : : get_singleton ( ) - > globalize_path ( fpath ) ;
2022-12-07 04:33:35 +01:00
OS : : get_singleton ( ) - > shell_show_in_file_manager ( dir , true ) ;
2017-10-09 15:59:48 +02:00
} break ;
2018-08-23 17:00:30 +02:00
2022-11-10 22:26:40 +01:00
case FILE_OPEN_EXTERNAL : {
2023-05-11 04:17:03 +02:00
String fpath = current_path ;
if ( current_path = = " Favorites " ) {
2022-11-10 22:26:40 +01:00
fpath = p_selected [ 0 ] ;
}
String file = ProjectSettings : : get_singleton ( ) - > globalize_path ( fpath ) ;
String resource_type = ResourceLoader : : get_resource_type ( fpath ) ;
String external_program ;
if ( resource_type = = " CompressedTexture2D " | | resource_type = = " Image " ) {
if ( file . get_extension ( ) = = " svg " | | file . get_extension ( ) = = " svgz " ) {
external_program = EDITOR_GET ( " filesystem/external_programs/vector_image_editor " ) ;
} else {
external_program = EDITOR_GET ( " filesystem/external_programs/raster_image_editor " ) ;
}
} else if ( ClassDB : : is_parent_class ( resource_type , " AudioStream " ) ) {
external_program = EDITOR_GET ( " filesystem/external_programs/audio_editor " ) ;
} else if ( resource_type = = " PackedScene " ) {
// Ignore non-model scenes.
if ( file . get_extension ( ) ! = " tscn " & & file . get_extension ( ) ! = " scn " & & file . get_extension ( ) ! = " res " ) {
external_program = EDITOR_GET ( " filesystem/external_programs/3d_model_editor " ) ;
}
} else if ( ClassDB : : is_parent_class ( resource_type , " Script " ) ) {
external_program = EDITOR_GET ( " text_editor/external/exec_path " ) ;
}
if ( external_program . is_empty ( ) ) {
OS : : get_singleton ( ) - > shell_open ( file ) ;
} else {
List < String > args ;
args . push_back ( file ) ;
OS : : get_singleton ( ) - > create_process ( external_program , args ) ;
}
} break ;
2016-05-16 01:25:51 +02:00
case FILE_OPEN : {
2019-08-22 06:22:52 +02:00
// Open folders.
2019-05-10 16:50:43 +02:00
TreeItem * selected = tree - > get_root ( ) ;
selected = tree - > get_next_selected ( selected ) ;
while ( selected ) {
if ( p_selected . find ( selected - > get_metadata ( 0 ) ) > = 0 ) {
selected - > set_collapsed ( false ) ;
}
selected = tree - > get_next_selected ( selected ) ;
}
2019-08-22 06:22:52 +02:00
// Open the file.
2018-08-23 17:00:30 +02:00
for ( int i = 0 ; i < p_selected . size ( ) ; i + + ) {
_select_file ( p_selected [ i ] ) ;
2017-12-01 09:01:50 +01:00
}
2016-05-16 01:25:51 +02:00
} break ;
2019-05-08 04:35:23 +02:00
case FILE_INHERIT : {
2019-08-22 06:22:52 +02:00
// Create a new scene inherited from the selected one.
2019-05-08 04:35:23 +02:00
if ( p_selected . size ( ) = = 1 ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " inherit " ) , p_selected [ 0 ] ) ;
2019-05-08 04:35:23 +02:00
}
} break ;
2019-10-29 19:24:38 +01:00
case FILE_MAIN_SCENE : {
// Set as main scene with selected scene file.
if ( p_selected . size ( ) = = 1 ) {
ProjectSettings : : get_singleton ( ) - > set ( " application/run/main_scene " , p_selected [ 0 ] ) ;
ProjectSettings : : get_singleton ( ) - > save ( ) ;
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2020-01-09 01:51:31 +01:00
_update_file_list ( true ) ;
2019-10-29 19:24:38 +01:00
}
} break ;
2022-11-16 00:13:39 +01:00
case FILE_INSTANTIATE : {
// Instantiate all selected scenes.
2016-07-20 19:09:03 +02:00
Vector < String > paths ;
2018-08-23 17:00:30 +02:00
for ( int i = 0 ; i < p_selected . size ( ) ; i + + ) {
String fpath = p_selected [ i ] ;
2017-09-03 22:35:18 +02:00
if ( EditorFileSystem : : get_singleton ( ) - > get_file_type ( fpath ) = = " PackedScene " ) {
paths . push_back ( fpath ) ;
2016-05-16 01:25:51 +02:00
}
}
2020-12-15 13:04:21 +01:00
if ( ! paths . is_empty ( ) ) {
2022-11-16 00:13:39 +01:00
emit_signal ( SNAME ( " instantiate " ) , paths ) ;
2016-07-20 19:09:03 +02:00
}
2016-05-16 01:25:51 +02:00
} break ;
2015-08-24 01:15:56 +02:00
2018-09-13 18:11:05 +02:00
case FILE_ADD_FAVORITE : {
2019-08-22 06:22:52 +02:00
// Add the files from favorites.
2022-09-29 11:53:28 +02:00
Vector < String > favorites_list = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
2018-09-13 18:11:05 +02:00
for ( int i = 0 ; i < p_selected . size ( ) ; i + + ) {
2022-09-29 11:53:28 +02:00
if ( ! favorites_list . has ( p_selected [ i ] ) ) {
favorites_list . push_back ( p_selected [ i ] ) ;
2018-09-13 18:11:05 +02:00
}
}
2022-09-29 11:53:28 +02:00
EditorSettings : : get_singleton ( ) - > set_favorites ( favorites_list ) ;
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2018-09-13 18:11:05 +02:00
} break ;
case FILE_REMOVE_FAVORITE : {
2019-08-22 06:22:52 +02:00
// Remove the files from favorites.
2022-09-29 11:53:28 +02:00
Vector < String > favorites_list = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
2018-09-13 18:11:05 +02:00
for ( int i = 0 ; i < p_selected . size ( ) ; i + + ) {
2022-09-29 11:53:28 +02:00
favorites_list . erase ( p_selected [ i ] ) ;
2018-09-13 18:11:05 +02:00
}
2022-09-29 11:53:28 +02:00
EditorSettings : : get_singleton ( ) - > set_favorites ( favorites_list ) ;
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
if ( current_path = = " Favorites " ) {
2018-09-29 00:11:26 +02:00
_update_file_list ( true ) ;
2020-05-14 16:41:43 +02:00
}
2018-09-13 18:11:05 +02:00
} break ;
2018-08-23 17:00:30 +02:00
case FILE_DEPENDENCIES : {
2019-08-22 06:22:52 +02:00
// Checkout the file dependencies.
2020-12-15 13:04:21 +01:00
if ( ! p_selected . is_empty ( ) ) {
2018-08-23 17:00:30 +02:00
String fpath = p_selected [ 0 ] ;
deps_editor - > edit ( fpath ) ;
}
2015-08-24 01:15:56 +02:00
} break ;
2018-08-23 17:00:30 +02:00
case FILE_OWNERS : {
2019-08-22 06:22:52 +02:00
// Checkout the file owners.
2020-12-15 13:04:21 +01:00
if ( ! p_selected . is_empty ( ) ) {
2018-08-23 17:00:30 +02:00
String fpath = p_selected [ 0 ] ;
owners_editor - > show ( fpath ) ;
}
2015-08-24 01:15:56 +02:00
} break ;
2018-08-23 17:00:30 +02:00
2015-08-24 01:15:56 +02:00
case FILE_MOVE : {
2023-03-25 20:58:37 +01:00
// Move or copy the files to a given location.
2017-10-01 23:59:27 +02:00
to_move . clear ( ) ;
2019-08-10 01:15:25 +02:00
Vector < String > collapsed_paths = _remove_self_included_paths ( p_selected ) ;
for ( int i = collapsed_paths . size ( ) - 1 ; i > = 0 ; i - - ) {
String fpath = collapsed_paths [ i ] ;
2018-08-23 17:00:30 +02:00
if ( fpath ! = " res:// " ) {
to_move . push_back ( FileOrFolder ( fpath , ! fpath . ends_with ( " / " ) ) ) ;
}
2015-08-24 01:15:56 +02:00
}
2017-10-01 23:59:27 +02:00
if ( to_move . size ( ) > 0 ) {
2023-03-25 20:58:37 +01:00
move_dialog - > popup_centered_ratio ( 0.4 ) ;
2015-08-24 01:15:56 +02:00
}
2017-10-01 23:59:27 +02:00
} break ;
2015-08-24 01:15:56 +02:00
2018-08-23 17:00:30 +02:00
case FILE_RENAME : {
2023-05-26 23:04:14 +02:00
if ( ! p_selected . is_empty ( ) ) {
2022-11-26 15:58:25 +01:00
// Set to_rename variable for callback execution.
2018-08-23 17:00:30 +02:00
to_rename . path = p_selected [ 0 ] ;
2022-11-26 15:58:25 +01:00
to_rename . is_file = ! to_rename . path . ends_with ( " / " ) ;
2023-05-26 23:04:14 +02:00
if ( to_rename . path = = " res:// " ) {
break ;
}
2022-11-26 15:58:25 +01:00
2023-05-26 23:04:14 +02:00
if ( tree - > has_focus ( ) ) {
// Edit node in Tree.
tree - > edit_selected ( true ) ;
2022-11-26 15:58:25 +01:00
2023-05-26 23:04:14 +02:00
if ( to_rename . is_file ) {
String name = to_rename . path . get_file ( ) ;
tree - > set_editor_selection ( 0 , name . rfind ( " . " ) ) ;
} else {
String name = to_rename . path . left ( - 1 ) . get_file ( ) ; // Removes the "/" suffix for folders.
tree - > set_editor_selection ( 0 , name . length ( ) ) ;
}
} else if ( files - > has_focus ( ) ) {
files - > edit_selected ( ) ;
2018-08-23 17:00:30 +02:00
}
2017-10-01 23:59:27 +02:00
}
2015-08-24 01:15:56 +02:00
} break ;
2018-08-23 17:00:30 +02:00
2015-08-24 01:15:56 +02:00
case FILE_REMOVE : {
2019-08-22 06:22:52 +02:00
// Remove the selected files.
2017-10-02 00:24:49 +02:00
Vector < String > remove_files ;
Vector < String > remove_folders ;
2019-08-10 01:15:25 +02:00
Vector < String > collapsed_paths = _remove_self_included_paths ( p_selected ) ;
2015-08-24 01:15:56 +02:00
2019-08-10 01:15:25 +02:00
for ( int i = 0 ; i < collapsed_paths . size ( ) ; i + + ) {
String fpath = collapsed_paths [ i ] ;
2018-08-23 17:00:30 +02:00
if ( fpath ! = " res:// " ) {
2017-09-03 22:35:18 +02:00
if ( fpath . ends_with ( " / " ) ) {
remove_folders . push_back ( fpath ) ;
2017-10-02 00:24:49 +02:00
} else {
2017-09-03 22:35:18 +02:00
remove_files . push_back ( fpath ) ;
2017-10-02 00:24:49 +02:00
}
}
2015-08-24 01:15:56 +02:00
}
2017-10-02 00:24:49 +02:00
if ( remove_files . size ( ) + remove_folders . size ( ) > 0 ) {
remove_dialog - > show ( remove_folders , remove_files ) ;
2015-08-24 01:15:56 +02:00
}
} break ;
2017-12-01 12:13:50 +01:00
2018-08-23 17:00:30 +02:00
case FILE_DUPLICATE : {
2019-08-22 06:22:52 +02:00
// Duplicate the selected files.
2018-08-23 17:00:30 +02:00
for ( int i = 0 ; i < p_selected . size ( ) ; i + + ) {
to_duplicate . path = p_selected [ i ] ;
to_duplicate . is_file = ! to_duplicate . path . ends_with ( " / " ) ;
if ( to_duplicate . is_file ) {
String name = to_duplicate . path . get_file ( ) ;
duplicate_dialog - > set_title ( TTR ( " Duplicating file: " ) + " " + name ) ;
duplicate_dialog_text - > set_text ( name ) ;
2020-07-03 15:26:22 +02:00
duplicate_dialog_text - > select ( 0 , name . rfind ( " . " ) ) ;
2018-08-23 17:00:30 +02:00
} else {
String name = to_duplicate . path . substr ( 0 , to_duplicate . path . length ( ) - 1 ) . get_file ( ) ;
duplicate_dialog - > set_title ( TTR ( " Duplicating folder: " ) + " " + name ) ;
duplicate_dialog_text - > set_text ( name ) ;
duplicate_dialog_text - > select ( 0 , name . length ( ) ) ;
}
2020-03-06 18:00:16 +01:00
duplicate_dialog - > popup_centered ( Size2 ( 250 , 80 ) * EDSCALE ) ;
2018-08-23 17:00:30 +02:00
duplicate_dialog_text - > grab_focus ( ) ;
2017-12-01 12:13:50 +01:00
}
} break ;
2018-08-23 17:00:30 +02:00
2015-08-24 01:15:56 +02:00
case FILE_INFO : {
} break ;
2016-05-27 19:18:40 +02:00
2018-08-23 17:00:30 +02:00
case FILE_REIMPORT : {
2019-08-22 06:22:52 +02:00
// Reimport all selected files.
2016-05-27 19:18:40 +02:00
Vector < String > reimport ;
2018-08-23 17:00:30 +02:00
for ( int i = 0 ; i < p_selected . size ( ) ; i + + ) {
reimport . push_back ( p_selected [ i ] ) ;
2016-05-27 19:18:40 +02:00
}
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_MSG ( reimport . size ( ) = = 0 , " You need to select files to reimport them. " ) ;
2016-05-27 19:18:40 +02:00
} break ;
2018-08-23 17:00:30 +02:00
2017-10-02 00:33:43 +02:00
case FILE_NEW_FOLDER : {
2023-05-11 04:17:03 +02:00
String directory = current_path ;
2023-04-15 12:15:57 +02:00
if ( ! directory . ends_with ( " / " ) ) {
directory = directory . get_base_dir ( ) ;
}
make_dir_dialog - > config ( directory ) ;
make_dir_dialog - > popup_centered ( ) ;
2017-10-02 00:33:43 +02:00
} break ;
2018-08-23 17:00:30 +02:00
2019-08-15 19:47:21 +02:00
case FILE_NEW_SCENE : {
2023-05-11 04:17:03 +02:00
String directory = current_path ;
2022-06-12 02:11:52 +02:00
if ( ! directory . ends_with ( " / " ) ) {
directory = directory . get_base_dir ( ) ;
}
make_scene_dialog - > config ( directory ) ;
make_scene_dialog - > popup_centered ( ) ;
2019-08-15 19:47:21 +02:00
} break ;
2018-04-25 09:18:10 +02:00
case FILE_NEW_SCRIPT : {
2023-05-11 04:17:03 +02:00
String fpath = current_path ;
2018-08-23 17:00:30 +02:00
if ( ! fpath . ends_with ( " / " ) ) {
fpath = fpath . get_base_dir ( ) ;
2018-04-25 09:18:10 +02:00
}
2022-08-30 02:34:01 +02:00
make_script_dialog - > config ( " Node " , fpath . path_join ( " new_script.gd " ) , false , false ) ;
2020-01-08 05:15:05 +01:00
make_script_dialog - > popup_centered ( ) ;
2018-04-25 09:18:10 +02:00
} break ;
2018-08-23 17:00:30 +02:00
2017-10-09 15:59:48 +02:00
case FILE_COPY_PATH : {
2020-12-15 13:04:21 +01:00
if ( ! p_selected . is_empty ( ) ) {
2018-08-23 17:00:30 +02:00
String fpath = p_selected [ 0 ] ;
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > clipboard_set ( fpath ) ;
2018-08-23 17:00:30 +02:00
}
2017-10-09 15:59:48 +02:00
} break ;
2018-08-23 17:00:30 +02:00
2022-05-02 11:51:23 +02:00
case FILE_COPY_UID : {
if ( ! p_selected . is_empty ( ) ) {
ResourceUID : : ID uid = ResourceLoader : : get_resource_uid ( p_selected [ 0 ] ) ;
if ( uid ! = ResourceUID : : INVALID_ID ) {
String uid_string = ResourceUID : : get_singleton ( ) - > id_to_text ( uid ) ;
DisplayServer : : get_singleton ( ) - > clipboard_set ( uid_string ) ;
}
}
} break ;
2018-07-22 17:53:40 +02:00
case FILE_NEW_RESOURCE : {
new_resource_dialog - > popup_create ( true ) ;
} break ;
2021-09-23 23:09:15 +02:00
case FILE_NEW_TEXTFILE : {
2023-05-11 04:17:03 +02:00
String fpath = current_path ;
2021-09-23 23:09:15 +02:00
if ( ! fpath . ends_with ( " / " ) ) {
fpath = fpath . get_base_dir ( ) ;
}
2023-01-14 17:43:33 +01:00
String dir = ProjectSettings : : get_singleton ( ) - > globalize_path ( fpath ) ;
ScriptEditor : : get_singleton ( ) - > open_text_file_create_dialog ( dir ) ;
2021-09-23 23:09:15 +02:00
} break ;
2015-08-24 01:15:56 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-02-21 17:44:59 +01:00
void FileSystemDock : : _resource_created ( ) {
2023-05-11 04:17:03 +02:00
String fpath = current_path ;
2021-12-03 15:45:32 +01:00
if ( ! fpath . ends_with ( " / " ) ) {
fpath = fpath . get_base_dir ( ) ;
}
String type_name = new_resource_dialog - > get_selected_type ( ) ;
if ( type_name = = " Shader " ) {
2022-08-30 02:34:01 +02:00
make_shader_dialog - > config ( fpath . path_join ( " new_shader " ) , false , false , 0 ) ;
2021-12-03 15:45:32 +01:00
make_shader_dialog - > popup_centered ( ) ;
return ;
} else if ( type_name = = " VisualShader " ) {
2022-08-30 02:34:01 +02:00
make_shader_dialog - > config ( fpath . path_join ( " new_shader " ) , false , false , 1 ) ;
2021-12-03 15:45:32 +01:00
make_shader_dialog - > popup_centered ( ) ;
return ;
2022-03-08 11:39:16 +01:00
} else if ( type_name = = " ShaderInclude " ) {
2022-08-30 02:34:01 +02:00
make_shader_dialog - > config ( fpath . path_join ( " new_shader_include " ) , false , false , 2 ) ;
2022-03-08 11:39:16 +01:00
make_shader_dialog - > popup_centered ( ) ;
return ;
2021-12-03 15:45:32 +01:00
}
2022-11-16 00:13:39 +01:00
Variant c = new_resource_dialog - > instantiate_selected ( ) ;
2018-07-22 17:53:40 +02:00
ERR_FAIL_COND ( ! c ) ;
Resource * r = Object : : cast_to < Resource > ( c ) ;
ERR_FAIL_COND ( ! r ) ;
2020-02-09 07:21:10 +01:00
PackedScene * scene = Object : : cast_to < PackedScene > ( r ) ;
if ( scene ) {
Node * node = memnew ( Node ) ;
node - > set_name ( " Node " ) ;
scene - > pack ( node ) ;
memdelete ( node ) ;
}
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > push_item ( r ) ;
2022-05-03 01:43:50 +02:00
EditorNode : : get_singleton ( ) - > save_resource_as ( Ref < Resource > ( r ) , fpath ) ;
2017-01-10 13:19:59 +01:00
}
2018-09-13 21:49:56 +02:00
void FileSystemDock : : _search_changed ( const String & p_text , const Control * p_from ) {
2019-11-21 15:40:11 +01:00
if ( searched_string . length ( ) = = 0 ) {
2019-08-22 06:22:52 +02:00
// Register the uncollapsed paths before they change.
2023-05-11 04:17:03 +02:00
uncollapsed_paths_before_search = get_uncollapsed_paths ( ) ;
2018-09-13 23:28:21 +02:00
}
2018-09-13 21:49:56 +02:00
searched_string = p_text . to_lower ( ) ;
2015-08-24 01:15:56 +02:00
2020-05-14 16:41:43 +02:00
if ( p_from = = tree_search_box ) {
2018-09-13 21:49:56 +02:00
file_list_search_box - > set_text ( searched_string ) ;
2020-05-14 16:41:43 +02:00
} else { // File_list_search_box.
2018-09-13 21:49:56 +02:00
tree_search_box - > set_text ( searched_string ) ;
2020-05-14 16:41:43 +02:00
}
2018-09-13 21:49:56 +02:00
2023-05-11 04:17:03 +02:00
bool unfold_path = ( p_text . is_empty ( ) & & ! current_path . is_empty ( ) ) ;
2018-09-13 21:49:56 +02:00
switch ( display_mode ) {
case DISPLAY_MODE_TREE_ONLY : {
2019-11-21 15:40:11 +01:00
_update_tree ( searched_string . length ( ) = = 0 ? uncollapsed_paths_before_search : Vector < String > ( ) , false , false , unfold_path ) ;
2018-09-13 21:49:56 +02:00
} break ;
case DISPLAY_MODE_SPLIT : {
2018-09-28 13:26:36 +02:00
_update_file_list ( false ) ;
2019-11-21 15:40:11 +01:00
_update_tree ( searched_string . length ( ) = = 0 ? uncollapsed_paths_before_search : Vector < String > ( ) , false , false , unfold_path ) ;
2018-09-13 21:49:56 +02:00
} break ;
}
2016-05-16 01:25:51 +02:00
}
2015-08-24 01:15:56 +02:00
2016-07-21 15:34:57 +02:00
void FileSystemDock : : _rescan ( ) {
2017-01-21 13:07:29 +01:00
_set_scanning_mode ( ) ;
2014-02-10 02:10:30 +01:00
EditorFileSystem : : get_singleton ( ) - > scan ( ) ;
2015-08-24 01:15:56 +02:00
}
2018-09-14 00:16:43 +02:00
void FileSystemDock : : _toggle_split_mode ( bool p_active ) {
2019-02-25 23:39:49 +01:00
set_display_mode ( p_active ? DISPLAY_MODE_SPLIT : DISPLAY_MODE_TREE_ONLY ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " display_mode_changed " ) ) ;
2018-09-14 00:16:43 +02:00
}
2017-03-05 16:44:50 +01:00
void FileSystemDock : : fix_dependencies ( const String & p_for_file ) {
2015-08-24 01:15:56 +02:00
deps_editor - > edit ( p_for_file ) ;
}
2016-07-21 15:34:57 +02:00
void FileSystemDock : : focus_on_filter ( ) {
2021-06-04 01:22:50 +02:00
LineEdit * current_search_box = nullptr ;
if ( display_mode = = DISPLAY_MODE_TREE_ONLY ) {
current_search_box = tree_search_box ;
} else if ( display_mode = = DISPLAY_MODE_SPLIT ) {
current_search_box = file_list_search_box ;
}
if ( current_search_box ) {
current_search_box - > grab_focus ( ) ;
current_search_box - > select_all ( ) ;
}
2014-02-10 02:10:30 +01:00
}
2022-03-10 17:46:31 +01:00
ScriptCreateDialog * FileSystemDock : : get_script_create_dialog ( ) const {
return make_script_dialog ;
}
2019-02-25 23:39:49 +01:00
void FileSystemDock : : set_file_list_display_mode ( FileListDisplayMode p_mode ) {
2020-05-14 16:41:43 +02:00
if ( p_mode = = file_list_display_mode ) {
2016-08-16 18:25:42 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-12-15 17:39:13 +01:00
2019-03-05 07:55:08 +01:00
_toggle_file_display ( ) ;
2015-12-15 17:39:13 +01:00
}
2022-07-20 23:44:06 +02:00
void FileSystemDock : : add_resource_tooltip_plugin ( const Ref < EditorResourceTooltipPlugin > & p_plugin ) {
tooltip_plugins . push_back ( p_plugin ) ;
}
void FileSystemDock : : remove_resource_tooltip_plugin ( const Ref < EditorResourceTooltipPlugin > & p_plugin ) {
int index = tooltip_plugins . find ( p_plugin ) ;
ERR_FAIL_COND_MSG ( index = = - 1 , " Can't remove plugin that wasn't registered. " ) ;
tooltip_plugins . remove_at ( index ) ;
}
Control * FileSystemDock : : create_tooltip_for_path ( const String & p_path ) const {
2023-05-24 14:22:03 +02:00
if ( p_path = = " Favorites " ) {
// No tooltip for the "Favorites" group.
return nullptr ;
}
2022-07-20 23:44:06 +02:00
if ( DirAccess : : exists ( p_path ) ) {
// No tooltip for directory.
return nullptr ;
}
const String type = ResourceLoader : : get_resource_type ( p_path ) ;
2023-05-18 17:03:22 +02:00
Control * tooltip = EditorResourceTooltipPlugin : : make_default_tooltip ( p_path ) ;
2022-07-20 23:44:06 +02:00
for ( const Ref < EditorResourceTooltipPlugin > & plugin : tooltip_plugins ) {
if ( plugin - > handles ( type ) ) {
2023-05-18 17:03:22 +02:00
tooltip = plugin - > make_tooltip_for_path ( p_path , EditorResourcePreview : : get_singleton ( ) - > get_preview_metadata ( p_path ) , tooltip ) ;
2022-07-20 23:44:06 +02:00
}
}
return tooltip ;
}
2017-03-05 16:44:50 +01:00
Variant FileSystemDock : : get_drag_data_fw ( const Point2 & p_point , Control * p_from ) {
2018-08-23 17:00:30 +02:00
bool all_favorites = true ;
bool all_not_favorites = true ;
2017-10-25 00:09:04 +02:00
Vector < String > paths ;
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
if ( p_from = = tree ) {
2019-08-22 06:22:52 +02:00
// Check if the first selected is in favorite.
2018-08-23 17:00:30 +02:00
TreeItem * selected = tree - > get_next_selected ( tree - > get_root ( ) ) ;
while ( selected ) {
2021-03-07 21:07:30 +01:00
TreeItem * favorites_item = tree - > get_root ( ) - > get_first_child ( ) ;
2018-09-29 00:11:26 +02:00
if ( selected = = favorites_item ) {
2019-08-22 06:22:52 +02:00
// The "Favorites" item is not draggable.
2018-09-29 00:11:26 +02:00
return Variant ( ) ;
}
2021-03-07 21:07:30 +01:00
bool is_favorite = selected - > get_parent ( ) ! = nullptr & & tree - > get_root ( ) - > get_first_child ( ) = = selected - > get_parent ( ) ;
2018-08-23 17:00:30 +02:00
all_favorites & = is_favorite ;
all_not_favorites & = ! is_favorite ;
selected = tree - > get_next_selected ( selected ) ;
}
2019-10-20 19:39:21 +02:00
if ( ! all_not_favorites ) {
2018-08-23 17:00:30 +02:00
paths = _tree_get_selected ( false ) ;
} else {
paths = _tree_get_selected ( ) ;
}
2017-10-25 00:09:04 +02:00
} else if ( p_from = = files ) {
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < files - > get_item_count ( ) ; i + + ) {
2016-05-11 16:46:08 +02:00
if ( files - > is_selected ( i ) ) {
2017-10-25 00:09:04 +02:00
paths . push_back ( files - > get_item_metadata ( i ) ) ;
2016-05-11 16:46:08 +02:00
}
}
2018-08-23 17:00:30 +02:00
all_favorites = false ;
all_not_favorites = true ;
2017-10-25 00:09:04 +02:00
}
2016-05-11 16:46:08 +02:00
2020-12-15 13:04:21 +01:00
if ( paths . is_empty ( ) ) {
2017-10-25 00:09:04 +02:00
return Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-09-03 22:35:18 +02:00
2017-10-25 00:09:04 +02:00
Dictionary drag_data = EditorNode : : get_singleton ( ) - > drag_files_and_dirs ( paths , p_from ) ;
2019-10-20 19:39:21 +02:00
if ( ! all_not_favorites ) {
drag_data [ " favorite " ] = all_favorites ? " all " : " mixed " ;
2016-05-11 16:46:08 +02:00
}
2017-10-25 00:09:04 +02:00
return drag_data ;
2016-05-11 16:46:08 +02:00
}
2017-03-05 16:44:50 +01:00
bool FileSystemDock : : can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
2016-05-11 16:46:08 +02:00
Dictionary drag_data = p_data ;
2019-10-20 19:39:21 +02:00
if ( drag_data . has ( " favorite " ) ) {
if ( String ( drag_data [ " favorite " ] ) ! = " all " ) {
return false ;
}
2016-05-24 04:24:17 +02:00
2019-08-22 06:22:52 +02:00
// Moving favorite around.
2017-09-10 15:37:49 +02:00
TreeItem * ti = tree - > get_item_at_position ( p_point ) ;
2020-05-14 16:41:43 +02:00
if ( ! ti ) {
2016-05-24 04:24:17 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2016-05-24 04:24:17 +02:00
2018-08-23 17:00:30 +02:00
int drop_section = tree - > get_drop_section_at_position ( p_point ) ;
2021-03-07 21:07:30 +01:00
TreeItem * favorites_item = tree - > get_root ( ) - > get_first_child ( ) ;
2018-09-14 13:59:19 +02:00
2018-08-23 17:00:30 +02:00
TreeItem * resources_item = favorites_item - > get_next ( ) ;
2016-05-24 04:24:17 +02:00
2018-08-23 17:00:30 +02:00
if ( ti = = favorites_item ) {
2019-08-22 06:22:52 +02:00
return ( drop_section = = 1 ) ; // The parent, first fav.
2016-05-24 04:24:17 +02:00
}
2018-08-23 17:00:30 +02:00
if ( ti - > get_parent ( ) & & favorites_item = = ti - > get_parent ( ) ) {
return true ; // A favorite
2016-05-24 04:24:17 +02:00
}
2018-08-23 17:00:30 +02:00
if ( ti = = resources_item ) {
2019-08-22 06:22:52 +02:00
return ( drop_section = = - 1 ) ; // The tree, last fav.
2016-05-24 04:24:17 +02:00
}
return false ;
}
2017-03-05 16:44:50 +01:00
if ( drag_data . has ( " type " ) & & String ( drag_data [ " type " ] ) = = " resource " ) {
2019-08-22 06:22:52 +02:00
// Move resources.
2018-09-13 22:38:35 +02:00
String to_dir ;
bool favorite ;
_get_drag_target_folder ( to_dir , favorite , p_point , p_from ) ;
2020-12-15 13:04:21 +01:00
return ! to_dir . is_empty ( ) ;
2016-05-11 16:46:08 +02:00
}
2017-03-05 16:44:50 +01:00
if ( drag_data . has ( " type " ) & & ( String ( drag_data [ " type " ] ) = = " files " | | String ( drag_data [ " type " ] ) = = " files_and_dirs " ) ) {
2019-08-22 06:22:52 +02:00
// Move files or dir.
2018-09-13 22:38:35 +02:00
String to_dir ;
bool favorite ;
_get_drag_target_folder ( to_dir , favorite , p_point , p_from ) ;
2020-05-14 16:41:43 +02:00
if ( favorite ) {
2018-09-13 22:38:35 +02:00
return true ;
2020-05-14 16:41:43 +02:00
}
2018-09-13 22:38:35 +02:00
2020-12-15 13:04:21 +01:00
if ( to_dir . is_empty ( ) ) {
2017-10-25 16:27:35 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
2019-08-22 06:22:52 +02:00
// Attempting to move a folder into itself will fail later,
2020-02-04 23:20:01 +01:00
// rather than bring up a message don't try to do it in the first place.
2017-10-25 16:27:35 +02:00
to_dir = to_dir . ends_with ( " / " ) ? to_dir : ( to_dir + " / " ) ;
2016-05-11 16:46:08 +02:00
Vector < String > fnames = drag_data [ " files " ] ;
2017-10-25 16:27:35 +02:00
for ( int i = 0 ; i < fnames . size ( ) ; + + i ) {
2020-05-14 16:41:43 +02:00
if ( fnames [ i ] . ends_with ( " / " ) & & to_dir . begins_with ( fnames [ i ] ) ) {
2016-05-16 01:25:51 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2016-05-16 01:25:51 +02:00
}
2017-10-25 16:27:35 +02:00
return true ;
2016-05-11 16:46:08 +02:00
}
2021-09-09 00:43:14 +02:00
if ( drag_data . has ( " type " ) & & String ( drag_data [ " type " ] ) = = " nodes " ) {
// Save branch as scene.
String to_dir ;
bool favorite ;
_get_drag_target_folder ( to_dir , favorite , p_point , p_from ) ;
return ! favorite & & Array ( drag_data [ " nodes " ] ) . size ( ) = = 1 ;
}
2016-05-11 16:46:08 +02:00
return false ;
}
2017-03-05 16:44:50 +01:00
void FileSystemDock : : drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
2020-05-14 16:41:43 +02:00
if ( ! can_drop_data_fw ( p_point , p_data , p_from ) ) {
2016-05-11 16:46:08 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
Dictionary drag_data = p_data ;
2018-09-18 14:02:59 +02:00
Vector < String > dirs = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
2016-05-24 04:24:17 +02:00
2019-10-20 19:39:21 +02:00
if ( drag_data . has ( " favorite " ) ) {
if ( String ( drag_data [ " favorite " ] ) ! = " all " ) {
return ;
}
2019-08-22 06:22:52 +02:00
// Moving favorite around.
2017-09-10 15:37:49 +02:00
TreeItem * ti = tree - > get_item_at_position ( p_point ) ;
2020-05-14 16:41:43 +02:00
if ( ! ti ) {
2016-05-24 04:24:17 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-08-23 17:00:30 +02:00
int drop_section = tree - > get_drop_section_at_position ( p_point ) ;
2016-05-24 04:24:17 +02:00
2018-08-23 17:00:30 +02:00
int drop_position ;
2022-09-29 11:53:28 +02:00
Vector < String > drag_files = drag_data [ " files " ] ;
2021-03-07 21:07:30 +01:00
TreeItem * favorites_item = tree - > get_root ( ) - > get_first_child ( ) ;
2018-08-23 17:00:30 +02:00
TreeItem * resources_item = favorites_item - > get_next ( ) ;
if ( ti = = favorites_item ) {
2019-08-22 06:22:52 +02:00
// Drop on the favorite folder.
2018-08-23 17:00:30 +02:00
drop_position = 0 ;
} else if ( ti = = resources_item ) {
2019-08-22 06:22:52 +02:00
// Drop on the resource item.
2018-08-23 17:00:30 +02:00
drop_position = dirs . size ( ) ;
} else {
2019-08-22 06:22:52 +02:00
// Drop in the list.
2018-08-23 17:00:30 +02:00
drop_position = dirs . find ( ti - > get_metadata ( 0 ) ) ;
if ( drop_section = = 1 ) {
drop_position + + ;
2016-05-24 04:24:17 +02:00
}
}
2019-08-22 06:22:52 +02:00
// Remove dragged favorites.
2018-08-23 17:00:30 +02:00
Vector < int > to_remove ;
int offset = 0 ;
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < drag_files . size ( ) ; i + + ) {
int to_remove_pos = dirs . find ( drag_files [ i ] ) ;
2018-08-23 17:00:30 +02:00
to_remove . push_back ( to_remove_pos ) ;
2018-09-14 13:59:19 +02:00
if ( to_remove_pos < drop_position ) {
2018-08-23 17:00:30 +02:00
offset + + ;
2016-05-24 04:24:17 +02:00
}
}
2018-08-23 17:00:30 +02:00
drop_position - = offset ;
to_remove . sort ( ) ;
for ( int i = 0 ; i < to_remove . size ( ) ; i + + ) {
2021-07-04 00:17:03 +02:00
dirs . remove_at ( to_remove [ i ] - i ) ;
2018-08-23 17:00:30 +02:00
}
2016-05-24 04:24:17 +02:00
2019-08-22 06:22:52 +02:00
// Re-add them at the right position.
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < drag_files . size ( ) ; i + + ) {
dirs . insert ( drop_position , drag_files [ i ] ) ;
2018-08-23 17:00:30 +02:00
drop_position + + ;
2016-05-24 04:24:17 +02:00
}
2018-09-18 14:02:59 +02:00
EditorSettings : : get_singleton ( ) - > set_favorites ( dirs ) ;
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2018-09-29 00:11:26 +02:00
2023-05-11 04:17:03 +02:00
if ( display_mode = = DISPLAY_MODE_SPLIT & & current_path = = " Favorites " ) {
2018-09-29 00:11:26 +02:00
_update_file_list ( true ) ;
2020-05-14 16:41:43 +02:00
}
2016-05-24 04:24:17 +02:00
return ;
}
2017-03-05 16:44:50 +01:00
if ( drag_data . has ( " type " ) & & String ( drag_data [ " type " ] ) = = " resource " ) {
2019-08-22 06:22:52 +02:00
// Moving resource.
2016-05-11 16:46:08 +02:00
Ref < Resource > res = drag_data [ " resource " ] ;
2018-09-13 22:38:35 +02:00
String to_dir ;
bool favorite ;
_get_drag_target_folder ( to_dir , favorite , p_point , p_from ) ;
2020-12-15 13:04:21 +01:00
if ( res . is_valid ( ) & & ! to_dir . is_empty ( ) ) {
2017-10-25 16:40:33 +02:00
EditorNode : : get_singleton ( ) - > push_item ( res . ptr ( ) ) ;
EditorNode : : get_singleton ( ) - > save_resource_as ( res , to_dir ) ;
2016-05-16 01:25:51 +02:00
}
2016-05-11 16:46:08 +02:00
}
2017-03-05 16:44:50 +01:00
if ( drag_data . has ( " type " ) & & ( String ( drag_data [ " type " ] ) = = " files " | | String ( drag_data [ " type " ] ) = = " files_and_dirs " ) ) {
2019-08-22 06:22:52 +02:00
// Move files or add to favorites.
2018-09-13 22:38:35 +02:00
String to_dir ;
bool favorite ;
_get_drag_target_folder ( to_dir , favorite , p_point , p_from ) ;
2020-12-15 13:04:21 +01:00
if ( ! to_dir . is_empty ( ) ) {
2016-05-16 01:25:51 +02:00
Vector < String > fnames = drag_data [ " files " ] ;
2017-10-01 23:59:27 +02:00
to_move . clear ( ) ;
2023-07-01 19:21:35 +02:00
String target_dir = to_dir = = " res:// " ? to_dir : to_dir . trim_suffix ( " / " ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < fnames . size ( ) ; i + + ) {
2023-07-01 19:21:35 +02:00
if ( fnames [ i ] . trim_suffix ( " / " ) . get_base_dir ( ) ! = target_dir ) {
2020-02-04 23:20:01 +01:00
to_move . push_back ( FileOrFolder ( fnames [ i ] , ! fnames [ i ] . ends_with ( " / " ) ) ) ;
}
}
2020-12-15 13:04:21 +01:00
if ( ! to_move . is_empty ( ) ) {
2021-08-13 23:31:57 +02:00
if ( Input : : get_singleton ( ) - > is_key_pressed ( Key : : CTRL ) ) {
2023-03-25 20:58:37 +01:00
_move_operation_confirm ( to_dir , true ) ;
2020-06-05 01:53:35 +02:00
} else {
_move_operation_confirm ( to_dir ) ;
}
2016-05-16 01:25:51 +02:00
}
2018-09-13 22:38:35 +02:00
} else if ( favorite ) {
2020-02-04 23:20:01 +01:00
// Add the files from favorites.
2018-09-13 22:38:35 +02:00
Vector < String > fnames = drag_data [ " files " ] ;
2022-09-29 11:53:28 +02:00
Vector < String > favorites_list = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
2018-09-13 22:38:35 +02:00
for ( int i = 0 ; i < fnames . size ( ) ; i + + ) {
2022-09-29 11:53:28 +02:00
if ( ! favorites_list . has ( fnames [ i ] ) ) {
favorites_list . push_back ( fnames [ i ] ) ;
2018-09-13 22:38:35 +02:00
}
}
2022-09-29 11:53:28 +02:00
EditorSettings : : get_singleton ( ) - > set_favorites ( favorites_list ) ;
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2016-05-16 01:25:51 +02:00
}
2016-05-11 16:46:08 +02:00
}
2021-09-09 00:43:14 +02:00
if ( drag_data . has ( " type " ) & & String ( drag_data [ " type " ] ) = = " nodes " ) {
String to_dir ;
bool favorite ;
_get_drag_target_folder ( to_dir , favorite , p_point , p_from ) ;
2021-11-17 21:08:55 +01:00
SceneTreeDock : : get_singleton ( ) - > save_branch_to_file ( to_dir ) ;
2021-09-09 00:43:14 +02:00
}
2016-05-11 16:46:08 +02:00
}
2018-09-13 22:38:35 +02:00
void FileSystemDock : : _get_drag_target_folder ( String & target , bool & target_favorites , const Point2 & p_point , Control * p_from ) const {
target = String ( ) ;
target_favorites = false ;
2019-08-22 06:22:52 +02:00
// In the file list.
2017-10-25 16:27:35 +02:00
if ( p_from = = files ) {
int pos = files - > get_item_at_position ( p_point , true ) ;
2018-09-13 22:38:35 +02:00
if ( pos = = - 1 ) {
return ;
}
2017-10-25 16:27:35 +02:00
2018-09-13 22:38:35 +02:00
String ltarget = files - > get_item_metadata ( pos ) ;
2023-05-11 04:17:03 +02:00
target = ltarget . ends_with ( " / " ) ? ltarget : current_path . get_base_dir ( ) ;
2018-09-13 22:38:35 +02:00
return ;
2017-10-25 16:27:35 +02:00
}
2019-08-22 06:22:52 +02:00
// In the tree.
2017-10-25 16:27:35 +02:00
if ( p_from = = tree ) {
TreeItem * ti = tree - > get_item_at_position ( p_point ) ;
2018-09-13 22:38:35 +02:00
int section = tree - > get_drop_section_at_position ( p_point ) ;
if ( ti ) {
2019-08-22 06:22:52 +02:00
// Check the favorites first.
2021-03-07 21:07:30 +01:00
if ( ti = = tree - > get_root ( ) - > get_first_child ( ) & & section > = 0 ) {
2018-09-13 22:38:35 +02:00
target_favorites = true ;
return ;
2021-03-07 21:07:30 +01:00
} else if ( ti - > get_parent ( ) = = tree - > get_root ( ) - > get_first_child ( ) ) {
2018-09-13 22:38:35 +02:00
target_favorites = true ;
return ;
2018-08-23 17:00:30 +02:00
} else {
2018-09-13 22:38:35 +02:00
String fpath = ti - > get_metadata ( 0 ) ;
if ( section = = 0 ) {
if ( fpath . ends_with ( " / " ) ) {
2019-08-22 06:22:52 +02:00
// We drop on a folder.
2018-09-13 22:38:35 +02:00
target = fpath ;
return ;
2020-02-04 23:20:01 +01:00
} else {
// We drop on the folder that the target file is in.
target = fpath . get_base_dir ( ) ;
return ;
2018-09-13 22:38:35 +02:00
}
} else {
2021-03-07 21:07:30 +01:00
if ( ti - > get_parent ( ) ! = tree - > get_root ( ) - > get_first_child ( ) ) {
2019-08-22 06:22:52 +02:00
// Not in the favorite section.
2018-09-13 22:38:35 +02:00
if ( fpath ! = " res:// " ) {
// We drop between two files
if ( fpath . ends_with ( " / " ) ) {
fpath = fpath . substr ( 0 , fpath . length ( ) - 1 ) ;
}
target = fpath . get_base_dir ( ) ;
return ;
2018-08-23 17:00:30 +02:00
}
}
}
}
}
2017-10-25 16:27:35 +02:00
}
}
2018-11-03 18:36:59 +01:00
void FileSystemDock : : _file_and_folders_fill_popup ( PopupMenu * p_popup , Vector < String > p_paths , bool p_display_path_dependent_options ) {
2019-08-22 06:22:52 +02:00
// Add options for files and folders.
2020-12-15 13:04:21 +01:00
ERR_FAIL_COND_MSG ( p_paths . is_empty ( ) , " Path cannot be empty. " ) ;
2016-05-16 01:25:51 +02:00
2017-10-09 15:59:48 +02:00
Vector < String > filenames ;
Vector < String > foldernames ;
2016-05-16 01:25:51 +02:00
2022-09-29 11:53:28 +02:00
Vector < String > favorites_list = EditorSettings : : get_singleton ( ) - > get_favorites ( ) ;
2018-09-13 18:11:05 +02:00
2017-10-09 15:59:48 +02:00
bool all_files = true ;
bool all_files_scenes = true ;
bool all_folders = true ;
2018-09-13 18:11:05 +02:00
bool all_favorites = true ;
bool all_not_favorites = true ;
2019-09-06 13:57:51 +02:00
2018-08-23 17:00:30 +02:00
for ( int i = 0 ; i < p_paths . size ( ) ; i + + ) {
String fpath = p_paths [ i ] ;
2017-09-03 22:35:18 +02:00
if ( fpath . ends_with ( " / " ) ) {
foldernames . push_back ( fpath ) ;
2017-10-09 15:59:48 +02:00
all_files = false ;
2016-05-27 19:18:40 +02:00
} else {
2017-09-03 22:35:18 +02:00
filenames . push_back ( fpath ) ;
2017-10-09 15:59:48 +02:00
all_folders = false ;
2017-09-03 22:35:18 +02:00
all_files_scenes & = ( EditorFileSystem : : get_singleton ( ) - > get_file_type ( fpath ) = = " PackedScene " ) ;
2016-05-27 19:18:40 +02:00
}
2018-09-13 18:11:05 +02:00
2019-08-22 06:22:52 +02:00
// Check if in favorites.
2018-09-13 18:11:05 +02:00
bool found = false ;
2022-09-29 11:53:28 +02:00
for ( int j = 0 ; j < favorites_list . size ( ) ; j + + ) {
if ( favorites_list [ j ] = = fpath ) {
2018-09-13 18:11:05 +02:00
found = true ;
break ;
}
}
if ( found ) {
all_not_favorites = false ;
} else {
all_favorites = false ;
}
2016-05-16 01:25:51 +02:00
}
2017-12-01 09:01:50 +01:00
if ( all_files ) {
2019-05-08 04:35:23 +02:00
if ( all_files_scenes ) {
if ( filenames . size ( ) = = 1 ) {
2021-07-17 23:22:52 +02:00
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Load " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Open Scene " ) , FILE_OPEN ) ;
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " CreateNewSceneFrom " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Inherited Scene " ) , FILE_INHERIT ) ;
2022-10-18 16:43:37 +02:00
if ( GLOBAL_GET ( " application/run/main_scene " ) ! = filenames [ 0 ] ) {
2021-07-17 23:22:52 +02:00
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " PlayScene " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Set As Main Scene " ) , FILE_MAIN_SCENE ) ;
2019-11-11 16:41:46 +01:00
}
2019-05-08 04:35:23 +02:00
} else {
2021-07-17 23:22:52 +02:00
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Load " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Open Scenes " ) , FILE_OPEN ) ;
2019-05-08 04:35:23 +02:00
}
2022-11-16 00:13:39 +01:00
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Instance " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Instantiate " ) , FILE_INSTANTIATE ) ;
2018-08-23 17:00:30 +02:00
p_popup - > add_separator ( ) ;
2019-05-08 04:35:23 +02:00
} else if ( filenames . size ( ) = = 1 ) {
2021-07-17 23:22:52 +02:00
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Load " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Open " ) , FILE_OPEN ) ;
2018-08-23 17:00:30 +02:00
p_popup - > add_separator ( ) ;
2017-12-09 03:33:28 +01:00
}
if ( filenames . size ( ) = = 1 ) {
2018-08-23 17:00:30 +02:00
p_popup - > add_item ( TTR ( " Edit Dependencies... " ) , FILE_DEPENDENCIES ) ;
p_popup - > add_item ( TTR ( " View Owners... " ) , FILE_OWNERS ) ;
p_popup - > add_separator ( ) ;
2017-10-09 15:59:48 +02:00
}
2023-02-17 20:37:58 +01:00
}
if ( p_paths . size ( ) = = 1 & & p_display_path_dependent_options ) {
PopupMenu * new_menu = memnew ( PopupMenu ) ;
new_menu - > set_name ( " New " ) ;
new_menu - > connect ( " id_pressed " , callable_mp ( this , & FileSystemDock : : _tree_rmb_option ) ) ;
p_popup - > add_child ( new_menu ) ;
p_popup - > add_submenu_item ( TTR ( " Create New " ) , " New " , FILE_NEW ) ;
p_popup - > set_item_icon ( p_popup - > get_item_index ( FILE_NEW ) , get_theme_icon ( SNAME ( " Add " ) , SNAME ( " EditorIcons " ) ) ) ;
new_menu - > add_icon_item ( get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Folder... " ) , FILE_NEW_FOLDER ) ;
new_menu - > add_icon_item ( get_theme_icon ( SNAME ( " PackedScene " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Scene... " ) , FILE_NEW_SCENE ) ;
new_menu - > add_icon_item ( get_theme_icon ( SNAME ( " Script " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Script... " ) , FILE_NEW_SCRIPT ) ;
new_menu - > add_icon_item ( get_theme_icon ( SNAME ( " Object " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Resource... " ) , FILE_NEW_RESOURCE ) ;
new_menu - > add_icon_item ( get_theme_icon ( SNAME ( " TextFile " ) , SNAME ( " EditorIcons " ) ) , TTR ( " TextFile... " ) , FILE_NEW_TEXTFILE ) ;
p_popup - > add_separator ( ) ;
}
if ( all_folders & & foldernames . size ( ) > 0 ) {
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Load " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Expand Folder " ) , FILE_OPEN ) ;
if ( foldernames . size ( ) = = 1 ) {
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " GuiTreeArrowDown " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Expand Hierarchy " ) , FOLDER_EXPAND_ALL ) ;
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " GuiTreeArrowRight " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Collapse Hierarchy " ) , FOLDER_COLLAPSE_ALL ) ;
}
2017-12-09 03:33:28 +01:00
2018-08-23 17:00:30 +02:00
p_popup - > add_separator ( ) ;
2016-05-16 01:25:51 +02:00
}
2018-08-23 17:00:30 +02:00
if ( p_paths . size ( ) = = 1 ) {
2021-07-17 23:22:52 +02:00
p_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " ActionCopy " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/copy_path " ) , FILE_COPY_PATH ) ;
2022-05-02 11:51:23 +02:00
if ( ResourceLoader : : get_resource_uid ( p_paths [ 0 ] ) ! = ResourceUID : : INVALID_ID ) {
p_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " Instance " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/copy_uid " ) , FILE_COPY_UID ) ;
}
2019-08-10 01:15:25 +02:00
if ( p_paths [ 0 ] ! = " res:// " ) {
2021-07-17 23:22:52 +02:00
p_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " Rename " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/rename " ) , FILE_RENAME ) ;
p_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " Duplicate " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/duplicate " ) , FILE_DUPLICATE ) ;
2019-08-10 01:15:25 +02:00
}
2018-08-23 17:00:30 +02:00
}
2019-08-10 01:15:25 +02:00
if ( p_paths . size ( ) > 1 | | p_paths [ 0 ] ! = " res:// " ) {
2023-03-25 20:58:37 +01:00
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " MoveUp " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Move/Duplicate To... " ) , FILE_MOVE ) ;
2021-07-17 23:22:52 +02:00
p_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " Remove " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/delete " ) , FILE_REMOVE ) ;
2019-08-10 01:15:25 +02:00
}
2018-08-23 17:00:30 +02:00
2023-02-17 20:37:58 +01:00
p_popup - > add_separator ( ) ;
if ( p_paths . size ( ) > = 1 ) {
if ( ! all_favorites ) {
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Favorites " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Add to Favorites " ) , FILE_ADD_FAVORITE ) ;
2018-11-03 18:36:59 +01:00
}
2023-02-17 20:37:58 +01:00
if ( ! all_not_favorites ) {
p_popup - > add_icon_item ( get_theme_icon ( SNAME ( " NonFavorite " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Remove from Favorites " ) , FILE_REMOVE_FAVORITE ) ;
}
}
2018-08-23 17:00:30 +02:00
2023-02-17 20:37:58 +01:00
if ( p_paths . size ( ) = = 1 ) {
2023-01-15 22:50:40 +01:00
const String fpath = p_paths [ 0 ] ;
# if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
2023-02-17 20:37:58 +01:00
p_popup - > add_separator ( ) ;
2023-01-15 22:50:40 +01:00
// Opening the system file manager is not supported on the Android and web editors.
const bool is_directory = fpath . ends_with ( " / " ) ;
const String item_text = is_directory ? TTR ( " Open in File Manager " ) : TTR ( " Show in File Manager " ) ;
2023-01-08 18:00:07 +01:00
p_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " Filesystem " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/show_in_explorer " ) , FILE_SHOW_IN_EXPLORER ) ;
p_popup - > set_item_text ( p_popup - > get_item_index ( FILE_SHOW_IN_EXPLORER ) , item_text ) ;
2022-11-10 22:26:40 +01:00
if ( ! is_directory ) {
2023-01-22 01:29:59 +01:00
p_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " ExternalLink " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/open_in_external_program " ) , FILE_OPEN_EXTERNAL ) ;
2022-11-10 22:26:40 +01:00
}
2023-01-15 22:50:40 +01:00
# endif
2023-05-11 04:17:03 +02:00
current_path = fpath ;
2016-05-16 01:25:51 +02:00
}
2018-08-23 17:00:30 +02:00
}
2016-05-16 01:25:51 +02:00
2021-09-18 09:33:18 +02:00
void FileSystemDock : : _tree_rmb_select ( const Vector2 & p_pos , MouseButton p_button ) {
if ( p_button ! = MouseButton : : RIGHT ) {
return ;
}
2019-08-22 06:22:52 +02:00
// Right click is pressed in the tree.
2019-08-10 01:15:25 +02:00
Vector < String > paths = _tree_get_selected ( false ) ;
2018-08-11 14:43:00 +02:00
2020-09-07 14:09:53 +02:00
tree_popup - > clear ( ) ;
2016-05-18 09:37:59 +02:00
2019-08-22 06:22:52 +02:00
// Popup.
2020-12-15 13:04:21 +01:00
if ( ! paths . is_empty ( ) ) {
2021-11-20 09:04:57 +01:00
tree_popup - > reset_size ( ) ;
2018-08-23 17:00:30 +02:00
_file_and_folders_fill_popup ( tree_popup , paths ) ;
2020-07-01 19:44:19 +02:00
tree_popup - > set_position ( tree - > get_screen_position ( ) + p_pos ) ;
2021-08-31 17:43:35 +02:00
tree_popup - > reset_size ( ) ;
2018-08-23 17:00:30 +02:00
tree_popup - > popup ( ) ;
}
2016-05-16 01:25:51 +02:00
}
2016-05-11 16:46:08 +02:00
2021-09-18 09:33:18 +02:00
void FileSystemDock : : _tree_empty_click ( const Vector2 & p_pos , MouseButton p_button ) {
if ( p_button ! = MouseButton : : RIGHT ) {
return ;
}
2019-08-22 06:22:52 +02:00
// Right click is pressed in the empty space of the tree.
2023-05-11 04:17:03 +02:00
current_path = " res:// " ;
2019-04-09 19:22:14 +02:00
tree_popup - > clear ( ) ;
2021-11-20 09:04:57 +01:00
tree_popup - > reset_size ( ) ;
2021-07-17 23:22:52 +02:00
tree_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Folder... " ) , FILE_NEW_FOLDER ) ;
tree_popup - > add_icon_item ( get_theme_icon ( SNAME ( " PackedScene " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Scene... " ) , FILE_NEW_SCENE ) ;
tree_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Script " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Script... " ) , FILE_NEW_SCRIPT ) ;
tree_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Object " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Resource... " ) , FILE_NEW_RESOURCE ) ;
2021-09-23 23:09:15 +02:00
tree_popup - > add_icon_item ( get_theme_icon ( SNAME ( " TextFile " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New TextFile... " ) , FILE_NEW_TEXTFILE ) ;
2023-01-15 22:50:40 +01:00
# if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
// Opening the system file manager is not supported on the Android and web editors.
2022-01-19 00:51:10 +01:00
tree_popup - > add_separator ( ) ;
2023-01-08 18:00:07 +01:00
tree_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " Filesystem " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/show_in_explorer " ) , FILE_SHOW_IN_EXPLORER ) ;
2023-01-15 22:50:40 +01:00
# endif
2022-01-19 00:51:10 +01:00
2021-08-31 17:43:35 +02:00
tree_popup - > set_position ( tree - > get_screen_position ( ) + p_pos ) ;
tree_popup - > reset_size ( ) ;
2019-04-09 19:22:14 +02:00
tree_popup - > popup ( ) ;
}
2019-04-09 14:54:41 +02:00
void FileSystemDock : : _tree_empty_selected ( ) {
tree - > deselect_all ( ) ;
}
2022-05-09 20:17:04 +02:00
void FileSystemDock : : _file_list_item_clicked ( int p_item , const Vector2 & p_pos , MouseButton p_mouse_button_index ) {
2021-11-26 00:53:27 +01:00
if ( p_mouse_button_index ! = MouseButton : : RIGHT ) {
return ;
}
2019-08-22 06:22:52 +02:00
// Right click is pressed in the file list.
2018-08-23 17:00:30 +02:00
Vector < String > paths ;
for ( int i = 0 ; i < files - > get_item_count ( ) ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( ! files - > is_selected ( i ) ) {
2018-08-23 17:00:30 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-08-23 17:00:30 +02:00
if ( files - > get_item_text ( p_item ) = = " .. " ) {
2020-12-21 11:26:41 +01:00
files - > deselect ( i ) ;
2018-08-23 17:00:30 +02:00
continue ;
}
paths . push_back ( files - > get_item_metadata ( i ) ) ;
}
2017-11-20 19:25:13 +01:00
2019-08-22 06:22:52 +02:00
// Popup.
2020-12-15 13:04:21 +01:00
if ( ! paths . is_empty ( ) ) {
2018-08-23 17:00:30 +02:00
file_list_popup - > clear ( ) ;
2018-11-03 18:36:59 +01:00
_file_and_folders_fill_popup ( file_list_popup , paths , searched_string . length ( ) = = 0 ) ;
2021-08-31 17:43:35 +02:00
file_list_popup - > set_position ( files - > get_screen_position ( ) + p_pos ) ;
file_list_popup - > reset_size ( ) ;
2018-08-23 17:00:30 +02:00
file_list_popup - > popup ( ) ;
}
}
2022-05-09 20:17:04 +02:00
void FileSystemDock : : _file_list_empty_clicked ( const Vector2 & p_pos , MouseButton p_mouse_button_index ) {
if ( p_mouse_button_index ! = MouseButton : : RIGHT ) {
return ;
}
2019-08-22 06:22:52 +02:00
// Right click on empty space for file list.
2020-05-14 16:41:43 +02:00
if ( searched_string . length ( ) > 0 ) {
2018-11-03 18:36:59 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-11-03 18:36:59 +01:00
2023-05-11 04:17:03 +02:00
current_path = current_path_line_edit - > get_text ( ) ;
2022-01-19 00:51:10 +01:00
2018-08-23 17:00:30 +02:00
file_list_popup - > clear ( ) ;
2021-11-20 09:04:57 +01:00
file_list_popup - > reset_size ( ) ;
2018-08-23 17:00:30 +02:00
2021-07-17 23:22:52 +02:00
file_list_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Folder... " ) , FILE_NEW_FOLDER ) ;
file_list_popup - > add_icon_item ( get_theme_icon ( SNAME ( " PackedScene " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Scene... " ) , FILE_NEW_SCENE ) ;
file_list_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Script " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Script... " ) , FILE_NEW_SCRIPT ) ;
file_list_popup - > add_icon_item ( get_theme_icon ( SNAME ( " Object " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New Resource... " ) , FILE_NEW_RESOURCE ) ;
2021-09-23 23:09:15 +02:00
file_list_popup - > add_icon_item ( get_theme_icon ( SNAME ( " TextFile " ) , SNAME ( " EditorIcons " ) ) , TTR ( " New TextFile... " ) , FILE_NEW_TEXTFILE ) ;
2019-08-22 06:22:52 +02:00
file_list_popup - > add_separator ( ) ;
2023-01-08 18:00:07 +01:00
file_list_popup - > add_icon_shortcut ( get_theme_icon ( SNAME ( " Filesystem " ) , SNAME ( " EditorIcons " ) ) , ED_GET_SHORTCUT ( " filesystem_dock/show_in_explorer " ) , FILE_SHOW_IN_EXPLORER ) ;
2022-11-10 22:26:40 +01:00
2021-08-31 17:43:35 +02:00
file_list_popup - > set_position ( files - > get_screen_position ( ) + p_pos ) ;
file_list_popup - > reset_size ( ) ;
2018-08-23 17:00:30 +02:00
file_list_popup - > popup ( ) ;
2017-11-20 19:25:13 +01:00
}
2017-03-05 16:44:50 +01:00
void FileSystemDock : : select_file ( const String & p_file ) {
2019-01-17 20:40:38 +01:00
_navigate_to_path ( p_file ) ;
2017-01-25 18:30:40 +01:00
}
2017-03-05 16:44:50 +01:00
void FileSystemDock : : _file_multi_selected ( int p_index , bool p_selected ) {
2019-08-22 06:22:52 +02:00
// Set the path to the current focused item.
2018-08-23 17:00:30 +02:00
int current = files - > get_current ( ) ;
if ( current = = p_index ) {
String fpath = files - > get_item_metadata ( current ) ;
if ( ! fpath . ends_with ( " / " ) ) {
2023-05-11 04:17:03 +02:00
current_path = fpath ;
2018-09-13 17:35:44 +02:00
if ( display_mode = = DISPLAY_MODE_SPLIT ) {
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2018-08-23 17:00:30 +02:00
}
}
}
2019-08-22 06:22:52 +02:00
// Update the import dock.
2017-11-02 14:05:34 +01:00
import_dock_needs_update = true ;
2021-07-17 23:22:52 +02:00
call_deferred ( SNAME ( " _update_import_dock " ) ) ;
2017-02-01 13:45:45 +01:00
}
2022-03-03 21:36:56 +01:00
void FileSystemDock : : _tree_mouse_exited ( ) {
if ( holding_branch ) {
_reselect_items_selected_on_drag_begin ( ) ;
}
}
void FileSystemDock : : _reselect_items_selected_on_drag_begin ( bool reset ) {
TreeItem * selected_item = tree - > get_next_selected ( tree - > get_root ( ) ) ;
if ( selected_item ) {
selected_item - > deselect ( 0 ) ;
}
if ( ! tree_items_selected_on_drag_begin . is_empty ( ) ) {
bool reselected = false ;
for ( TreeItem * item : tree_items_selected_on_drag_begin ) {
if ( item - > get_tree ( ) ) {
item - > select ( 0 ) ;
reselected = true ;
}
}
if ( reset ) {
tree_items_selected_on_drag_begin . clear ( ) ;
}
if ( ! reselected ) {
// If couldn't reselect the items selected on drag begin, select the "res://" item.
tree - > get_root ( ) - > get_child ( 1 ) - > select ( 0 ) ;
}
}
files - > deselect_all ( ) ;
if ( ! list_items_selected_on_drag_begin . is_empty ( ) ) {
for ( const int idx : list_items_selected_on_drag_begin ) {
files - > select ( idx , false ) ;
}
if ( reset ) {
list_items_selected_on_drag_begin . clear ( ) ;
}
}
}
2018-08-23 17:00:30 +02:00
void FileSystemDock : : _tree_gui_input ( Ref < InputEvent > p_event ) {
2018-01-05 20:45:54 +01:00
Ref < InputEventKey > key = p_event ;
2022-03-03 21:36:56 +01:00
Ref < InputEventMouseMotion > mm = p_event ;
if ( mm . is_valid ( ) ) {
TreeItem * item = tree - > get_item_at_position ( mm - > get_position ( ) ) ;
if ( item & & holding_branch ) {
String fpath = item - > get_metadata ( 0 ) ;
while ( ! fpath . ends_with ( " / " ) & & fpath ! = " res:// " & & item - > get_parent ( ) ) { // Find the parent folder tree item.
item = item - > get_parent ( ) ;
fpath = item - > get_metadata ( 0 ) ;
}
TreeItem * deselect_item = tree - > get_next_selected ( tree - > get_root ( ) ) ;
while ( deselect_item ) {
deselect_item - > deselect ( 0 ) ;
deselect_item = tree - > get_next_selected ( deselect_item ) ;
}
item - > select ( 0 ) ;
if ( display_mode = = DisplayMode : : DISPLAY_MODE_SPLIT ) {
files - > deselect_all ( ) ;
// Try to select the corresponding file list item.
const int files_item_idx = files - > find_metadata ( fpath ) ;
if ( files_item_idx ! = - 1 ) {
files - > select ( files_item_idx ) ;
}
}
}
}
2018-01-05 20:45:54 +01:00
if ( key . is_valid ( ) & & key - > is_pressed ( ) & & ! key - > is_echo ( ) ) {
if ( ED_IS_SHORTCUT ( " filesystem_dock/duplicate " , p_event ) ) {
2018-08-23 17:00:30 +02:00
_tree_rmb_option ( FILE_DUPLICATE ) ;
2018-01-05 20:45:54 +01:00
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/copy_path " , p_event ) ) {
2018-08-23 17:00:30 +02:00
_tree_rmb_option ( FILE_COPY_PATH ) ;
2022-05-02 11:51:23 +02:00
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/copy_uid " , p_event ) ) {
_tree_rmb_option ( FILE_COPY_UID ) ;
2018-01-05 20:45:54 +01:00
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/delete " , p_event ) ) {
2018-08-23 17:00:30 +02:00
_tree_rmb_option ( FILE_REMOVE ) ;
2018-03-26 19:50:48 +02:00
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/rename " , p_event ) ) {
2018-08-23 17:00:30 +02:00
_tree_rmb_option ( FILE_RENAME ) ;
2023-01-08 18:00:07 +01:00
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/show_in_explorer " , p_event ) ) {
_tree_rmb_option ( FILE_SHOW_IN_EXPLORER ) ;
2023-01-22 01:29:59 +01:00
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/open_in_external_program " , p_event ) ) {
_tree_rmb_option ( FILE_OPEN_EXTERNAL ) ;
2021-05-14 02:13:17 +02:00
} else if ( ED_IS_SHORTCUT ( " editor/open_search " , p_event ) ) {
2021-06-04 01:22:50 +02:00
focus_on_filter ( ) ;
2020-12-02 23:15:33 +01:00
} else {
return ;
2018-01-05 20:45:54 +01:00
}
2020-12-02 23:15:33 +01:00
accept_event ( ) ;
2018-01-05 20:45:54 +01:00
}
}
2018-08-23 17:00:30 +02:00
void FileSystemDock : : _file_list_gui_input ( Ref < InputEvent > p_event ) {
2022-03-03 21:36:56 +01:00
Ref < InputEventMouseMotion > mm = p_event ;
if ( mm . is_valid ( ) & & holding_branch ) {
const int item_idx = files - > get_item_at_position ( mm - > get_position ( ) ) ;
if ( item_idx ! = - 1 ) {
files - > deselect_all ( ) ;
String fpath = files - > get_item_metadata ( item_idx ) ;
if ( fpath . ends_with ( " / " ) | | fpath = = " res:// " ) {
files - > select ( item_idx ) ;
}
TreeItem * deselect_item = tree - > get_next_selected ( tree - > get_root ( ) ) ;
while ( deselect_item ) {
deselect_item - > deselect ( 0 ) ;
deselect_item = tree - > get_next_selected ( deselect_item ) ;
}
// Try to select the corresponding tree item.
TreeItem * tree_item = tree - > get_item_with_text ( files - > get_item_text ( item_idx ) ) ;
if ( tree_item ) {
tree_item - > select ( 0 ) ;
} else {
// Find parent folder.
fpath = fpath . substr ( 0 , fpath . rfind ( " / " ) + 1 ) ;
if ( fpath . size ( ) > String ( " res:// " ) . size ( ) ) {
fpath = fpath . left ( fpath . size ( ) - 2 ) ; // Remove last '/'.
const int slash_idx = fpath . rfind ( " / " ) ;
fpath = fpath . substr ( slash_idx + 1 , fpath . size ( ) - slash_idx - 1 ) ;
}
tree_item = tree - > get_item_with_text ( fpath ) ;
if ( tree_item ) {
tree_item - > select ( 0 ) ;
}
}
}
}
2018-08-23 17:00:30 +02:00
Ref < InputEventKey > key = p_event ;
if ( key . is_valid ( ) & & key - > is_pressed ( ) & & ! key - > is_echo ( ) ) {
if ( ED_IS_SHORTCUT ( " filesystem_dock/duplicate " , p_event ) ) {
_file_list_rmb_option ( FILE_DUPLICATE ) ;
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/copy_path " , p_event ) ) {
_file_list_rmb_option ( FILE_COPY_PATH ) ;
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/delete " , p_event ) ) {
_file_list_rmb_option ( FILE_REMOVE ) ;
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/rename " , p_event ) ) {
_file_list_rmb_option ( FILE_RENAME ) ;
2023-01-08 18:00:07 +01:00
} else if ( ED_IS_SHORTCUT ( " filesystem_dock/show_in_explorer " , p_event ) ) {
_file_list_rmb_option ( FILE_SHOW_IN_EXPLORER ) ;
2021-05-14 02:13:17 +02:00
} else if ( ED_IS_SHORTCUT ( " editor/open_search " , p_event ) ) {
2021-06-04 01:22:50 +02:00
focus_on_filter ( ) ;
2020-12-02 23:15:33 +01:00
} else {
return ;
2018-08-23 17:00:30 +02:00
}
2020-12-02 23:15:33 +01:00
accept_event ( ) ;
2018-08-23 17:00:30 +02:00
}
2017-11-02 14:05:34 +01:00
}
2023-01-15 00:20:50 +01:00
bool FileSystemDock : : _get_imported_files ( const String & p_path , String & r_extension , Vector < String > & r_files ) const {
2020-08-14 08:31:41 +02:00
if ( ! p_path . ends_with ( " / " ) ) {
if ( FileAccess : : exists ( p_path + " .import " ) ) {
2023-01-15 00:20:50 +01:00
if ( r_extension . is_empty ( ) ) {
r_extension = p_path . get_extension ( ) ;
} else if ( r_extension ! = p_path . get_extension ( ) ) {
r_files . clear ( ) ;
return false ; // File type mismatch, stop search.
}
2022-09-29 11:53:28 +02:00
r_files . push_back ( p_path ) ;
2020-08-14 08:31:41 +02:00
}
2023-01-15 00:20:50 +01:00
return true ;
2020-05-14 16:41:43 +02:00
}
2017-11-02 14:05:34 +01:00
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : open ( p_path ) ;
2020-08-14 08:31:41 +02:00
da - > list_dir_begin ( ) ;
String n = da - > get_next ( ) ;
2021-12-09 10:42:46 +01:00
while ( ! n . is_empty ( ) ) {
2020-08-14 08:31:41 +02:00
if ( n ! = " . " & & n ! = " .. " & & ! n . ends_with ( " .import " ) ) {
String npath = p_path + n + ( da - > current_is_dir ( ) ? " / " : " " ) ;
2023-01-15 00:20:50 +01:00
if ( ! _get_imported_files ( npath , r_extension , r_files ) ) {
return false ;
}
2020-08-14 08:31:41 +02:00
}
n = da - > get_next ( ) ;
}
da - > list_dir_end ( ) ;
2023-01-15 00:20:50 +01:00
return true ;
2020-08-14 08:31:41 +02:00
}
void FileSystemDock : : _update_import_dock ( ) {
2021-04-05 14:09:59 +02:00
if ( ! import_dock_needs_update ) {
2020-08-14 08:31:41 +02:00
return ;
2021-04-05 14:09:59 +02:00
}
2020-08-14 08:31:41 +02:00
2019-08-22 06:22:52 +02:00
// List selected.
2018-09-24 14:26:26 +02:00
Vector < String > selected ;
2019-02-25 23:39:49 +01:00
if ( display_mode = = DISPLAY_MODE_TREE_ONLY ) {
2018-09-24 14:26:26 +02:00
// Use the tree
selected = _tree_get_selected ( ) ;
} else {
2019-08-22 06:22:52 +02:00
// Use the file list.
2018-09-24 14:26:26 +02:00
for ( int i = 0 ; i < files - > get_item_count ( ) ; i + + ) {
2021-04-05 14:09:59 +02:00
if ( ! files - > is_selected ( i ) ) {
2018-09-24 14:26:26 +02:00
continue ;
2021-04-05 14:09:59 +02:00
}
2018-09-24 14:26:26 +02:00
selected . push_back ( files - > get_item_metadata ( i ) ) ;
}
}
2023-01-15 00:20:50 +01:00
if ( ! selected . is_empty ( ) & & selected [ 0 ] = = " res:// " ) {
// Scanning res:// is costly and unlikely to yield any useful results.
return ;
}
// Expand directory selection.
2020-08-14 08:31:41 +02:00
Vector < String > efiles ;
2023-01-15 00:20:50 +01:00
String extension ;
for ( const String & fpath : selected ) {
_get_imported_files ( fpath , extension , efiles ) ;
2020-08-14 08:31:41 +02:00
}
2019-08-22 06:22:52 +02:00
// Check import.
2017-02-01 13:45:45 +01:00
Vector < String > imports ;
String import_type ;
2020-08-14 08:31:41 +02:00
for ( int i = 0 ; i < efiles . size ( ) ; i + + ) {
String fpath = efiles [ i ] ;
2017-02-01 13:45:45 +01:00
Ref < ConfigFile > cf ;
2021-06-18 00:03:09 +02:00
cf . instantiate ( ) ;
2017-09-03 22:35:18 +02:00
Error err = cf - > load ( fpath + " .import " ) ;
2017-03-05 16:44:50 +01:00
if ( err ! = OK ) {
2017-02-01 13:45:45 +01:00
imports . clear ( ) ;
break ;
}
2021-03-23 15:20:14 +01:00
String type ;
if ( cf - > has_section_key ( " remap " , " type " ) ) {
type = cf - > get_value ( " remap " , " type " ) ;
}
2021-12-09 10:42:46 +01:00
if ( import_type . is_empty ( ) ) {
2017-03-05 16:44:50 +01:00
import_type = type ;
} else if ( import_type ! = type ) {
2019-08-22 06:22:52 +02:00
// All should be the same type.
2017-02-01 13:45:45 +01:00
imports . clear ( ) ;
break ;
}
2017-09-03 22:35:18 +02:00
imports . push_back ( fpath ) ;
2017-02-01 13:45:45 +01:00
}
2017-03-05 16:44:50 +01:00
if ( imports . size ( ) = = 0 ) {
2021-11-17 21:08:55 +01:00
ImportDock : : get_singleton ( ) - > clear ( ) ;
2017-03-05 16:44:50 +01:00
} else if ( imports . size ( ) = = 1 ) {
2021-11-17 21:08:55 +01:00
ImportDock : : get_singleton ( ) - > set_edit_path ( imports [ 0 ] ) ;
2017-02-01 13:45:45 +01:00
} else {
2021-11-17 21:08:55 +01:00
ImportDock : : get_singleton ( ) - > set_edit_multiple_paths ( imports ) ;
2017-02-01 13:45:45 +01:00
}
2017-11-02 14:05:34 +01:00
import_dock_needs_update = false ;
2017-02-01 13:45:45 +01:00
}
2019-04-09 00:18:03 +02:00
void FileSystemDock : : _feature_profile_changed ( ) {
_update_display_mode ( true ) ;
}
2020-10-07 21:56:53 +02:00
void FileSystemDock : : set_file_sort ( FileSortOption p_file_sort ) {
for ( int i = 0 ; i ! = FILE_SORT_MAX ; i + + ) {
tree_button_sort - > get_popup ( ) - > set_item_checked ( i , ( i = = ( int ) p_file_sort ) ) ;
file_list_button_sort - > get_popup ( ) - > set_item_checked ( i , ( i = = ( int ) p_file_sort ) ) ;
}
file_sort = p_file_sort ;
// Update everything needed.
2023-05-11 04:17:03 +02:00
_update_tree ( get_uncollapsed_paths ( ) ) ;
2020-10-07 21:56:53 +02:00
_update_file_list ( true ) ;
}
void FileSystemDock : : _file_sort_popup ( int p_id ) {
set_file_sort ( ( FileSortOption ) p_id ) ;
}
MenuButton * FileSystemDock : : _create_file_menu_button ( ) {
MenuButton * button = memnew ( MenuButton ) ;
button - > set_flat ( true ) ;
2022-07-29 02:30:20 +02:00
button - > set_tooltip_text ( TTR ( " Sort Files " ) ) ;
2020-10-07 21:56:53 +02:00
PopupMenu * p = button - > get_popup ( ) ;
p - > connect ( " id_pressed " , callable_mp ( this , & FileSystemDock : : _file_sort_popup ) ) ;
2021-05-15 18:59:57 +02:00
p - > add_radio_check_item ( TTR ( " Sort by Name (Ascending) " ) , FILE_SORT_NAME ) ;
p - > add_radio_check_item ( TTR ( " Sort by Name (Descending) " ) , FILE_SORT_NAME_REVERSE ) ;
p - > add_radio_check_item ( TTR ( " Sort by Type (Ascending) " ) , FILE_SORT_TYPE ) ;
p - > add_radio_check_item ( TTR ( " Sort by Type (Descending) " ) , FILE_SORT_TYPE_REVERSE ) ;
p - > add_radio_check_item ( TTR ( " Sort by Last Modified " ) , FILE_SORT_MODIFIED_TIME ) ;
p - > add_radio_check_item ( TTR ( " Sort by First Modified " ) , FILE_SORT_MODIFIED_TIME_REVERSE ) ;
2020-10-07 21:56:53 +02:00
p - > set_item_checked ( file_sort , true ) ;
return button ;
}
2016-07-21 15:34:57 +02:00
void FileSystemDock : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _update_tree " ) , & FileSystemDock : : _update_tree ) ;
2018-11-13 20:17:33 +01:00
2018-09-12 13:10:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " _file_list_thumbnail_done " ) , & FileSystemDock : : _file_list_thumbnail_done ) ;
ClassDB : : bind_method ( D_METHOD ( " _tree_thumbnail_done " ) , & FileSystemDock : : _tree_thumbnail_done ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " _select_file " ) , & FileSystemDock : : _select_file ) ;
2020-07-01 14:18:13 +02:00
ClassDB : : bind_method ( D_METHOD ( " navigate_to_path " , " path " ) , & FileSystemDock : : navigate_to_path ) ;
2016-07-03 18:15:15 +02:00
2017-11-02 14:05:34 +01:00
ClassDB : : bind_method ( D_METHOD ( " _update_import_dock " ) , & FileSystemDock : : _update_import_dock ) ;
2016-07-03 18:15:15 +02:00
2022-07-20 23:44:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_resource_tooltip_plugin " , " plugin " ) , & FileSystemDock : : add_resource_tooltip_plugin ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_resource_tooltip_plugin " , " plugin " ) , & FileSystemDock : : remove_resource_tooltip_plugin ) ;
2019-05-08 04:35:23 +02:00
ADD_SIGNAL ( MethodInfo ( " inherit " , PropertyInfo ( Variant : : STRING , " file " ) ) ) ;
2022-11-16 00:13:39 +01:00
ADD_SIGNAL ( MethodInfo ( " instantiate " , PropertyInfo ( Variant : : PACKED_STRING_ARRAY , " files " ) ) ) ;
2018-11-13 20:17:33 +01:00
2023-01-23 10:01:28 +01:00
ADD_SIGNAL ( MethodInfo ( " resource_removed " , PropertyInfo ( Variant : : OBJECT , " resource " , PROPERTY_HINT_RESOURCE_TYPE , " Resource " ) ) ) ;
2018-11-13 20:17:33 +01:00
ADD_SIGNAL ( MethodInfo ( " file_removed " , PropertyInfo ( Variant : : STRING , " file " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " folder_removed " , PropertyInfo ( Variant : : STRING , " folder " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " files_moved " , PropertyInfo ( Variant : : STRING , " old_file " ) , PropertyInfo ( Variant : : STRING , " new_file " ) ) ) ;
2022-10-07 18:38:29 +02:00
ADD_SIGNAL ( MethodInfo ( " folder_moved " , PropertyInfo ( Variant : : STRING , " old_folder " ) , PropertyInfo ( Variant : : STRING , " new_folder " ) ) ) ;
2019-02-25 23:39:49 +01:00
ADD_SIGNAL ( MethodInfo ( " display_mode_changed " ) ) ;
2014-02-10 02:10:30 +01:00
}
2022-01-27 10:36:51 +01:00
FileSystemDock : : FileSystemDock ( ) {
2021-11-17 21:08:55 +01:00
singleton = this ;
2017-11-26 02:59:31 +01:00
set_name ( " FileSystem " ) ;
2023-05-11 04:17:03 +02:00
current_path = " res:// " ;
2016-05-16 01:25:51 +02:00
2022-09-02 11:37:48 +02:00
// `KeyModifierMask::CMD_OR_CTRL | Key::C` conflicts with other editor shortcuts.
ED_SHORTCUT ( " filesystem_dock/copy_path " , TTR ( " Copy Path " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : C ) ;
2022-05-02 11:51:23 +02:00
ED_SHORTCUT ( " filesystem_dock/copy_uid " , TTR ( " Copy UID " ) ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " filesystem_dock/duplicate " , TTR ( " Duplicate... " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : D ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " filesystem_dock/delete " , TTR ( " Delete " ) , Key : : KEY_DELETE ) ;
ED_SHORTCUT ( " filesystem_dock/rename " , TTR ( " Rename... " ) , Key : : F2 ) ;
ED_SHORTCUT_OVERRIDE ( " filesystem_dock/rename " , " macos " , Key : : ENTER ) ;
2023-01-15 22:50:40 +01:00
# if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
// Opening the system file manager or opening in an external program is not supported on the Android and web editors.
2023-01-08 18:00:07 +01:00
ED_SHORTCUT ( " filesystem_dock/show_in_explorer " , TTR ( " Open in File Manager " ) ) ;
2023-01-22 01:29:59 +01:00
ED_SHORTCUT ( " filesystem_dock/open_in_external_program " , TTR ( " Open in External Program " ) ) ;
2023-01-15 22:50:40 +01:00
# endif
2018-01-05 20:45:54 +01:00
2018-09-13 21:49:56 +02:00
VBoxContainer * top_vbc = memnew ( VBoxContainer ) ;
add_child ( top_vbc ) ;
2017-03-05 16:44:50 +01:00
HBoxContainer * toolbar_hbc = memnew ( HBoxContainer ) ;
2022-02-08 10:14:58 +01:00
toolbar_hbc - > add_theme_constant_override ( " separation " , 0 ) ;
2018-09-13 21:49:56 +02:00
top_vbc - > add_child ( toolbar_hbc ) ;
2014-02-10 02:10:30 +01:00
2020-06-19 20:49:04 +02:00
button_hist_prev = memnew ( Button ) ;
button_hist_prev - > set_flat ( true ) ;
2015-08-24 01:15:56 +02:00
button_hist_prev - > set_disabled ( true ) ;
2017-09-03 22:35:18 +02:00
button_hist_prev - > set_focus_mode ( FOCUS_NONE ) ;
2022-07-29 02:30:20 +02:00
button_hist_prev - > set_tooltip_text ( TTR ( " Go to previous selected folder/file. " ) ) ;
2017-09-03 22:35:18 +02:00
toolbar_hbc - > add_child ( button_hist_prev ) ;
2015-08-24 01:15:56 +02:00
2020-06-19 20:49:04 +02:00
button_hist_next = memnew ( Button ) ;
button_hist_next - > set_flat ( true ) ;
2015-08-24 01:15:56 +02:00
button_hist_next - > set_disabled ( true ) ;
button_hist_next - > set_focus_mode ( FOCUS_NONE ) ;
2022-07-29 02:30:20 +02:00
button_hist_next - > set_tooltip_text ( TTR ( " Go to next selected folder/file. " ) ) ;
2017-09-03 22:35:18 +02:00
toolbar_hbc - > add_child ( button_hist_next ) ;
2015-08-24 01:15:56 +02:00
2023-05-11 04:17:03 +02:00
current_path_line_edit = memnew ( LineEdit ) ;
current_path_line_edit - > set_structured_text_bidi_override ( TextServer : : STRUCTURED_TEXT_FILE ) ;
current_path_line_edit - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
_set_current_path_line_edit_text ( current_path ) ;
toolbar_hbc - > add_child ( current_path_line_edit ) ;
2016-05-24 04:24:17 +02:00
2017-03-05 16:44:50 +01:00
button_reload = memnew ( Button ) ;
2020-02-21 18:28:45 +01:00
button_reload - > connect ( " pressed " , callable_mp ( this , & FileSystemDock : : _rescan ) ) ;
2015-08-24 01:15:56 +02:00
button_reload - > set_focus_mode ( FOCUS_NONE ) ;
2022-08-25 12:42:17 +02:00
button_reload - > set_tooltip_text ( TTR ( " Re-Scan Filesystem " ) ) ;
2016-05-24 04:24:17 +02:00
button_reload - > hide ( ) ;
2017-09-03 22:35:18 +02:00
toolbar_hbc - > add_child ( button_reload ) ;
2015-08-24 01:15:56 +02:00
2018-09-14 00:16:43 +02:00
button_toggle_display_mode = memnew ( Button ) ;
button_toggle_display_mode - > set_toggle_mode ( true ) ;
2020-02-21 18:28:45 +01:00
button_toggle_display_mode - > connect ( " toggled " , callable_mp ( this , & FileSystemDock : : _toggle_split_mode ) ) ;
2018-09-14 00:16:43 +02:00
button_toggle_display_mode - > set_focus_mode ( FOCUS_NONE ) ;
2022-08-25 12:42:17 +02:00
button_toggle_display_mode - > set_tooltip_text ( TTR ( " Toggle Split Mode " ) ) ;
2021-05-27 17:32:30 +02:00
button_toggle_display_mode - > set_flat ( true ) ;
2018-09-14 00:16:43 +02:00
toolbar_hbc - > add_child ( button_toggle_display_mode ) ;
2020-10-07 21:56:53 +02:00
toolbar2_hbc = memnew ( HBoxContainer ) ;
2022-02-08 10:14:58 +01:00
toolbar2_hbc - > add_theme_constant_override ( " separation " , 0 ) ;
2018-09-13 21:49:56 +02:00
top_vbc - > add_child ( toolbar2_hbc ) ;
tree_search_box = memnew ( LineEdit ) ;
tree_search_box - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2022-05-27 06:02:48 +02:00
tree_search_box - > set_placeholder ( TTR ( " Filter Files " ) ) ;
2022-07-28 22:56:41 +02:00
tree_search_box - > connect ( " text_changed " , callable_mp ( this , & FileSystemDock : : _search_changed ) . bind ( tree_search_box ) ) ;
2018-09-13 21:49:56 +02:00
toolbar2_hbc - > add_child ( tree_search_box ) ;
2020-10-07 21:56:53 +02:00
tree_button_sort = _create_file_menu_button ( ) ;
toolbar2_hbc - > add_child ( tree_button_sort ) ;
2018-08-23 17:00:30 +02:00
file_list_popup = memnew ( PopupMenu ) ;
2020-03-12 13:37:40 +01:00
2018-08-23 17:00:30 +02:00
add_child ( file_list_popup ) ;
2015-08-24 01:15:56 +02:00
2018-08-23 17:00:30 +02:00
tree_popup = memnew ( PopupMenu ) ;
2020-03-12 13:37:40 +01:00
2018-08-23 17:00:30 +02:00
add_child ( tree_popup ) ;
2017-01-10 13:19:59 +01:00
2017-03-05 16:44:50 +01:00
split_box = memnew ( VSplitContainer ) ;
2016-05-16 01:25:51 +02:00
split_box - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-09-03 22:35:18 +02:00
add_child ( split_box ) ;
2014-05-16 13:48:23 +02:00
2022-07-20 23:44:06 +02:00
tree = memnew ( FileSystemTree ) ;
2015-08-24 01:15:56 +02:00
tree - > set_hide_root ( true ) ;
2023-01-14 03:37:19 +01:00
SET_DRAG_FORWARDING_GCD ( tree , FileSystemDock ) ;
2017-01-10 13:19:59 +01:00
tree - > set_allow_rmb_select ( true ) ;
2018-08-23 17:00:30 +02:00
tree - > set_select_mode ( Tree : : SELECT_MULTI ) ;
2018-09-24 11:59:43 +02:00
tree - > set_custom_minimum_size ( Size2 ( 0 , 15 * EDSCALE ) ) ;
2023-01-07 14:05:10 +01:00
tree - > set_column_clip_content ( 0 , true ) ;
2017-09-03 22:35:18 +02:00
split_box - > add_child ( tree ) ;
2014-05-16 13:48:23 +02:00
2020-02-21 18:28:45 +01:00
tree - > connect ( " item_activated " , callable_mp ( this , & FileSystemDock : : _tree_activate_file ) ) ;
tree - > connect ( " multi_selected " , callable_mp ( this , & FileSystemDock : : _tree_multi_selected ) ) ;
2021-09-18 09:33:18 +02:00
tree - > connect ( " item_mouse_selected " , callable_mp ( this , & FileSystemDock : : _tree_rmb_select ) ) ;
tree - > connect ( " empty_clicked " , callable_mp ( this , & FileSystemDock : : _tree_empty_click ) ) ;
2020-02-21 18:28:45 +01:00
tree - > connect ( " nothing_selected " , callable_mp ( this , & FileSystemDock : : _tree_empty_selected ) ) ;
tree - > connect ( " gui_input " , callable_mp ( this , & FileSystemDock : : _tree_gui_input ) ) ;
2022-03-03 21:36:56 +01:00
tree - > connect ( " mouse_exited " , callable_mp ( this , & FileSystemDock : : _tree_mouse_exited ) ) ;
2022-11-26 15:58:25 +01:00
tree - > connect ( " item_edited " , callable_mp ( this , & FileSystemDock : : _rename_operation_confirm ) ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
file_list_vb = memnew ( VBoxContainer ) ;
2016-05-16 01:25:51 +02:00
file_list_vb - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-09-03 22:35:18 +02:00
split_box - > add_child ( file_list_vb ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
path_hb = memnew ( HBoxContainer ) ;
2016-05-16 01:25:51 +02:00
file_list_vb - > add_child ( path_hb ) ;
2018-09-13 21:49:56 +02:00
file_list_search_box = memnew ( LineEdit ) ;
file_list_search_box - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2022-05-27 06:02:48 +02:00
file_list_search_box - > set_placeholder ( TTR ( " Filter Files " ) ) ;
2022-07-28 22:56:41 +02:00
file_list_search_box - > connect ( " text_changed " , callable_mp ( this , & FileSystemDock : : _search_changed ) . bind ( file_list_search_box ) ) ;
2018-09-13 21:49:56 +02:00
path_hb - > add_child ( file_list_search_box ) ;
2016-05-16 01:25:51 +02:00
2020-10-07 21:56:53 +02:00
file_list_button_sort = _create_file_menu_button ( ) ;
path_hb - > add_child ( file_list_button_sort ) ;
2020-06-19 20:49:04 +02:00
button_file_list_display_mode = memnew ( Button ) ;
button_file_list_display_mode - > set_flat ( true ) ;
2018-08-13 19:05:31 +02:00
path_hb - > add_child ( button_file_list_display_mode ) ;
2015-08-24 01:15:56 +02:00
2022-07-20 23:44:06 +02:00
files = memnew ( FileSystemList ) ;
2017-09-03 22:35:18 +02:00
files - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
files - > set_select_mode ( ItemList : : SELECT_MULTI ) ;
2023-01-14 03:37:19 +01:00
SET_DRAG_FORWARDING_GCD ( files , FileSystemDock ) ;
2022-05-09 20:17:04 +02:00
files - > connect ( " item_clicked " , callable_mp ( this , & FileSystemDock : : _file_list_item_clicked ) ) ;
2020-02-21 18:28:45 +01:00
files - > connect ( " gui_input " , callable_mp ( this , & FileSystemDock : : _file_list_gui_input ) ) ;
files - > connect ( " multi_selected " , callable_mp ( this , & FileSystemDock : : _file_multi_selected ) ) ;
2022-05-09 20:17:04 +02:00
files - > connect ( " empty_clicked " , callable_mp ( this , & FileSystemDock : : _file_list_empty_clicked ) ) ;
2023-05-26 23:04:14 +02:00
files - > connect ( " item_edited " , callable_mp ( this , & FileSystemDock : : _rename_operation_confirm ) ) ;
2018-09-24 11:59:43 +02:00
files - > set_custom_minimum_size ( Size2 ( 0 , 15 * EDSCALE ) ) ;
2017-09-03 22:35:18 +02:00
files - > set_allow_rmb_select ( true ) ;
2016-05-16 01:25:51 +02:00
file_list_vb - > add_child ( files ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
scanning_vb = memnew ( VBoxContainer ) ;
2017-09-03 22:35:18 +02:00
scanning_vb - > hide ( ) ;
add_child ( scanning_vb ) ;
2017-03-05 16:44:50 +01:00
Label * slabel = memnew ( Label ) ;
2018-04-22 19:36:01 +02:00
slabel - > set_text ( TTR ( " Scanning Files, \n Please Wait... " ) ) ;
2021-11-25 03:58:47 +01:00
slabel - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2015-08-24 01:15:56 +02:00
scanning_vb - > add_child ( slabel ) ;
2017-09-03 22:35:18 +02:00
2017-03-05 16:44:50 +01:00
scanning_progress = memnew ( ProgressBar ) ;
2015-08-24 01:15:56 +02:00
scanning_vb - > add_child ( scanning_progress ) ;
2017-03-05 16:44:50 +01:00
deps_editor = memnew ( DependencyEditor ) ;
2015-08-24 01:15:56 +02:00
add_child ( deps_editor ) ;
2022-01-27 10:36:51 +01:00
owners_editor = memnew ( DependencyEditorOwners ( ) ) ;
2015-08-24 01:15:56 +02:00
add_child ( owners_editor ) ;
2017-03-05 16:44:50 +01:00
remove_dialog = memnew ( DependencyRemoveDialog ) ;
2023-01-23 10:01:28 +01:00
remove_dialog - > connect ( " resource_removed " , callable_mp ( this , & FileSystemDock : : _resource_removed ) ) ;
2020-03-17 01:40:15 +01:00
remove_dialog - > connect ( " file_removed " , callable_mp ( this , & FileSystemDock : : _file_removed ) ) ;
remove_dialog - > connect ( " folder_removed " , callable_mp ( this , & FileSystemDock : : _folder_removed ) ) ;
2015-08-24 01:15:56 +02:00
add_child ( remove_dialog ) ;
2017-03-05 16:44:50 +01:00
move_dialog = memnew ( EditorDirDialog ) ;
2016-03-09 00:00:52 +01:00
add_child ( move_dialog ) ;
2023-03-25 20:58:37 +01:00
move_dialog - > connect ( " dir_selected " , callable_mp ( this , & FileSystemDock : : _move_dialog_confirm ) ) ;
2016-03-09 00:00:52 +01:00
2018-05-29 14:33:11 +02:00
overwrite_dialog = memnew ( ConfirmationDialog ) ;
add_child ( overwrite_dialog ) ;
2023-03-25 20:58:37 +01:00
overwrite_dialog - > set_ok_button_text ( TTR ( " Overwrite " ) ) ;
overwrite_dialog - > add_button ( TTR ( " Keep Both " ) , true ) - > connect ( " pressed " , callable_mp ( this , & FileSystemDock : : _overwrite_dialog_action ) . bind ( false ) ) ;
overwrite_dialog - > connect ( " confirmed " , callable_mp ( this , & FileSystemDock : : _overwrite_dialog_action ) . bind ( true ) ) ;
2018-05-29 14:33:11 +02:00
2023-05-18 00:09:44 +02:00
VBoxContainer * overwrite_dialog_vb = memnew ( VBoxContainer ) ;
overwrite_dialog - > add_child ( overwrite_dialog_vb ) ;
overwrite_dialog_header = memnew ( Label ) ;
overwrite_dialog_vb - > add_child ( overwrite_dialog_header ) ;
overwrite_dialog_scroll = memnew ( ScrollContainer ) ;
overwrite_dialog_vb - > add_child ( overwrite_dialog_scroll ) ;
overwrite_dialog_scroll - > set_custom_minimum_size ( Vector2 ( 400 , 600 ) * EDSCALE ) ;
overwrite_dialog_file_list = memnew ( Label ) ;
overwrite_dialog_scroll - > add_child ( overwrite_dialog_file_list ) ;
overwrite_dialog_footer = memnew ( Label ) ;
overwrite_dialog_vb - > add_child ( overwrite_dialog_footer ) ;
2017-12-01 12:13:50 +01:00
duplicate_dialog = memnew ( ConfirmationDialog ) ;
VBoxContainer * duplicate_dialog_vb = memnew ( VBoxContainer ) ;
duplicate_dialog - > add_child ( duplicate_dialog_vb ) ;
duplicate_dialog_text = memnew ( LineEdit ) ;
duplicate_dialog_vb - > add_margin_child ( TTR ( " Name: " ) , duplicate_dialog_text ) ;
2022-07-08 02:31:19 +02:00
duplicate_dialog - > set_ok_button_text ( TTR ( " Duplicate " ) ) ;
2017-12-01 12:13:50 +01:00
add_child ( duplicate_dialog ) ;
duplicate_dialog - > register_text_enter ( duplicate_dialog_text ) ;
2020-02-21 18:28:45 +01:00
duplicate_dialog - > connect ( " confirmed " , callable_mp ( this , & FileSystemDock : : _duplicate_operation_confirm ) ) ;
2017-12-01 12:13:50 +01:00
2023-04-15 12:15:57 +02:00
make_dir_dialog = memnew ( DirectoryCreateDialog ) ;
2017-10-02 00:33:43 +02:00
add_child ( make_dir_dialog ) ;
2023-04-15 12:15:57 +02:00
make_dir_dialog - > connect ( " dir_created " , callable_mp ( this , & FileSystemDock : : _rescan ) ) ;
2017-10-02 00:33:43 +02:00
2022-06-12 02:11:52 +02:00
make_scene_dialog = memnew ( SceneCreateDialog ) ;
2019-08-15 19:47:21 +02:00
add_child ( make_scene_dialog ) ;
2020-02-21 18:28:45 +01:00
make_scene_dialog - > connect ( " confirmed " , callable_mp ( this , & FileSystemDock : : _make_scene_confirm ) ) ;
2019-08-15 19:47:21 +02:00
2019-12-24 07:37:55 +01:00
make_script_dialog = memnew ( ScriptCreateDialog ) ;
make_script_dialog - > set_title ( TTR ( " Create Script " ) ) ;
add_child ( make_script_dialog ) ;
2018-04-25 09:18:10 +02:00
2021-12-03 15:45:32 +01:00
make_shader_dialog = memnew ( ShaderCreateDialog ) ;
add_child ( make_shader_dialog ) ;
2018-07-22 17:53:40 +02:00
new_resource_dialog = memnew ( CreateDialog ) ;
add_child ( new_resource_dialog ) ;
new_resource_dialog - > set_base_type ( " Resource " ) ;
2020-02-21 18:28:45 +01:00
new_resource_dialog - > connect ( " create " , callable_mp ( this , & FileSystemDock : : _resource_created ) ) ;
2018-07-22 17:53:40 +02:00
2018-09-14 00:16:43 +02:00
searched_string = String ( ) ;
uncollapsed_paths_before_search = Vector < String > ( ) ;
2018-09-12 13:10:49 +02:00
tree_update_id = 0 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
history_pos = 0 ;
2017-09-03 22:35:18 +02:00
history_max_size = 20 ;
history . push_back ( " res:// " ) ;
2016-05-16 01:25:51 +02:00
2019-02-25 23:39:49 +01:00
display_mode = DISPLAY_MODE_TREE_ONLY ;
old_display_mode = DISPLAY_MODE_TREE_ONLY ;
2018-08-13 19:05:31 +02:00
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS ;
2022-07-20 23:44:06 +02:00
add_resource_tooltip_plugin ( memnew ( EditorTextureTooltipPlugin ) ) ;
2014-05-16 13:48:23 +02:00
}
2016-07-21 15:34:57 +02:00
FileSystemDock : : ~ FileSystemDock ( ) {
2021-11-17 21:08:55 +01:00
singleton = nullptr ;
2014-05-16 13:48:23 +02:00
}