2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* project_export.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2020-01-01 10:16:22 +00:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* 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-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "project_export.h"
2018-08-18 13:07:23 +00:00
2018-09-11 16:13:45 +00:00
# include "core/compressed_translation.h"
# include "core/io/image_loader.h"
# include "core/io/resource_loader.h"
# include "core/io/resource_saver.h"
# include "core/os/dir_access.h"
# include "core/os/file_access.h"
# include "core/os/os.h"
# include "core/project_settings.h"
2017-03-05 15:44:50 +00:00
# include "editor_data.h"
# include "editor_node.h"
2019-12-24 07:17:23 +00:00
# include "editor_scale.h"
2017-03-05 15:44:50 +00:00
# include "editor_settings.h"
2014-02-10 01:10:30 +00:00
# include "scene/gui/box_container.h"
2017-02-20 02:19:30 +00:00
# include "scene/gui/margin_container.h"
2017-03-05 15:44:50 +00:00
# include "scene/gui/scroll_container.h"
# include "scene/gui/tab_container.h"
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _notification ( int p_what ) {
2014-02-10 01:10:30 +00:00
2017-03-02 21:43:56 +00:00
switch ( p_what ) {
case NOTIFICATION_READY : {
2018-10-28 18:13:38 +00:00
duplicate_preset - > set_icon ( get_icon ( " Duplicate " , " EditorIcons " ) ) ;
2017-09-08 06:06:02 +00:00
delete_preset - > set_icon ( get_icon ( " Remove " , " EditorIcons " ) ) ;
2017-03-05 15:44:50 +00:00
connect ( " confirmed " , this , " _export_pck_zip " ) ;
2017-07-19 20:00:46 +00:00
custom_feature_display - > get_parent_control ( ) - > add_style_override ( " panel " , get_stylebox ( " bg " , " Tree " ) ) ;
2017-03-02 21:43:56 +00:00
} break ;
case NOTIFICATION_POPUP_HIDE : {
2018-12-04 15:52:56 +00:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " dialog_bounds " , " export " , get_rect ( ) ) ;
2017-03-02 21:43:56 +00:00
} break ;
2018-02-25 16:04:16 +00:00
case NOTIFICATION_THEME_CHANGED : {
2018-10-28 18:13:38 +00:00
duplicate_preset - > set_icon ( get_icon ( " Duplicate " , " EditorIcons " ) ) ;
2018-02-25 16:04:16 +00:00
delete_preset - > set_icon ( get_icon ( " Remove " , " EditorIcons " ) ) ;
} break ;
2014-02-10 01:10:30 +00:00
}
}
2016-01-27 10:23:12 +00:00
void ProjectExportDialog : : popup_export ( ) {
2017-02-20 02:19:30 +00:00
add_preset - > get_popup ( ) - > clear ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < EditorExport : : get_singleton ( ) - > get_export_platform_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
Ref < EditorExportPlatform > plat = EditorExport : : get_singleton ( ) - > get_export_platform ( i ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
add_preset - > get_popup ( ) - > add_icon_item ( plat - > get_logo ( ) , plat - > get_name ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-02-20 02:19:30 +00:00
_update_presets ( ) ;
2018-07-18 11:46:02 +00:00
if ( presets - > get_current ( ) > = 0 ) {
2018-12-23 18:28:29 +00:00
_update_current_preset ( ) ; // triggers rescan for templates if newly installed
2018-07-18 11:46:02 +00:00
}
2017-03-02 21:43:56 +00:00
// Restore valid window bounds or pop up at default size.
2018-12-04 15:52:56 +00:00
Rect2 saved_size = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " dialog_bounds " , " export " , Rect2 ( ) ) ;
if ( saved_size ! = Rect2 ( ) ) {
popup ( saved_size ) ;
2017-03-02 21:43:56 +00:00
} else {
2019-04-26 19:36:44 +00:00
popup_centered_clamped ( Size2 ( 900 , 700 ) * EDSCALE , 0.8 ) ;
2017-03-02 21:43:56 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _add_preset ( int p_platform ) {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
Ref < EditorExportPreset > preset = EditorExport : : get_singleton ( ) - > get_export_platform ( p_platform ) - > create_preset ( ) ;
ERR_FAIL_COND ( ! preset . is_valid ( ) ) ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
String name = EditorExport : : get_singleton ( ) - > get_export_platform ( p_platform ) - > get_name ( ) ;
2017-03-05 15:44:50 +00:00
bool make_runnable = true ;
int attempt = 1 ;
while ( true ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool valid = true ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) ; i + + ) {
2017-02-20 02:19:30 +00:00
Ref < EditorExportPreset > p = EditorExport : : get_singleton ( ) - > get_export_preset ( i ) ;
2017-03-05 15:44:50 +00:00
if ( p - > get_platform ( ) = = preset - > get_platform ( ) & & p - > is_runnable ( ) ) {
make_runnable = false ;
2017-02-20 02:19:30 +00:00
}
2017-03-05 15:44:50 +00:00
if ( p - > get_name ( ) = = name ) {
valid = false ;
2017-02-20 02:19:30 +00:00
break ;
}
}
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
if ( valid )
break ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
attempt + + ;
2017-03-05 15:44:50 +00:00
name = EditorExport : : get_singleton ( ) - > get_export_platform ( p_platform ) - > get_name ( ) + " " + itos ( attempt ) ;
2016-01-27 10:23:12 +00:00
}
2017-02-20 02:19:30 +00:00
preset - > set_name ( name ) ;
if ( make_runnable )
preset - > set_runnable ( make_runnable ) ;
EditorExport : : get_singleton ( ) - > add_export_preset ( preset ) ;
_update_presets ( ) ;
2017-03-05 15:44:50 +00:00
_edit_preset ( EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) - 1 ) ;
2014-02-10 01:10:30 +00:00
}
2020-04-24 07:45:14 +00:00
void ProjectExportDialog : : _force_update_current_preset_parameters ( ) {
// Force the parameters section to refresh its UI.
parameters - > edit ( nullptr ) ;
_update_current_preset ( ) ;
}
2018-12-23 18:28:29 +00:00
void ProjectExportDialog : : _update_current_preset ( ) {
_edit_preset ( presets - > get_current ( ) ) ;
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _update_presets ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
updating = true ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
Ref < EditorExportPreset > current ;
2017-03-05 15:44:50 +00:00
if ( presets - > get_current ( ) > = 0 & & presets - > get_current ( ) < presets - > get_item_count ( ) )
2018-12-23 18:28:29 +00:00
current = get_current_preset ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
int current_idx = - 1 ;
2017-02-20 02:19:30 +00:00
presets - > clear ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) ; i + + ) {
2017-02-20 02:19:30 +00:00
Ref < EditorExportPreset > preset = EditorExport : : get_singleton ( ) - > get_export_preset ( i ) ;
2017-03-05 15:44:50 +00:00
if ( preset = = current ) {
current_idx = i ;
2017-02-20 02:19:30 +00:00
}
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
String name = preset - > get_name ( ) ;
if ( preset - > is_runnable ( ) )
2017-03-05 15:44:50 +00:00
name + = " ( " + TTR ( " Runnable " ) + " ) " ;
2020-06-10 09:41:42 +00:00
preset - > update_files_to_export ( ) ;
2017-03-05 15:44:50 +00:00
presets - > add_item ( name , preset - > get_platform ( ) - > get_logo ( ) ) ;
2017-02-20 02:19:30 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( current_idx ! = - 1 ) {
2017-02-20 02:19:30 +00:00
presets - > select ( current_idx ) ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
updating = false ;
2014-02-10 01:10:30 +00:00
}
2018-11-03 15:56:31 +00:00
void ProjectExportDialog : : _update_export_all ( ) {
2019-06-26 13:08:25 +00:00
bool can_export = EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) > 0 ;
2018-11-03 15:56:31 +00:00
for ( int i = 0 ; i < EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) ; i + + ) {
Ref < EditorExportPreset > preset = EditorExport : : get_singleton ( ) - > get_export_preset ( i ) ;
bool needs_templates ;
String error ;
if ( preset - > get_export_path ( ) = = " " | | ! preset - > get_platform ( ) - > can_export ( preset , error , needs_templates ) ) {
can_export = false ;
break ;
}
}
if ( can_export ) {
export_all_button - > set_disabled ( false ) ;
} else {
export_all_button - > set_disabled ( true ) ;
}
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _edit_preset ( int p_index ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_index < 0 | | p_index > = presets - > get_item_count ( ) ) {
2017-02-20 02:19:30 +00:00
name - > set_text ( " " ) ;
name - > set_editable ( false ) ;
2018-11-12 19:04:58 +00:00
export_path - > hide ( ) ;
2017-02-20 02:19:30 +00:00
runnable - > set_disabled ( true ) ;
parameters - > edit ( NULL ) ;
2018-07-18 11:46:02 +00:00
presets - > unselect_all ( ) ;
2018-10-28 18:13:38 +00:00
duplicate_preset - > set_disabled ( true ) ;
2017-02-20 02:19:30 +00:00
delete_preset - > set_disabled ( true ) ;
sections - > hide ( ) ;
2017-03-21 02:31:41 +00:00
export_error - > hide ( ) ;
export_templates_error - > hide ( ) ;
2017-02-20 02:19:30 +00:00
return ;
}
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
Ref < EditorExportPreset > current = EditorExport : : get_singleton ( ) - > get_export_preset ( p_index ) ;
ERR_FAIL_COND ( current . is_null ( ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
updating = true ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
presets - > select ( p_index ) ;
sections - > show ( ) ;
name - > set_editable ( true ) ;
2018-11-12 19:04:58 +00:00
export_path - > show ( ) ;
2018-10-28 18:13:38 +00:00
duplicate_preset - > set_disabled ( false ) ;
2017-02-20 02:19:30 +00:00
delete_preset - > set_disabled ( false ) ;
name - > set_text ( current - > get_name ( ) ) ;
2018-11-12 19:04:58 +00:00
List < String > extension_list = current - > get_platform ( ) - > get_binary_extensions ( current ) ;
Vector < String > extension_vector ;
for ( int i = 0 ; i < extension_list . size ( ) ; i + + ) {
extension_vector . push_back ( " *. " + extension_list [ i ] ) ;
}
export_path - > setup ( extension_vector , false , true ) ;
export_path - > update_property ( ) ;
2017-02-20 02:19:30 +00:00
runnable - > set_disabled ( false ) ;
runnable - > set_pressed ( current - > is_runnable ( ) ) ;
parameters - > edit ( current . ptr ( ) ) ;
export_filter - > select ( current - > get_export_filter ( ) ) ;
include_filters - > set_text ( current - > get_include_filter ( ) ) ;
exclude_filters - > set_text ( current - > get_exclude_filter ( ) ) ;
_fill_resource_tree ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-21 02:31:41 +00:00
bool needs_templates ;
String error ;
if ( ! current - > get_platform ( ) - > can_export ( current , error , needs_templates ) ) {
if ( error ! = String ( ) ) {
2018-08-17 09:27:26 +00:00
Vector < String > items = error . split ( " \n " , false ) ;
2017-03-21 02:31:41 +00:00
error = " " ;
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
if ( i > 0 )
error + = " \n " ;
error + = " - " + items [ i ] ;
}
export_error - > set_text ( error ) ;
export_error - > show ( ) ;
} else {
export_error - > hide ( ) ;
}
if ( needs_templates )
export_templates_error - > show ( ) ;
2017-04-21 23:15:42 +00:00
else
export_templates_error - > hide ( ) ;
2017-03-21 02:31:41 +00:00
2017-03-28 01:21:21 +00:00
export_button - > set_disabled ( true ) ;
2019-10-16 09:54:04 +00:00
get_ok ( ) - > set_disabled ( true ) ;
2017-03-21 22:34:26 +00:00
2017-03-21 02:31:41 +00:00
} else {
2017-06-21 09:11:38 +00:00
export_error - > hide ( ) ;
2017-03-21 02:31:41 +00:00
export_templates_error - > hide ( ) ;
2017-03-28 01:21:21 +00:00
export_button - > set_disabled ( false ) ;
2019-10-16 09:54:04 +00:00
get_ok ( ) - > set_disabled ( false ) ;
2017-03-21 02:31:41 +00:00
}
2017-07-19 20:00:46 +00:00
custom_features - > set_text ( current - > get_custom_features ( ) ) ;
_update_feature_list ( ) ;
2018-11-03 15:56:31 +00:00
_update_export_all ( ) ;
2018-12-07 02:39:16 +00:00
minimum_size_changed ( ) ;
2017-07-19 20:00:46 +00:00
2018-12-23 18:28:29 +00:00
int script_export_mode = current - > get_script_export_mode ( ) ;
script_mode - > select ( script_export_mode ) ;
String key = current - > get_script_encryption_key ( ) ;
if ( ! updating_script_key ) {
script_key - > set_text ( key ) ;
}
if ( script_export_mode = = EditorExportPreset : : MODE_SCRIPT_ENCRYPTED ) {
script_key - > set_editable ( true ) ;
bool key_valid = _validate_script_encryption_key ( key ) ;
if ( key_valid ) {
script_key_error - > hide ( ) ;
} else {
script_key_error - > show ( ) ;
}
} else {
script_key - > set_editable ( false ) ;
script_key_error - > hide ( ) ;
}
2017-03-05 15:44:50 +00:00
updating = false ;
2014-02-26 13:08:17 +00:00
}
2017-07-19 20:00:46 +00:00
void ProjectExportDialog : : _update_feature_list ( ) {
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-07-19 20:00:46 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
Set < String > fset ;
List < String > features ;
current - > get_platform ( ) - > get_platform_features ( & features ) ;
current - > get_platform ( ) - > get_preset_features ( current , & features ) ;
String custom = current - > get_custom_features ( ) ;
Vector < String > custom_list = custom . split ( " , " ) ;
for ( int i = 0 ; i < custom_list . size ( ) ; i + + ) {
String f = custom_list [ i ] . strip_edges ( ) ;
if ( f ! = String ( ) ) {
features . push_back ( f ) ;
}
}
for ( List < String > : : Element * E = features . front ( ) ; E ; E = E - > next ( ) ) {
fset . insert ( E - > get ( ) ) ;
}
custom_feature_display - > clear ( ) ;
for ( Set < String > : : Element * E = fset . front ( ) ; E ; E = E - > next ( ) ) {
String f = E - > get ( ) ;
if ( E - > next ( ) ) {
f + = " , " ;
}
custom_feature_display - > add_text ( f ) ;
}
}
void ProjectExportDialog : : _custom_features_changed ( const String & p_text ) {
if ( updating )
return ;
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-07-19 20:00:46 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
current - > set_custom_features ( p_text ) ;
_update_feature_list ( ) ;
}
void ProjectExportDialog : : _tab_changed ( int ) {
_update_feature_list ( ) ;
}
2017-03-28 01:21:21 +00:00
void ProjectExportDialog : : _update_parameters ( const String & p_edited_property ) {
2018-12-23 18:28:29 +00:00
_update_current_preset ( ) ;
2017-03-28 01:21:21 +00:00
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _runnable_pressed ( ) {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
if ( updating )
return ;
2014-02-15 05:01:39 +00:00
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-02-20 02:19:30 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
2014-02-15 05:01:39 +00:00
2017-02-20 02:19:30 +00:00
if ( runnable - > is_pressed ( ) ) {
2014-02-15 05:01:39 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) ; i + + ) {
2017-02-20 02:19:30 +00:00
Ref < EditorExportPreset > p = EditorExport : : get_singleton ( ) - > get_export_preset ( i ) ;
2017-03-05 15:44:50 +00:00
if ( p - > get_platform ( ) = = current - > get_platform ( ) ) {
p - > set_runnable ( current = = p ) ;
2017-02-20 02:19:30 +00:00
}
2014-02-15 05:01:39 +00:00
}
2017-02-20 02:19:30 +00:00
} else {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
current - > set_runnable ( false ) ;
2014-02-10 01:10:30 +00:00
}
2017-02-20 02:19:30 +00:00
_update_presets ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void ProjectExportDialog : : _name_changed ( const String & p_string ) {
2014-02-13 21:03:28 +00:00
2017-02-20 02:19:30 +00:00
if ( updating )
2014-02-13 21:03:28 +00:00
return ;
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-02-20 02:19:30 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
2015-12-13 04:08:36 +00:00
2017-02-20 02:19:30 +00:00
current - > set_name ( p_string ) ;
_update_presets ( ) ;
2014-02-13 21:03:28 +00:00
}
2018-11-12 19:04:58 +00:00
void ProjectExportDialog : : set_export_path ( const String & p_value ) {
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2018-11-12 19:04:58 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
current - > set_export_path ( p_value ) ;
}
String ProjectExportDialog : : get_export_path ( ) {
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2018-11-12 19:04:58 +00:00
ERR_FAIL_COND_V ( current . is_null ( ) , String ( " " ) ) ;
return current - > get_export_path ( ) ;
}
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > ProjectExportDialog : : get_current_preset ( ) const {
return EditorExport : : get_singleton ( ) - > get_export_preset ( presets - > get_current ( ) ) ;
}
2019-01-18 16:01:24 +00:00
void ProjectExportDialog : : _export_path_changed ( const StringName & p_property , const Variant & p_value , const String & p_field , bool p_changing ) {
2018-11-06 01:01:34 +00:00
if ( updating )
return ;
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2018-11-06 01:01:34 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
2018-11-12 19:04:58 +00:00
current - > set_export_path ( p_value ) ;
2018-11-06 01:01:34 +00:00
_update_presets ( ) ;
}
2018-12-23 18:28:29 +00:00
void ProjectExportDialog : : _script_export_mode_changed ( int p_mode ) {
if ( updating )
return ;
Ref < EditorExportPreset > current = get_current_preset ( ) ;
ERR_FAIL_COND ( current . is_null ( ) ) ;
current - > set_script_export_mode ( p_mode ) ;
_update_current_preset ( ) ;
}
void ProjectExportDialog : : _script_encryption_key_changed ( const String & p_key ) {
if ( updating )
return ;
Ref < EditorExportPreset > current = get_current_preset ( ) ;
ERR_FAIL_COND ( current . is_null ( ) ) ;
current - > set_script_encryption_key ( p_key ) ;
updating_script_key = true ;
_update_current_preset ( ) ;
updating_script_key = false ;
}
bool ProjectExportDialog : : _validate_script_encryption_key ( const String & p_key ) {
bool is_valid = false ;
if ( ! p_key . empty ( ) & & p_key . is_valid_hex_number ( false ) & & p_key . length ( ) = = 64 ) {
is_valid = true ;
}
return is_valid ;
}
2018-10-28 18:13:38 +00:00
void ProjectExportDialog : : _duplicate_preset ( ) {
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2018-10-28 18:13:38 +00:00
if ( current . is_null ( ) )
return ;
Ref < EditorExportPreset > preset = current - > get_platform ( ) - > create_preset ( ) ;
ERR_FAIL_COND ( ! preset . is_valid ( ) ) ;
2019-05-23 12:45:17 +00:00
String name = current - > get_name ( ) + " (copy) " ;
2018-10-28 18:13:38 +00:00
bool make_runnable = true ;
while ( true ) {
bool valid = true ;
for ( int i = 0 ; i < EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) ; i + + ) {
Ref < EditorExportPreset > p = EditorExport : : get_singleton ( ) - > get_export_preset ( i ) ;
if ( p - > get_platform ( ) = = preset - > get_platform ( ) & & p - > is_runnable ( ) ) {
make_runnable = false ;
}
if ( p - > get_name ( ) = = name ) {
valid = false ;
break ;
}
}
if ( valid )
break ;
2019-05-23 12:45:17 +00:00
name + = " (copy) " ;
2018-10-28 18:13:38 +00:00
}
preset - > set_name ( name ) ;
if ( make_runnable )
preset - > set_runnable ( make_runnable ) ;
preset - > set_export_filter ( current - > get_export_filter ( ) ) ;
preset - > set_include_filter ( current - > get_include_filter ( ) ) ;
preset - > set_exclude_filter ( current - > get_exclude_filter ( ) ) ;
preset - > set_custom_features ( current - > get_custom_features ( ) ) ;
for ( const List < PropertyInfo > : : Element * E = current - > get_properties ( ) . front ( ) ; E ; E = E - > next ( ) ) {
preset - > set ( E - > get ( ) . name , current - > get ( E - > get ( ) . name ) ) ;
}
EditorExport : : get_singleton ( ) - > add_export_preset ( preset ) ;
_update_presets ( ) ;
_edit_preset ( EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) - 1 ) ;
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _delete_preset ( ) {
2014-02-13 21:03:28 +00:00
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-02-20 02:19:30 +00:00
if ( current . is_null ( ) )
return ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
delete_confirm - > set_text ( vformat ( TTR ( " Delete preset '%s'? " ) , current - > get_name ( ) ) ) ;
2017-02-20 02:19:30 +00:00
delete_confirm - > popup_centered_minsize ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _delete_preset_confirm ( ) {
2014-02-13 21:03:28 +00:00
2017-02-20 02:19:30 +00:00
int idx = presets - > get_current ( ) ;
2017-09-04 18:45:18 +00:00
_edit_preset ( - 1 ) ;
2019-04-23 15:49:15 +00:00
export_button - > set_disabled ( true ) ;
2019-10-16 09:54:04 +00:00
get_ok ( ) - > set_disabled ( true ) ;
2017-02-20 02:19:30 +00:00
EditorExport : : get_singleton ( ) - > remove_export_preset ( idx ) ;
_update_presets ( ) ;
2014-02-13 21:03:28 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Variant ProjectExportDialog : : get_drag_data_fw ( const Point2 & p_point , Control * p_from ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_from = = presets ) {
2017-09-10 13:37:49 +00:00
int pos = presets - > get_item_at_position ( p_point , true ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( pos > = 0 ) {
2017-02-20 02:19:30 +00:00
Dictionary d ;
2017-03-05 15:44:50 +00:00
d [ " type " ] = " export_preset " ;
d [ " preset " ] = pos ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
HBoxContainer * drag = memnew ( HBoxContainer ) ;
2017-02-20 02:19:30 +00:00
TextureRect * tr = memnew ( TextureRect ) ;
tr - > set_texture ( presets - > get_item_icon ( pos ) ) ;
drag - > add_child ( tr ) ;
2017-03-05 15:44:50 +00:00
Label * label = memnew ( Label ) ;
2017-02-20 02:19:30 +00:00
label - > set_text ( presets - > get_item_text ( pos ) ) ;
drag - > add_child ( label ) ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
set_drag_preview ( drag ) ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
return d ;
}
}
2016-11-26 14:30:46 +00:00
2017-02-20 02:19:30 +00:00
return Variant ( ) ;
2016-11-26 14:30:46 +00:00
}
2017-03-05 15:44:50 +00:00
bool ProjectExportDialog : : can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
2016-11-26 14:30:46 +00:00
2017-03-05 15:44:50 +00:00
if ( p_from = = presets ) {
2017-02-20 02:19:30 +00:00
Dictionary d = p_data ;
2017-03-05 15:44:50 +00:00
if ( ! d . has ( " type " ) | | String ( d [ " type " ] ) ! = " export_preset " )
2017-02-20 02:19:30 +00:00
return false ;
2016-11-26 14:30:46 +00:00
2017-09-10 13:37:49 +00:00
if ( presets - > get_item_at_position ( p_point , true ) < 0 & & ! presets - > is_pos_at_end_of_items ( p_point ) )
2017-02-20 02:19:30 +00:00
return false ;
2016-11-26 14:30:46 +00:00
}
2017-02-20 02:19:30 +00:00
return true ;
2016-11-26 14:30:46 +00:00
}
2017-03-05 15:44:50 +00:00
void ProjectExportDialog : : drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
2016-11-26 14:30:46 +00:00
2017-03-05 15:44:50 +00:00
if ( p_from = = presets ) {
Dictionary d = p_data ;
2017-02-20 02:19:30 +00:00
int from_pos = d [ " preset " ] ;
2016-11-26 14:30:46 +00:00
2017-03-05 15:44:50 +00:00
int to_pos = - 1 ;
2016-11-26 14:30:46 +00:00
2017-09-10 13:37:49 +00:00
if ( presets - > get_item_at_position ( p_point , true ) > = 0 ) {
to_pos = presets - > get_item_at_position ( p_point , true ) ;
2016-11-26 14:30:46 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( to_pos = = - 1 & & ! presets - > is_pos_at_end_of_items ( p_point ) )
2017-02-20 02:19:30 +00:00
return ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( to_pos = = from_pos )
2017-02-20 02:19:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
else if ( to_pos > from_pos ) {
2017-02-20 02:19:30 +00:00
to_pos - - ;
}
2014-10-23 10:04:21 +00:00
2017-02-20 02:19:30 +00:00
Ref < EditorExportPreset > preset = EditorExport : : get_singleton ( ) - > get_export_preset ( from_pos ) ;
EditorExport : : get_singleton ( ) - > remove_export_preset ( from_pos ) ;
2017-03-05 15:44:50 +00:00
EditorExport : : get_singleton ( ) - > add_export_preset ( preset , to_pos ) ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
_update_presets ( ) ;
2017-03-05 15:44:50 +00:00
if ( to_pos > = 0 )
2017-02-20 02:19:30 +00:00
_edit_preset ( to_pos ) ;
else
2017-03-05 15:44:50 +00:00
_edit_preset ( presets - > get_item_count ( ) - 1 ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _export_type_changed ( int p_which ) {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
if ( updating )
2014-02-10 01:10:30 +00:00
return ;
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-02-20 02:19:30 +00:00
if ( current . is_null ( ) )
2014-02-10 01:10:30 +00:00
return ;
2017-02-20 02:19:30 +00:00
current - > set_export_filter ( EditorExportPreset : : ExportFilter ( p_which ) ) ;
2017-03-05 15:44:50 +00:00
updating = true ;
2017-02-20 02:19:30 +00:00
_fill_resource_tree ( ) ;
2017-03-05 15:44:50 +00:00
updating = false ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void ProjectExportDialog : : _filter_changed ( const String & p_filter ) {
2014-02-10 01:10:30 +00:00
if ( updating )
return ;
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-02-20 02:19:30 +00:00
if ( current . is_null ( ) )
return ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
current - > set_include_filter ( include_filters - > get_text ( ) ) ;
current - > set_exclude_filter ( exclude_filters - > get_text ( ) ) ;
}
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _fill_resource_tree ( ) {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
include_files - > clear ( ) ;
include_label - > hide ( ) ;
include_margin - > hide ( ) ;
2014-02-10 01:10:30 +00:00
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-02-20 02:19:30 +00:00
if ( current . is_null ( ) )
return ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
EditorExportPreset : : ExportFilter f = current - > get_export_filter ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( f = = EditorExportPreset : : EXPORT_ALL_RESOURCES ) {
2017-02-20 02:19:30 +00:00
return ;
2014-02-10 01:10:30 +00:00
}
2017-02-20 02:19:30 +00:00
include_label - > show ( ) ;
include_margin - > show ( ) ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
TreeItem * root = include_files - > create_item ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
_fill_tree ( EditorFileSystem : : get_singleton ( ) - > get_filesystem ( ) , root , current , f = = EditorExportPreset : : EXPORT_SELECTED_SCENES ) ;
2017-02-20 02:19:30 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool ProjectExportDialog : : _fill_tree ( EditorFileSystemDirectory * p_dir , TreeItem * p_item , Ref < EditorExportPreset > & current , bool p_only_scenes ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
p_item - > set_icon ( 0 , get_icon ( " folder " , " FileDialog " ) ) ;
p_item - > set_text ( 0 , p_dir - > get_name ( ) + " / " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool used = false ;
for ( int i = 0 ; i < p_dir - > get_subdir_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
TreeItem * subdir = include_files - > create_item ( p_item ) ;
2018-10-06 20:20:41 +00:00
if ( _fill_tree ( p_dir - > get_subdir ( i ) , subdir , current , p_only_scenes ) ) {
2017-03-05 15:44:50 +00:00
used = true ;
2018-10-06 20:20:41 +00:00
} else {
memdelete ( subdir ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_dir - > get_file_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
String type = p_dir - > get_file_type ( i ) ;
2017-03-05 15:44:50 +00:00
if ( p_only_scenes & & type ! = " PackedScene " )
2017-02-20 02:19:30 +00:00
continue ;
2014-06-11 13:41:03 +00:00
2017-02-20 02:19:30 +00:00
TreeItem * file = include_files - > create_item ( p_item ) ;
2017-03-05 15:44:50 +00:00
file - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
file - > set_text ( 0 , p_dir - > get_file ( i ) ) ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
String path = p_dir - > get_file_path ( i ) ;
2014-02-10 01:10:30 +00:00
2018-09-02 21:40:51 +00:00
file - > set_icon ( 0 , EditorNode : : get_singleton ( ) - > get_class_icon ( type ) ) ;
2017-03-05 15:44:50 +00:00
file - > set_editable ( 0 , true ) ;
file - > set_checked ( 0 , current - > has_export_file ( path ) ) ;
file - > set_metadata ( 0 , path ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
used = true ;
2017-02-20 02:19:30 +00:00
}
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
return used ;
2014-02-10 01:10:30 +00:00
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _tree_changed ( ) {
2014-02-10 01:10:30 +00:00
if ( updating )
return ;
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-02-20 02:19:30 +00:00
if ( current . is_null ( ) )
return ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
TreeItem * item = include_files - > get_edited ( ) ;
2014-02-10 01:10:30 +00:00
if ( ! item )
return ;
2017-02-20 02:19:30 +00:00
String path = item - > get_metadata ( 0 ) ;
bool added = item - > is_checked ( 0 ) ;
2014-02-10 01:10:30 +00:00
2017-02-20 02:19:30 +00:00
if ( added ) {
current - > add_export_file ( path ) ;
} else {
current - > remove_export_file ( path ) ;
}
2014-02-10 01:10:30 +00:00
}
2017-02-21 03:05:15 +00:00
void ProjectExportDialog : : _export_pck_zip ( ) {
export_pck_zip - > popup_centered_ratio ( ) ;
}
2017-03-05 15:44:50 +00:00
void ProjectExportDialog : : _export_pck_zip_selected ( const String & p_path ) {
2017-02-21 03:05:15 +00:00
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
2017-02-21 03:05:15 +00:00
Ref < EditorExportPlatform > platform = current - > get_platform ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( platform . is_null ( ) ) ;
2017-02-21 03:05:15 +00:00
if ( p_path . ends_with ( " .zip " ) ) {
2018-04-26 21:08:19 +00:00
platform - > export_zip ( current , export_pck_zip_debug - > is_pressed ( ) , p_path ) ;
2017-02-21 03:05:15 +00:00
} else if ( p_path . ends_with ( " .pck " ) ) {
2018-04-26 21:08:19 +00:00
platform - > export_pack ( current , export_pck_zip_debug - > is_pressed ( ) , p_path ) ;
2017-02-21 03:05:15 +00:00
}
}
2017-03-21 02:31:41 +00:00
void ProjectExportDialog : : _open_export_template_manager ( ) {
EditorNode : : get_singleton ( ) - > open_export_template_manager ( ) ;
hide ( ) ;
}
2018-08-31 08:48:40 +00:00
void ProjectExportDialog : : _validate_export_path ( const String & p_path ) {
// Disable export via OK button or Enter key if LineEdit has an empty filename
bool invalid_path = ( p_path . get_file ( ) . get_basename ( ) = = " " ) ;
// Check if state change before needlessly messing with signals
if ( invalid_path & & export_project - > get_ok ( ) - > is_disabled ( ) )
return ;
if ( ! invalid_path & & ! export_project - > get_ok ( ) - > is_disabled ( ) )
return ;
if ( invalid_path ) {
export_project - > get_ok ( ) - > set_disabled ( true ) ;
export_project - > get_line_edit ( ) - > disconnect ( " text_entered " , export_project , " _file_entered " ) ;
} else {
export_project - > get_ok ( ) - > set_disabled ( false ) ;
export_project - > get_line_edit ( ) - > connect ( " text_entered " , export_project , " _file_entered " ) ;
}
}
2017-03-21 22:34:26 +00:00
void ProjectExportDialog : : _export_project ( ) {
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-03-21 22:34:26 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
Ref < EditorExportPlatform > platform = current - > get_platform ( ) ;
ERR_FAIL_COND ( platform . is_null ( ) ) ;
2019-04-24 18:52:15 +00:00
export_project - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
2017-03-21 22:34:26 +00:00
export_project - > clear_filters ( ) ;
2017-12-12 21:09:48 +00:00
2018-10-29 21:18:49 +00:00
List < String > extension_list = platform - > get_binary_extensions ( current ) ;
for ( int i = 0 ; i < extension_list . size ( ) ; i + + ) {
export_project - > add_filter ( " *. " + extension_list [ i ] + " ; " + platform - > get_name ( ) + " Export " ) ;
}
2019-08-22 20:14:45 +00:00
if ( current - > get_export_path ( ) ! = " " ) {
export_project - > set_current_path ( current - > get_export_path ( ) ) ;
2018-08-31 08:48:40 +00:00
} else {
2018-10-29 21:18:49 +00:00
if ( extension_list . size ( ) > = 1 ) {
export_project - > set_current_file ( default_filename + " . " + extension_list [ 0 ] ) ;
2018-10-27 13:53:05 +00:00
} else {
export_project - > set_current_file ( default_filename ) ;
}
2018-08-31 08:48:40 +00:00
}
// Ensure that signal is connected if previous attempt left it disconnected with _validate_export_path
if ( ! export_project - > get_line_edit ( ) - > is_connected ( " text_entered " , export_project , " _file_entered " ) ) {
export_project - > get_ok ( ) - > set_disabled ( false ) ;
export_project - > get_line_edit ( ) - > connect ( " text_entered " , export_project , " _file_entered " ) ;
2017-03-21 22:34:26 +00:00
}
2019-04-24 18:52:15 +00:00
export_project - > set_mode ( EditorFileDialog : : MODE_SAVE_FILE ) ;
2017-03-21 22:34:26 +00:00
export_project - > popup_centered_ratio ( ) ;
}
void ProjectExportDialog : : _export_project_to_path ( const String & p_path ) {
2017-10-28 08:57:29 +00:00
// Save this name for use in future exports (but drop the file extension)
2018-08-31 08:48:40 +00:00
default_filename = p_path . get_file ( ) . get_basename ( ) ;
2017-10-28 08:57:29 +00:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " export_options " , " default_filename " , default_filename ) ;
2017-03-21 22:34:26 +00:00
2018-12-23 18:28:29 +00:00
Ref < EditorExportPreset > current = get_current_preset ( ) ;
2017-03-21 22:34:26 +00:00
ERR_FAIL_COND ( current . is_null ( ) ) ;
Ref < EditorExportPlatform > platform = current - > get_platform ( ) ;
ERR_FAIL_COND ( platform . is_null ( ) ) ;
2018-10-27 13:53:05 +00:00
current - > set_export_path ( p_path ) ;
2017-03-21 22:34:26 +00:00
Error err = platform - > export_project ( current , export_debug - > is_pressed ( ) , p_path , 0 ) ;
2018-12-19 18:50:40 +00:00
if ( err ! = OK & & err ! = ERR_SKIP ) {
2019-02-22 09:21:34 +00:00
if ( err = = ERR_FILE_NOT_FOUND ) {
error_dialog - > set_text ( vformat ( TTR ( " Failed to export the project for platform '%s'. \n Export templates seem to be missing or invalid. " ) , platform - > get_name ( ) ) ) ;
} else { // Assume misconfiguration. FIXME: Improve error handling and preset config validation.
error_dialog - > set_text ( vformat ( TTR ( " Failed to export the project for platform '%s'. \n This might be due to a configuration issue in the export preset or your export settings. " ) , platform - > get_name ( ) ) ) ;
}
ERR_PRINTS ( vformat ( " Failed to export the project for platform '%s'. " , platform - > get_name ( ) ) ) ;
2017-10-12 22:38:42 +00:00
error_dialog - > show ( ) ;
error_dialog - > popup_centered_minsize ( Size2 ( 300 , 80 ) ) ;
}
2017-03-21 22:34:26 +00:00
}
2018-11-03 15:56:31 +00:00
void ProjectExportDialog : : _export_all_dialog ( ) {
export_all_dialog - > show ( ) ;
export_all_dialog - > popup_centered_minsize ( Size2 ( 300 , 80 ) ) ;
}
void ProjectExportDialog : : _export_all_dialog_action ( const String & p_str ) {
export_all_dialog - > hide ( ) ;
2019-06-26 13:08:25 +00:00
_export_all ( p_str ! = " release " ) ;
2018-11-03 15:56:31 +00:00
}
void ProjectExportDialog : : _export_all ( bool p_debug ) {
String mode = p_debug ? TTR ( " Debug " ) : TTR ( " Release " ) ;
2018-12-19 18:50:40 +00:00
EditorProgress ep ( " exportall " , TTR ( " Exporting All " ) + " " + mode , EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) , true ) ;
2018-11-03 15:56:31 +00:00
for ( int i = 0 ; i < EditorExport : : get_singleton ( ) - > get_export_preset_count ( ) ; i + + ) {
Ref < EditorExportPreset > preset = EditorExport : : get_singleton ( ) - > get_export_preset ( i ) ;
ERR_FAIL_COND ( preset . is_null ( ) ) ;
Ref < EditorExportPlatform > platform = preset - > get_platform ( ) ;
ERR_FAIL_COND ( platform . is_null ( ) ) ;
ep . step ( preset - > get_name ( ) , i ) ;
Error err = platform - > export_project ( preset , p_debug , preset - > get_export_path ( ) , 0 ) ;
2018-12-19 18:50:40 +00:00
if ( err ! = OK & & err ! = ERR_SKIP ) {
2019-03-05 07:52:45 +00:00
if ( err = = ERR_FILE_BAD_PATH ) {
error_dialog - > set_text ( TTR ( " The given export path doesn't exist: " ) + " \n " + preset - > get_export_path ( ) . get_base_dir ( ) ) ;
} else {
error_dialog - > set_text ( TTR ( " Export templates for this platform are missing/corrupted: " ) + " " + platform - > get_name ( ) ) ;
}
2018-11-03 15:56:31 +00:00
error_dialog - > show ( ) ;
error_dialog - > popup_centered_minsize ( Size2 ( 300 , 80 ) ) ;
ERR_PRINT ( " Failed to export project " ) ;
}
}
}
2017-02-20 02:19:30 +00:00
void ProjectExportDialog : : _bind_methods ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _add_preset " , & ProjectExportDialog : : _add_preset ) ;
ClassDB : : bind_method ( " _edit_preset " , & ProjectExportDialog : : _edit_preset ) ;
2017-03-28 01:21:21 +00:00
ClassDB : : bind_method ( " _update_parameters " , & ProjectExportDialog : : _update_parameters ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _runnable_pressed " , & ProjectExportDialog : : _runnable_pressed ) ;
ClassDB : : bind_method ( " _name_changed " , & ProjectExportDialog : : _name_changed ) ;
2018-10-28 18:13:38 +00:00
ClassDB : : bind_method ( " _duplicate_preset " , & ProjectExportDialog : : _duplicate_preset ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _delete_preset " , & ProjectExportDialog : : _delete_preset ) ;
ClassDB : : bind_method ( " _delete_preset_confirm " , & ProjectExportDialog : : _delete_preset_confirm ) ;
ClassDB : : bind_method ( " get_drag_data_fw " , & ProjectExportDialog : : get_drag_data_fw ) ;
ClassDB : : bind_method ( " can_drop_data_fw " , & ProjectExportDialog : : can_drop_data_fw ) ;
ClassDB : : bind_method ( " drop_data_fw " , & ProjectExportDialog : : drop_data_fw ) ;
ClassDB : : bind_method ( " _export_type_changed " , & ProjectExportDialog : : _export_type_changed ) ;
ClassDB : : bind_method ( " _filter_changed " , & ProjectExportDialog : : _filter_changed ) ;
ClassDB : : bind_method ( " _tree_changed " , & ProjectExportDialog : : _tree_changed ) ;
ClassDB : : bind_method ( " _export_pck_zip " , & ProjectExportDialog : : _export_pck_zip ) ;
ClassDB : : bind_method ( " _export_pck_zip_selected " , & ProjectExportDialog : : _export_pck_zip_selected ) ;
2017-03-21 02:31:41 +00:00
ClassDB : : bind_method ( " _open_export_template_manager " , & ProjectExportDialog : : _open_export_template_manager ) ;
2018-08-31 08:48:40 +00:00
ClassDB : : bind_method ( " _validate_export_path " , & ProjectExportDialog : : _validate_export_path ) ;
2018-11-12 14:38:26 +00:00
ClassDB : : bind_method ( " _export_path_changed " , & ProjectExportDialog : : _export_path_changed ) ;
2018-12-23 18:28:29 +00:00
ClassDB : : bind_method ( " _script_export_mode_changed " , & ProjectExportDialog : : _script_export_mode_changed ) ;
ClassDB : : bind_method ( " _script_encryption_key_changed " , & ProjectExportDialog : : _script_encryption_key_changed ) ;
2017-03-21 22:34:26 +00:00
ClassDB : : bind_method ( " _export_project " , & ProjectExportDialog : : _export_project ) ;
ClassDB : : bind_method ( " _export_project_to_path " , & ProjectExportDialog : : _export_project_to_path ) ;
2018-11-03 15:56:31 +00:00
ClassDB : : bind_method ( " _export_all " , & ProjectExportDialog : : _export_all ) ;
ClassDB : : bind_method ( " _export_all_dialog " , & ProjectExportDialog : : _export_all_dialog ) ;
ClassDB : : bind_method ( " _export_all_dialog_action " , & ProjectExportDialog : : _export_all_dialog_action ) ;
2017-07-19 20:00:46 +00:00
ClassDB : : bind_method ( " _custom_features_changed " , & ProjectExportDialog : : _custom_features_changed ) ;
ClassDB : : bind_method ( " _tab_changed " , & ProjectExportDialog : : _tab_changed ) ;
2018-11-12 19:04:58 +00:00
ClassDB : : bind_method ( " set_export_path " , & ProjectExportDialog : : set_export_path ) ;
ClassDB : : bind_method ( " get_export_path " , & ProjectExportDialog : : get_export_path ) ;
2018-12-23 18:28:29 +00:00
ClassDB : : bind_method ( " get_current_preset " , & ProjectExportDialog : : get_current_preset ) ;
2020-04-24 07:45:14 +00:00
ClassDB : : bind_method ( " _force_update_current_preset_parameters " , & ProjectExportDialog : : _force_update_current_preset_parameters ) ;
2018-11-12 19:04:58 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " export_path " ) , " set_export_path " , " get_export_path " ) ;
2017-02-20 02:19:30 +00:00
}
2018-08-31 08:48:40 +00:00
2017-02-20 02:19:30 +00:00
ProjectExportDialog : : ProjectExportDialog ( ) {
2017-03-02 21:43:56 +00:00
set_title ( TTR ( " Export " ) ) ;
set_resizable ( true ) ;
2017-03-21 02:31:41 +00:00
VBoxContainer * main_vb = memnew ( VBoxContainer ) ;
add_child ( main_vb ) ;
2019-01-11 16:54:00 +00:00
HSplitContainer * hbox = memnew ( HSplitContainer ) ;
2017-03-21 02:31:41 +00:00
main_vb - > add_child ( hbox ) ;
hbox - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-02-20 02:19:30 +00:00
2020-01-08 12:29:49 +00:00
// Presets list.
2017-03-05 15:44:50 +00:00
VBoxContainer * preset_vb = memnew ( VBoxContainer ) ;
2017-02-20 02:19:30 +00:00
preset_vb - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
hbox - > add_child ( preset_vb ) ;
2017-03-05 15:44:50 +00:00
HBoxContainer * preset_hb = memnew ( HBoxContainer ) ;
2017-02-20 02:19:30 +00:00
preset_hb - > add_child ( memnew ( Label ( TTR ( " Presets " ) ) ) ) ;
preset_hb - > add_spacer ( ) ;
preset_vb - > add_child ( preset_hb ) ;
2017-03-05 15:44:50 +00:00
add_preset = memnew ( MenuButton ) ;
2018-04-22 17:36:01 +00:00
add_preset - > set_text ( TTR ( " Add... " ) ) ;
2017-03-05 15:44:50 +00:00
add_preset - > get_popup ( ) - > connect ( " index_pressed " , this , " _add_preset " ) ;
2017-02-20 02:19:30 +00:00
preset_hb - > add_child ( add_preset ) ;
2017-03-05 15:44:50 +00:00
MarginContainer * mc = memnew ( MarginContainer ) ;
2017-02-20 02:19:30 +00:00
preset_vb - > add_child ( mc ) ;
mc - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-03-05 15:44:50 +00:00
presets = memnew ( ItemList ) ;
2017-02-20 02:19:30 +00:00
presets - > set_drag_forwarding ( this ) ;
mc - > add_child ( presets ) ;
2017-03-05 15:44:50 +00:00
presets - > connect ( " item_selected " , this , " _edit_preset " ) ;
2018-10-28 18:13:38 +00:00
duplicate_preset = memnew ( ToolButton ) ;
preset_hb - > add_child ( duplicate_preset ) ;
duplicate_preset - > connect ( " pressed " , this , " _duplicate_preset " ) ;
2017-03-05 15:44:50 +00:00
delete_preset = memnew ( ToolButton ) ;
2017-02-20 02:19:30 +00:00
preset_hb - > add_child ( delete_preset ) ;
2017-03-05 15:44:50 +00:00
delete_preset - > connect ( " pressed " , this , " _delete_preset " ) ;
2017-02-20 02:19:30 +00:00
2020-01-08 12:29:49 +00:00
// Preset settings.
2017-03-05 15:44:50 +00:00
VBoxContainer * settings_vb = memnew ( VBoxContainer ) ;
2017-02-20 02:19:30 +00:00
settings_vb - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
hbox - > add_child ( settings_vb ) ;
name = memnew ( LineEdit ) ;
2017-03-05 15:44:50 +00:00
settings_vb - > add_margin_child ( TTR ( " Name: " ) , name ) ;
name - > connect ( " text_changed " , this , " _name_changed " ) ;
2017-02-20 02:19:30 +00:00
runnable = memnew ( CheckButton ) ;
runnable - > set_text ( TTR ( " Runnable " ) ) ;
2019-11-14 14:11:31 +00:00
runnable - > set_tooltip ( TTR ( " If checked, the preset will be available for use in one-click deploy. \n Only one preset per platform may be marked as runnable. " ) ) ;
2017-03-05 15:44:50 +00:00
runnable - > connect ( " pressed " , this , " _runnable_pressed " ) ;
2017-02-20 02:19:30 +00:00
settings_vb - > add_child ( runnable ) ;
2018-11-12 19:04:58 +00:00
export_path = memnew ( EditorPropertyPath ) ;
settings_vb - > add_child ( export_path ) ;
export_path - > set_label ( TTR ( " Export Path " ) ) ;
export_path - > set_object_and_property ( this , " export_path " ) ;
export_path - > set_save_mode ( ) ;
export_path - > connect ( " property_changed " , this , " _export_path_changed " ) ;
2018-11-06 01:01:34 +00:00
2020-01-08 12:29:49 +00:00
// Subsections.
2017-03-05 15:44:50 +00:00
sections = memnew ( TabContainer ) ;
2017-05-02 20:13:12 +00:00
sections - > set_tab_align ( TabContainer : : ALIGN_LEFT ) ;
2019-01-26 18:41:36 +00:00
sections - > set_use_hidden_tabs_for_min_size ( true ) ;
2017-02-20 02:19:30 +00:00
settings_vb - > add_child ( sections ) ;
sections - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2020-01-08 12:29:49 +00:00
// Main preset parameters.
2018-08-18 13:07:23 +00:00
parameters = memnew ( EditorInspector ) ;
2017-02-20 02:19:30 +00:00
sections - > add_child ( parameters ) ;
parameters - > set_name ( TTR ( " Options " ) ) ;
parameters - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-03-28 01:21:21 +00:00
parameters - > connect ( " property_edited " , this , " _update_parameters " ) ;
2020-04-24 07:45:14 +00:00
EditorExport : : get_singleton ( ) - > connect ( " export_presets_updated " , this , " _force_update_current_preset_parameters " ) ;
2017-02-20 02:19:30 +00:00
2020-01-08 12:29:49 +00:00
// Resources export parameters.
2017-03-05 15:44:50 +00:00
VBoxContainer * resources_vb = memnew ( VBoxContainer ) ;
2017-02-20 02:19:30 +00:00
sections - > add_child ( resources_vb ) ;
resources_vb - > set_name ( TTR ( " Resources " ) ) ;
2017-03-05 15:44:50 +00:00
export_filter = memnew ( OptionButton ) ;
2017-02-20 02:19:30 +00:00
export_filter - > add_item ( TTR ( " Export all resources in the project " ) ) ;
export_filter - > add_item ( TTR ( " Export selected scenes (and dependencies) " ) ) ;
export_filter - > add_item ( TTR ( " Export selected resources (and dependencies) " ) ) ;
2017-03-05 15:44:50 +00:00
resources_vb - > add_margin_child ( TTR ( " Export Mode: " ) , export_filter ) ;
export_filter - > connect ( " item_selected " , this , " _export_type_changed " ) ;
2017-02-20 02:19:30 +00:00
2017-03-05 15:44:50 +00:00
include_label = memnew ( Label ) ;
2017-02-20 02:19:30 +00:00
include_label - > set_text ( TTR ( " Resources to export: " ) ) ;
resources_vb - > add_child ( include_label ) ;
2017-03-05 15:44:50 +00:00
include_margin = memnew ( MarginContainer ) ;
2017-02-20 02:19:30 +00:00
include_margin - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
resources_vb - > add_child ( include_margin ) ;
include_files = memnew ( Tree ) ;
include_margin - > add_child ( include_files ) ;
2017-03-05 15:44:50 +00:00
include_files - > connect ( " item_edited " , this , " _tree_changed " ) ;
2017-02-20 02:19:30 +00:00
2017-03-05 15:44:50 +00:00
include_filters = memnew ( LineEdit ) ;
2019-10-05 14:45:12 +00:00
resources_vb - > add_margin_child (
TTR ( " Filters to export non-resource files/folders \n (comma-separated, e.g: *.json, *.txt, docs/*) " ) ,
include_filters ) ;
2017-03-05 15:44:50 +00:00
include_filters - > connect ( " text_changed " , this , " _filter_changed " ) ;
2017-02-20 02:19:30 +00:00
2017-03-05 15:44:50 +00:00
exclude_filters = memnew ( LineEdit ) ;
2019-10-05 14:45:12 +00:00
resources_vb - > add_margin_child (
TTR ( " Filters to exclude files/folders from project \n (comma-separated, e.g: *.json, *.txt, docs/*) " ) ,
exclude_filters ) ;
2017-03-05 15:44:50 +00:00
exclude_filters - > connect ( " text_changed " , this , " _filter_changed " ) ;
2017-02-20 02:19:30 +00:00
2020-01-08 12:29:49 +00:00
// Feature tags.
2017-07-19 20:00:46 +00:00
VBoxContainer * feature_vb = memnew ( VBoxContainer ) ;
feature_vb - > set_name ( TTR ( " Features " ) ) ;
custom_features = memnew ( LineEdit ) ;
custom_features - > connect ( " text_changed " , this , " _custom_features_changed " ) ;
feature_vb - > add_margin_child ( TTR ( " Custom (comma-separated): " ) , custom_features ) ;
custom_feature_display = memnew ( RichTextLabel ) ;
2020-04-05 03:08:53 +00:00
custom_feature_display - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
feature_vb - > add_margin_child ( TTR ( " Feature List: " ) , custom_feature_display , true ) ;
2017-07-19 20:00:46 +00:00
sections - > add_child ( feature_vb ) ;
2020-01-08 12:29:49 +00:00
// Script export parameters.
2018-12-23 18:28:29 +00:00
updating_script_key = false ;
VBoxContainer * script_vb = memnew ( VBoxContainer ) ;
script_vb - > set_name ( TTR ( " Script " ) ) ;
script_mode = memnew ( OptionButton ) ;
script_vb - > add_margin_child ( TTR ( " Script Export Mode: " ) , script_mode ) ;
script_mode - > add_item ( TTR ( " Text " ) , ( int ) EditorExportPreset : : MODE_SCRIPT_TEXT ) ;
script_mode - > add_item ( TTR ( " Compiled " ) , ( int ) EditorExportPreset : : MODE_SCRIPT_COMPILED ) ;
script_mode - > add_item ( TTR ( " Encrypted (Provide Key Below) " ) , ( int ) EditorExportPreset : : MODE_SCRIPT_ENCRYPTED ) ;
script_mode - > connect ( " item_selected " , this , " _script_export_mode_changed " ) ;
script_key = memnew ( LineEdit ) ;
script_key - > connect ( " text_changed " , this , " _script_encryption_key_changed " ) ;
script_key_error = memnew ( Label ) ;
script_key_error - > set_text ( " - " + TTR ( " Invalid Encryption Key (must be 64 characters long) " ) ) ;
script_key_error - > add_color_override ( " font_color " , EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_color ( " error_color " , " Editor " ) ) ;
script_vb - > add_margin_child ( TTR ( " Script Encryption Key (256-bits as hex): " ) , script_key ) ;
script_vb - > add_child ( script_key_error ) ;
sections - > add_child ( script_vb ) ;
2017-07-19 20:00:46 +00:00
sections - > connect ( " tab_changed " , this , " _tab_changed " ) ;
2020-01-08 12:29:49 +00:00
// Disable by default.
2017-02-20 02:19:30 +00:00
name - > set_editable ( false ) ;
2018-11-12 19:04:58 +00:00
export_path - > hide ( ) ;
2017-02-20 02:19:30 +00:00
runnable - > set_disabled ( true ) ;
2018-10-28 18:13:38 +00:00
duplicate_preset - > set_disabled ( true ) ;
2017-02-20 02:19:30 +00:00
delete_preset - > set_disabled ( true ) ;
2018-12-23 18:28:29 +00:00
script_key_error - > hide ( ) ;
2017-02-20 02:19:30 +00:00
sections - > hide ( ) ;
parameters - > edit ( NULL ) ;
2020-01-08 12:29:49 +00:00
// Deletion dialog.
2017-03-05 15:44:50 +00:00
delete_confirm = memnew ( ConfirmationDialog ) ;
2017-02-20 02:19:30 +00:00
add_child ( delete_confirm ) ;
delete_confirm - > get_ok ( ) - > set_text ( TTR ( " Delete " ) ) ;
2017-03-05 15:44:50 +00:00
delete_confirm - > connect ( " confirmed " , this , " _delete_preset_confirm " ) ;
2014-02-10 01:10:30 +00:00
2020-01-08 12:29:49 +00:00
// Export buttons, dialogs and errors.
2017-03-05 15:44:50 +00:00
updating = false ;
2014-02-10 01:10:30 +00:00
2017-10-11 17:15:44 +00:00
get_cancel ( ) - > set_text ( TTR ( " Close " ) ) ;
2017-08-23 20:25:14 +00:00
get_ok ( ) - > set_text ( TTR ( " Export PCK/Zip " ) ) ;
export_button = add_button ( TTR ( " Export Project " ) , ! OS : : get_singleton ( ) - > get_swap_ok_cancel ( ) , " export " ) ;
2018-08-31 08:48:40 +00:00
export_button - > connect ( " pressed " , this , " _export_project " ) ;
// Disable initially before we select a valid preset
export_button - > set_disabled ( true ) ;
2019-10-16 09:54:04 +00:00
get_ok ( ) - > set_disabled ( true ) ;
2017-02-21 03:05:15 +00:00
2018-11-03 15:56:31 +00:00
export_all_dialog = memnew ( ConfirmationDialog ) ;
add_child ( export_all_dialog ) ;
export_all_dialog - > set_title ( " Export All " ) ;
export_all_dialog - > set_text ( TTR ( " Export mode? " ) ) ;
export_all_dialog - > get_ok ( ) - > hide ( ) ;
export_all_dialog - > add_button ( TTR ( " Debug " ) , true , " debug " ) ;
export_all_dialog - > add_button ( TTR ( " Release " ) , true , " release " ) ;
export_all_dialog - > connect ( " custom_action " , this , " _export_all_dialog_action " ) ;
export_all_button = add_button ( TTR ( " Export All " ) , ! OS : : get_singleton ( ) - > get_swap_ok_cancel ( ) , " export " ) ;
export_all_button - > connect ( " pressed " , this , " _export_all_dialog " ) ;
export_all_button - > set_disabled ( true ) ;
2019-04-24 18:52:15 +00:00
export_pck_zip = memnew ( EditorFileDialog ) ;
2019-12-16 05:18:44 +00:00
export_pck_zip - > add_filter ( " *.zip ; " + TTR ( " ZIP File " ) ) ;
export_pck_zip - > add_filter ( " *.pck ; " + TTR ( " Godot Game Pack " ) ) ;
2019-04-24 18:52:15 +00:00
export_pck_zip - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
export_pck_zip - > set_mode ( EditorFileDialog : : MODE_SAVE_FILE ) ;
2017-02-21 03:05:15 +00:00
add_child ( export_pck_zip ) ;
2017-03-05 15:44:50 +00:00
export_pck_zip - > connect ( " file_selected " , this , " _export_pck_zip_selected " ) ;
2017-02-21 03:05:15 +00:00
2017-03-21 02:31:41 +00:00
export_error = memnew ( Label ) ;
main_vb - > add_child ( export_error ) ;
export_error - > hide ( ) ;
2018-08-17 09:27:26 +00:00
export_error - > add_color_override ( " font_color " , EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_color ( " error_color " , " Editor " ) ) ;
2017-03-21 02:31:41 +00:00
export_templates_error = memnew ( HBoxContainer ) ;
main_vb - > add_child ( export_templates_error ) ;
export_templates_error - > hide ( ) ;
Label * export_error2 = memnew ( Label ) ;
export_templates_error - > add_child ( export_error2 ) ;
2018-08-17 09:27:26 +00:00
export_error2 - > add_color_override ( " font_color " , EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_color ( " error_color " , " Editor " ) ) ;
2017-03-21 02:31:41 +00:00
export_error2 - > set_text ( " - " + TTR ( " Export templates for this platform are missing: " ) + " " ) ;
2017-10-12 22:38:42 +00:00
error_dialog = memnew ( AcceptDialog ) ;
error_dialog - > set_title ( " Error " ) ;
error_dialog - > set_text ( TTR ( " Export templates for this platform are missing/corrupted: " ) + " " ) ;
main_vb - > add_child ( error_dialog ) ;
error_dialog - > hide ( ) ;
2017-03-21 02:31:41 +00:00
LinkButton * download_templates = memnew ( LinkButton ) ;
download_templates - > set_text ( TTR ( " Manage Export Templates " ) ) ;
2018-08-17 09:27:26 +00:00
download_templates - > set_v_size_flags ( SIZE_SHRINK_CENTER ) ;
2017-03-21 02:31:41 +00:00
export_templates_error - > add_child ( download_templates ) ;
download_templates - > connect ( " pressed " , this , " _open_export_template_manager " ) ;
2019-04-24 18:52:15 +00:00
export_project = memnew ( EditorFileDialog ) ;
export_project - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
2017-03-21 22:34:26 +00:00
add_child ( export_project ) ;
export_project - > connect ( " file_selected " , this , " _export_project_to_path " ) ;
2018-08-31 08:48:40 +00:00
export_project - > get_line_edit ( ) - > connect ( " text_changed " , this , " _validate_export_path " ) ;
2017-03-21 22:34:26 +00:00
2019-01-20 22:50:46 +00:00
export_debug = memnew ( CheckBox ) ;
2017-03-21 22:34:26 +00:00
export_debug - > set_text ( TTR ( " Export With Debug " ) ) ;
export_debug - > set_pressed ( true ) ;
export_project - > get_vbox ( ) - > add_child ( export_debug ) ;
2019-01-20 22:50:46 +00:00
export_pck_zip_debug = memnew ( CheckBox ) ;
2018-04-26 21:08:19 +00:00
export_pck_zip_debug - > set_text ( TTR ( " Export With Debug " ) ) ;
export_pck_zip_debug - > set_pressed ( true ) ;
export_pck_zip - > get_vbox ( ) - > add_child ( export_pck_zip_debug ) ;
2017-02-21 03:05:15 +00:00
set_hide_on_ok ( false ) ;
2017-02-20 02:19:30 +00:00
editor_icons = " EditorIcons " ;
2017-10-28 08:57:29 +00:00
2018-08-31 08:48:40 +00:00
default_filename = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " export_options " , " default_filename " , " " ) ;
// If no default set, use project name
2018-04-17 21:10:30 +00:00
if ( default_filename = = " " ) {
2018-08-31 08:48:40 +00:00
// If no project name defined, use a sane default
2018-04-17 21:10:30 +00:00
default_filename = ProjectSettings : : get_singleton ( ) - > get ( " application/config/name " ) ;
2018-08-31 08:48:40 +00:00
if ( default_filename = = " " ) {
default_filename = " UnnamedProject " ;
}
2018-04-17 21:10:30 +00:00
}
2018-11-03 15:56:31 +00:00
_update_export_all ( ) ;
2014-02-10 01:10:30 +00:00
}
ProjectExportDialog : : ~ ProjectExportDialog ( ) {
}