Path: blob/master/editor/version_control/version_control_editor_plugin.cpp
20983 views
/**************************************************************************/1/* version_control_editor_plugin.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "version_control_editor_plugin.h"3132#include "core/config/project_settings.h"33#include "core/os/keyboard.h"34#include "core/os/time.h"35#include "editor/docks/editor_dock.h"36#include "editor/docks/editor_dock_manager.h"37#include "editor/docks/filesystem_dock.h"38#include "editor/editor_interface.h"39#include "editor/editor_node.h"40#include "editor/editor_string_names.h"41#include "editor/file_system/editor_file_system.h"42#include "editor/gui/editor_bottom_panel.h"43#include "editor/gui/editor_file_dialog.h"44#include "editor/script/script_editor_plugin.h"45#include "editor/settings/editor_command_palette.h"46#include "editor/settings/editor_settings.h"47#include "editor/themes/editor_scale.h"48#include "scene/gui/flow_container.h"49#include "scene/gui/line_edit.h"50#include "scene/gui/separator.h"5152#define CHECK_PLUGIN_INITIALIZED() \53ERR_FAIL_NULL_MSG(EditorVCSInterface::get_singleton(), "No VCS plugin is initialized. Select a Version Control Plugin from Project menu.");5455VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr;5657void VersionControlEditorPlugin::_bind_methods() {58// No binds required so far.59}6061void VersionControlEditorPlugin::_create_vcs_metadata_files() {62String dir = "res://";63EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(metadata_selection->get_selected_id()), dir);64}6566void VersionControlEditorPlugin::_notification(int p_what) {67if (p_what == NOTIFICATION_READY) {68String installed_plugin = GLOBAL_GET("editor/version_control/plugin_name");69bool has_autoload_enable = GLOBAL_GET("editor/version_control/autoload_on_startup");7071if (installed_plugin != "" && has_autoload_enable) {72if (_load_plugin(installed_plugin)) {73_set_credentials();74}75}76}77}7879void VersionControlEditorPlugin::_update_theme() {80change_type_to_color[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("success_color"), EditorStringName(Editor));81change_type_to_color[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor));82change_type_to_color[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor));83change_type_to_color[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor));84change_type_to_color[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_editor_theme()->get_color(SceneStringName(font_color), EditorStringName(Editor));85change_type_to_color[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor));8687change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusSuccess"), EditorStringName(EditorIcons));88change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));89change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));90change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));91change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusError"), EditorStringName(EditorIcons));92change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));9394select_public_path_button->set_button_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon("Folder"));95select_private_path_button->set_button_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon("Folder"));96refresh_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));97discard_all_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Close"), EditorStringName(EditorIcons)));98stage_all_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));99unstage_all_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));100fetch_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));101pull_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));102push_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));103extra_options->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GuiTabMenuHl"), EditorStringName(EditorIcons)));104105if (EditorVCSInterface::get_singleton()) {106_refresh_stage_area();107}108}109110void VersionControlEditorPlugin::_populate_available_vcs_names() {111set_up_choice->clear();112for (const StringName &available_plugin : available_plugins) {113set_up_choice->add_item(available_plugin);114}115}116117VersionControlEditorPlugin *VersionControlEditorPlugin::get_singleton() {118return singleton ? singleton : memnew(VersionControlEditorPlugin);119}120121void VersionControlEditorPlugin::popup_vcs_metadata_dialog() {122metadata_dialog->popup_centered();123}124125void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) {126fetch_available_vcs_plugin_names();127if (!available_plugins.is_empty()) {128Size2 popup_size = Size2(400, 100);129Size2 window_size = p_gui_base->get_viewport_rect().size;130popup_size = popup_size.min(window_size * 0.5);131132_populate_available_vcs_names();133134set_up_dialog->popup_centered_clamped(popup_size * EDSCALE);135} else {136// TODO: Give info to user on how to fix this error.137EditorNode::get_singleton()->show_warning(TTR("No VCS plugins are available in the project. Install a VCS plugin to use VCS integration features."), TTR("Error"));138}139}140141void VersionControlEditorPlugin::_initialize_vcs() {142ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active.");143144const int id = set_up_choice->get_selected_id();145String selected_plugin = set_up_choice->get_item_text(id);146147if (_load_plugin(selected_plugin)) {148ProjectSettings::get_singleton()->set("editor/version_control/autoload_on_startup", true);149ProjectSettings::get_singleton()->set("editor/version_control/plugin_name", selected_plugin);150ProjectSettings::get_singleton()->save();151}152}153154void VersionControlEditorPlugin::_set_vcs_ui_state(bool p_enabled) {155set_up_dialog->get_ok_button()->set_disabled(!p_enabled);156set_up_choice->set_disabled(p_enabled);157toggle_vcs_choice->set_pressed_no_signal(p_enabled);158}159160void VersionControlEditorPlugin::_set_credentials() {161CHECK_PLUGIN_INITIALIZED();162163String username = set_up_username->get_text();164String password = set_up_password->get_text();165String ssh_public_key = set_up_ssh_public_key_path->get_text();166String ssh_private_key = set_up_ssh_private_key_path->get_text();167String ssh_passphrase = set_up_ssh_passphrase->get_text();168169EditorVCSInterface::get_singleton()->set_credentials(170username,171password,172ssh_public_key,173ssh_private_key,174ssh_passphrase);175176EditorSettings::get_singleton()->set_setting("version_control/username", username);177EditorSettings::get_singleton()->set_setting("version_control/ssh_public_key_path", ssh_public_key);178EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key);179}180181bool VersionControlEditorPlugin::_load_plugin(const String &p_name) {182Object *extension_instance = ClassDB::instantiate(p_name);183ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction.");184185EditorVCSInterface *vcs_plugin = Object::cast_to<EditorVCSInterface>(extension_instance);186ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat("Could not cast VCS extension instance to %s.", EditorVCSInterface::get_class_static()));187188String res_dir = OS::get_singleton()->get_resource_dir();189190ERR_FAIL_COND_V_MSG(!vcs_plugin->initialize(res_dir), false, "Could not initialize " + p_name);191192EditorVCSInterface::set_singleton(vcs_plugin);193194register_editor();195EditorFileSystem::get_singleton()->connect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));196197_refresh_stage_area();198_refresh_commit_list();199_refresh_branch_list();200_refresh_remote_list();201202return true;203}204205void VersionControlEditorPlugin::_update_set_up_warning(const String &p_new_text) {206bool empty_settings = set_up_username->get_text().strip_edges().is_empty() &&207set_up_password->get_text().is_empty() &&208set_up_ssh_public_key_path->get_text().strip_edges().is_empty() &&209set_up_ssh_private_key_path->get_text().strip_edges().is_empty() &&210set_up_ssh_passphrase->get_text().is_empty();211212if (empty_settings) {213set_up_warning_text->add_theme_color_override(SceneStringName(font_color), EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor)));214set_up_warning_text->set_text(TTR("Remote settings are empty. VCS features that use the network may not work."));215} else {216set_up_warning_text->set_text("");217}218}219220void VersionControlEditorPlugin::_refresh_branch_list() {221CHECK_PLUGIN_INITIALIZED();222223List<String> branch_list = EditorVCSInterface::get_singleton()->get_branch_list();224branch_select->clear();225226branch_select->set_disabled(branch_list.is_empty());227228String current_branch = EditorVCSInterface::get_singleton()->get_current_branch_name();229230int i = 0;231for (List<String>::ConstIterator itr = branch_list.begin(); itr != branch_list.end(); ++itr, ++i) {232branch_select->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("VcsBranches"), EditorStringName(EditorIcons)), *itr, i);233234if (*itr == current_branch) {235branch_select->select(i);236}237}238}239240String VersionControlEditorPlugin::_get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const {241return vformat(242"%s %s",243Time::get_singleton()->get_datetime_string_from_unix_time(p_unix_timestamp + p_offset_minutes * 60, true),244Time::get_singleton()->get_offset_string_from_offset_minutes(p_offset_minutes));245}246247void VersionControlEditorPlugin::_set_commit_list_size(int p_index) {248_refresh_commit_list();249}250251void VersionControlEditorPlugin::_refresh_commit_list() {252CHECK_PLUGIN_INITIALIZED();253254commit_list->get_root()->clear_children();255256List<EditorVCSInterface::Commit> commit_info_list = EditorVCSInterface::get_singleton()->get_previous_commits(commit_list_size_button->get_selected_metadata());257258for (const EditorVCSInterface::Commit &commit : commit_info_list) {259TreeItem *item = commit_list->create_item();260261// Only display the first line of a commit message262int line_ending = commit.msg.find_char('\n');263String commit_display_msg = commit.msg.substr(0, line_ending);264String commit_date_string = _get_date_string_from(commit.unix_timestamp, commit.offset_minutes);265266Dictionary meta_data;267meta_data[SNAME("commit_id")] = commit.id;268meta_data[SNAME("commit_title")] = commit_display_msg;269meta_data[SNAME("commit_subtitle")] = commit.msg.substr(line_ending).strip_edges();270meta_data[SNAME("commit_unix_timestamp")] = commit.unix_timestamp;271meta_data[SNAME("commit_author")] = commit.author;272meta_data[SNAME("commit_date_string")] = commit_date_string;273274item->set_text(0, commit_display_msg);275item->set_text(1, commit.author.strip_edges());276item->set_metadata(0, meta_data);277}278}279280void VersionControlEditorPlugin::_refresh_remote_list() {281CHECK_PLUGIN_INITIALIZED();282283List<String> remotes = EditorVCSInterface::get_singleton()->get_remotes();284285String current_remote = remote_select->get_selected_metadata();286remote_select->clear();287288remote_select->set_disabled(remotes.is_empty());289290int i = 0;291for (List<String>::ConstIterator itr = remotes.begin(); itr != remotes.end(); ++itr, ++i) {292remote_select->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ArrowUp"), EditorStringName(EditorIcons)), *itr, i);293remote_select->set_item_metadata(i, *itr);294295if (*itr == current_remote) {296remote_select->select(i);297}298}299}300301void VersionControlEditorPlugin::_commit() {302CHECK_PLUGIN_INITIALIZED();303304String msg = commit_message->get_text().strip_edges();305306ERR_FAIL_COND_MSG(msg.is_empty(), "No commit message was provided.");307308EditorVCSInterface::get_singleton()->commit(msg);309310if (version_control_dock->get_current_layout() == EditorDock::DOCK_LAYOUT_HORIZONTAL) {311version_control_dock->hide();312}313314commit_message->release_focus();315commit_button->release_focus();316commit_message->set_text("");317318_refresh_stage_area();319_refresh_commit_list();320_refresh_branch_list();321_clear_diff();322}323324void VersionControlEditorPlugin::_branch_item_selected(int p_index) {325CHECK_PLUGIN_INITIALIZED();326327String branch_name = branch_select->get_item_text(p_index);328EditorVCSInterface::get_singleton()->checkout_branch(branch_name);329330EditorFileSystem::get_singleton()->scan_changes();331ScriptEditor::get_singleton()->reload_scripts();332333_refresh_branch_list();334_refresh_commit_list();335_refresh_stage_area();336_clear_diff();337338_update_opened_tabs();339}340341void VersionControlEditorPlugin::_remote_selected(int p_index) {342_refresh_remote_list();343}344345void VersionControlEditorPlugin::_ssh_public_key_selected(const String &p_path) {346set_up_ssh_public_key_path->set_text(p_path);347}348349void VersionControlEditorPlugin::_ssh_private_key_selected(const String &p_path) {350set_up_ssh_private_key_path->set_text(p_path);351}352353void VersionControlEditorPlugin::_popup_file_dialog(const Variant &p_file_dialog_variant) {354FileDialog *file_dialog = Object::cast_to<FileDialog>(p_file_dialog_variant);355ERR_FAIL_NULL(file_dialog);356357file_dialog->popup_centered_ratio();358}359360void VersionControlEditorPlugin::_create_branch() {361CHECK_PLUGIN_INITIALIZED();362363String new_branch_name = branch_create_name_input->get_text().strip_edges();364365EditorVCSInterface::get_singleton()->create_branch(new_branch_name);366EditorVCSInterface::get_singleton()->checkout_branch(new_branch_name);367368branch_create_name_input->clear();369_refresh_branch_list();370}371372void VersionControlEditorPlugin::_create_remote() {373CHECK_PLUGIN_INITIALIZED();374375String new_remote_name = remote_create_name_input->get_text().strip_edges();376String new_remote_url = remote_create_url_input->get_text().strip_edges();377378EditorVCSInterface::get_singleton()->create_remote(new_remote_name, new_remote_url);379380remote_create_name_input->clear();381remote_create_url_input->clear();382_refresh_remote_list();383}384385void VersionControlEditorPlugin::_update_branch_create_button(const String &p_new_text) {386branch_create_ok->set_disabled(p_new_text.strip_edges().is_empty());387}388389void VersionControlEditorPlugin::_update_remote_create_button(const String &p_new_text) {390remote_create_ok->set_disabled(p_new_text.strip_edges().is_empty());391}392393int VersionControlEditorPlugin::_get_item_count(Tree *p_tree) {394if (!p_tree->get_root()) {395return 0;396}397return p_tree->get_root()->get_children().size();398}399400void VersionControlEditorPlugin::_refresh_stage_area() {401CHECK_PLUGIN_INITIALIZED();402403staged_files->get_root()->clear_children();404unstaged_files->get_root()->clear_children();405406List<EditorVCSInterface::StatusFile> status_files = EditorVCSInterface::get_singleton()->get_modified_files_data();407for (const EditorVCSInterface::StatusFile &sf : status_files) {408if (sf.area == EditorVCSInterface::TREE_AREA_STAGED) {409_add_new_item(staged_files, sf.file_path, sf.change_type);410} else if (sf.area == EditorVCSInterface::TREE_AREA_UNSTAGED) {411_add_new_item(unstaged_files, sf.file_path, sf.change_type);412}413}414415staged_files->queue_redraw();416unstaged_files->queue_redraw();417418int total_changes = status_files.size();419String commit_tab_title = TTR("Commit") + (total_changes > 0 ? " (" + itos(total_changes) + ")" : "");420version_commit_dock->set_name(commit_tab_title);421}422423void VersionControlEditorPlugin::_discard_file(const String &p_file_path, EditorVCSInterface::ChangeType p_change) {424CHECK_PLUGIN_INITIALIZED();425426if (p_change == EditorVCSInterface::CHANGE_TYPE_NEW) {427Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);428dir->remove(p_file_path);429} else {430CHECK_PLUGIN_INITIALIZED();431EditorVCSInterface::get_singleton()->discard_file(p_file_path);432}433// FIXIT: The project.godot file shows weird behavior434EditorFileSystem::get_singleton()->update_file(p_file_path);435}436437void VersionControlEditorPlugin::_confirm_discard_all() {438discard_all_confirm->popup_centered();439}440441void VersionControlEditorPlugin::_discard_all() {442TreeItem *file_entry = unstaged_files->get_root()->get_first_child();443while (file_entry) {444String file_path = file_entry->get_meta(SNAME("file_path"));445EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)file_entry->get_meta(SNAME("change_type"));446_discard_file(file_path, change);447448file_entry = file_entry->get_next();449}450_refresh_stage_area();451}452453void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, const String &p_file_path, EditorVCSInterface::ChangeType p_change) {454String change_text = p_file_path + " (" + change_type_to_strings[p_change] + ")";455456TreeItem *new_item = p_tree->create_item();457new_item->set_text(0, change_text);458new_item->set_icon(0, change_type_to_icon[p_change]);459new_item->set_meta(SNAME("file_path"), p_file_path);460new_item->set_meta(SNAME("change_type"), p_change);461new_item->set_custom_color(0, change_type_to_color[p_change]);462463new_item->add_button(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("File"), EditorStringName(EditorIcons)), BUTTON_TYPE_OPEN, false, TTR("Open in editor"));464if (p_tree == unstaged_files) {465new_item->add_button(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Close"), EditorStringName(EditorIcons)), BUTTON_TYPE_DISCARD, false, TTR("Discard changes"));466}467}468469void VersionControlEditorPlugin::_fetch() {470CHECK_PLUGIN_INITIALIZED();471472EditorVCSInterface::get_singleton()->fetch(remote_select->get_selected_metadata());473_refresh_branch_list();474}475476void VersionControlEditorPlugin::_pull() {477CHECK_PLUGIN_INITIALIZED();478479EditorVCSInterface::get_singleton()->pull(remote_select->get_selected_metadata());480_refresh_stage_area();481_refresh_branch_list();482_refresh_commit_list();483_clear_diff();484_update_opened_tabs();485}486487void VersionControlEditorPlugin::_push() {488CHECK_PLUGIN_INITIALIZED();489490EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), false);491}492493void VersionControlEditorPlugin::_force_push() {494CHECK_PLUGIN_INITIALIZED();495496EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), true);497}498499void VersionControlEditorPlugin::_update_opened_tabs() {500Vector<EditorData::EditedScene> open_scenes = EditorNode::get_editor_data().get_edited_scenes();501for (int i = 0; i < open_scenes.size(); i++) {502if (open_scenes[i].root == nullptr) {503continue;504}505EditorNode::get_singleton()->reload_scene(open_scenes[i].path);506}507}508509void VersionControlEditorPlugin::_move_all(Object *p_tree) {510Tree *tree = Object::cast_to<Tree>(p_tree);511512TreeItem *file_entry = tree->get_root()->get_first_child();513while (file_entry) {514_move_item(tree, file_entry);515516file_entry = file_entry->get_next();517}518_refresh_stage_area();519}520521void VersionControlEditorPlugin::_load_diff(Object *p_tree) {522CHECK_PLUGIN_INITIALIZED();523524version_control_dock->make_visible();525526Tree *tree = Object::cast_to<Tree>(p_tree);527if (tree == staged_files) {528show_commit_diff_header = false;529String file_path = tree->get_selected()->get_meta(SNAME("file_path"));530diff_title->set_text(TTR("Staged Changes"));531diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_STAGED);532} else if (tree == unstaged_files) {533show_commit_diff_header = false;534String file_path = tree->get_selected()->get_meta(SNAME("file_path"));535diff_title->set_text(TTR("Unstaged Changes"));536diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_UNSTAGED);537} else if (tree == commit_list) {538show_commit_diff_header = true;539Dictionary meta_data = tree->get_selected()->get_metadata(0);540String commit_id = meta_data[SNAME("commit_id")];541String commit_title = meta_data[SNAME("commit_title")];542diff_title->set_text(commit_title);543diff_content = EditorVCSInterface::get_singleton()->get_diff(commit_id, EditorVCSInterface::TREE_AREA_COMMIT);544}545_display_diff(0);546}547548void VersionControlEditorPlugin::_clear_diff() {549diff->clear();550diff_content.clear();551diff_title->set_text("");552}553554void VersionControlEditorPlugin::_item_activated(Object *p_tree) {555Tree *tree = Object::cast_to<Tree>(p_tree);556557_move_item(tree, tree->get_selected());558_refresh_stage_area();559}560561void VersionControlEditorPlugin::_move_item(Tree *p_tree, TreeItem *p_item) {562CHECK_PLUGIN_INITIALIZED();563564if (p_tree == staged_files) {565EditorVCSInterface::get_singleton()->unstage_file(p_item->get_meta(SNAME("file_path")));566} else {567EditorVCSInterface::get_singleton()->stage_file(p_item->get_meta(SNAME("file_path")));568}569}570571void VersionControlEditorPlugin::_cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index) {572TreeItem *item = Object::cast_to<TreeItem>(p_item);573String file_path = item->get_meta(SNAME("file_path"));574EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)item->get_meta(SNAME("change_type"));575576if (p_id == BUTTON_TYPE_OPEN && change != EditorVCSInterface::CHANGE_TYPE_DELETED) {577Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);578if (!dir->file_exists(file_path)) {579return;580}581582file_path = "res://" + file_path;583if (ResourceLoader::get_resource_type(file_path) == "PackedScene") {584EditorNode::get_singleton()->load_scene(file_path);585} else if (file_path.ends_with(".gd")) {586EditorNode::get_singleton()->load_resource(file_path);587ScriptEditor::get_singleton()->reload_scripts();588} else {589FileSystemDock::get_singleton()->navigate_to_path(file_path);590}591592} else if (p_id == BUTTON_TYPE_DISCARD) {593_discard_file(file_path, change);594_refresh_stage_area();595}596}597598void VersionControlEditorPlugin::_display_diff(int p_idx) {599DiffViewType diff_view = (DiffViewType)diff_view_type_select->get_selected();600601diff->clear();602603if (show_commit_diff_header) {604Dictionary meta_data = commit_list->get_selected()->get_metadata(0);605String commit_id = meta_data[SNAME("commit_id")];606String commit_subtitle = meta_data[SNAME("commit_subtitle")];607String commit_date = meta_data[SNAME("commit_date")];608String commit_author = meta_data[SNAME("commit_author")];609String commit_date_string = meta_data[SNAME("commit_date_string")];610611diff->push_font(EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("doc_bold"), EditorStringName(EditorFonts)));612diff->push_color(EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("accent_color"), EditorStringName(Editor)));613diff->add_text(TTR("Commit:") + " " + commit_id);614diff->add_newline();615diff->add_text(TTR("Author:") + " " + commit_author);616diff->add_newline();617diff->add_text(TTR("Date:") + " " + commit_date_string);618diff->add_newline();619if (!commit_subtitle.is_empty()) {620diff->add_text(TTR("Subtitle:") + " " + commit_subtitle);621diff->add_newline();622}623diff->add_newline();624diff->pop();625diff->pop();626}627628for (const EditorVCSInterface::DiffFile &diff_file : diff_content) {629diff->push_font(EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("doc_bold"), EditorStringName(EditorFonts)));630diff->push_color(EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("accent_color"), EditorStringName(Editor)));631diff->add_text(TTR("File:") + " " + diff_file.new_file);632diff->pop();633diff->pop();634635diff->push_font(EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("status_source"), EditorStringName(EditorFonts)));636for (EditorVCSInterface::DiffHunk hunk : diff_file.diff_hunks) {637String old_start = String::num_int64(hunk.old_start);638String new_start = String::num_int64(hunk.new_start);639String old_lines = String::num_int64(hunk.old_lines);640String new_lines = String::num_int64(hunk.new_lines);641642diff->add_newline();643diff->append_text("[center]@@ " + old_start + "," + old_lines + " " + new_start + "," + new_lines + " @@[/center]");644diff->add_newline();645646switch (diff_view) {647case DIFF_VIEW_TYPE_SPLIT:648_display_diff_split_view(hunk.diff_lines);649break;650case DIFF_VIEW_TYPE_UNIFIED:651_display_diff_unified_view(hunk.diff_lines);652break;653}654diff->add_newline();655}656diff->pop();657658diff->add_newline();659}660}661662void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content) {663LocalVector<EditorVCSInterface::DiffLine> parsed_diff;664665for (EditorVCSInterface::DiffLine diff_line : p_diff_content) {666String line = diff_line.content.strip_edges(false, true);667668if (diff_line.new_line_no >= 0 && diff_line.old_line_no >= 0) {669diff_line.new_text = line;670diff_line.old_text = line;671parsed_diff.push_back(diff_line);672} else if (diff_line.new_line_no == -1) {673diff_line.new_text = "";674diff_line.old_text = line;675parsed_diff.push_back(diff_line);676} else if (diff_line.old_line_no == -1) {677int32_t j = parsed_diff.size() - 1;678while (j >= 0 && parsed_diff[j].new_line_no == -1) {679j--;680}681682if (j == (int32_t)parsed_diff.size() - 1) {683// no lines are modified684diff_line.new_text = line;685diff_line.old_text = "";686parsed_diff.push_back(diff_line);687} else {688// lines are modified689EditorVCSInterface::DiffLine modified_line = parsed_diff[j + 1];690modified_line.new_text = line;691modified_line.new_line_no = diff_line.new_line_no;692parsed_diff[j + 1] = modified_line;693}694}695}696697diff->push_table(6);698/*699[cell]Old Line No[/cell]700[cell]prefix[/cell]701[cell]Old Code[/cell]702703[cell]New Line No[/cell]704[cell]prefix[/cell]705[cell]New Line[/cell]706*/707708diff->set_table_column_expand(2, true);709diff->set_table_column_expand(5, true);710711for (uint32_t i = 0; i < parsed_diff.size(); i++) {712EditorVCSInterface::DiffLine diff_line = parsed_diff[i];713714bool has_change = diff_line.status != " ";715static const Color red = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor));716static const Color green = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("success_color"), EditorStringName(Editor));717static const Color white = EditorNode::get_singleton()->get_editor_theme()->get_color(SceneStringName(font_color), SNAME("Label")) * Color(1, 1, 1, 0.6);718719if (diff_line.old_line_no >= 0) {720diff->push_cell();721diff->push_color(has_change ? red : white);722diff->add_text(String::num_int64(diff_line.old_line_no));723diff->pop();724diff->pop();725726diff->push_cell();727diff->push_color(has_change ? red : white);728diff->add_text(has_change ? "-|" : " |");729diff->pop();730diff->pop();731732diff->push_cell();733diff->push_color(has_change ? red : white);734diff->add_text(diff_line.old_text);735diff->pop();736diff->pop();737738} else {739diff->push_cell();740diff->pop();741742diff->push_cell();743diff->pop();744745diff->push_cell();746diff->pop();747}748749if (diff_line.new_line_no >= 0) {750diff->push_cell();751diff->push_color(has_change ? green : white);752diff->add_text(String::num_int64(diff_line.new_line_no));753diff->pop();754diff->pop();755756diff->push_cell();757diff->push_color(has_change ? green : white);758diff->add_text(has_change ? "+|" : " |");759diff->pop();760diff->pop();761762diff->push_cell();763diff->push_color(has_change ? green : white);764diff->add_text(diff_line.new_text);765diff->pop();766diff->pop();767} else {768diff->push_cell();769diff->pop();770771diff->push_cell();772diff->pop();773774diff->push_cell();775diff->pop();776}777}778diff->pop();779}780781void VersionControlEditorPlugin::_display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content) {782diff->push_table(4);783diff->set_table_column_expand(3, true);784785/*786[cell]Old Line No[/cell]787[cell]New Line No[/cell]788[cell]status[/cell]789[cell]code[/cell]790*/791for (const EditorVCSInterface::DiffLine &diff_line : p_diff_content) {792String line = diff_line.content.strip_edges(false, true);793794Color color;795if (diff_line.status == "+") {796color = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("success_color"), EditorStringName(Editor));797} else if (diff_line.status == "-") {798color = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor));799} else {800color = EditorNode::get_singleton()->get_editor_theme()->get_color(SceneStringName(font_color), SNAME("Label"));801color *= Color(1, 1, 1, 0.6);802}803804diff->push_cell();805diff->push_color(color);806diff->push_indent(1);807diff->add_text(diff_line.old_line_no >= 0 ? String::num_int64(diff_line.old_line_no) : "");808diff->pop();809diff->pop();810diff->pop();811812diff->push_cell();813diff->push_color(color);814diff->push_indent(1);815diff->add_text(diff_line.new_line_no >= 0 ? String::num_int64(diff_line.new_line_no) : "");816diff->pop();817diff->pop();818diff->pop();819820diff->push_cell();821diff->push_color(color);822diff->add_text(diff_line.status != "" ? diff_line.status + "|" : " |");823diff->pop();824diff->pop();825826diff->push_cell();827diff->push_color(color);828diff->add_text(line);829diff->pop();830diff->pop();831}832833diff->pop();834}835836void VersionControlEditorPlugin::_update_commit_button() {837commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty());838}839840void VersionControlEditorPlugin::_remove_branch() {841CHECK_PLUGIN_INITIALIZED();842843EditorVCSInterface::get_singleton()->remove_branch(branch_to_remove);844branch_to_remove.clear();845846_refresh_branch_list();847}848849void VersionControlEditorPlugin::_remove_remote() {850CHECK_PLUGIN_INITIALIZED();851852EditorVCSInterface::get_singleton()->remove_remote(remote_to_remove);853remote_to_remove.clear();854855_refresh_remote_list();856}857858void VersionControlEditorPlugin::_extra_option_selected(int p_index) {859CHECK_PLUGIN_INITIALIZED();860861switch ((ExtraOption)p_index) {862case EXTRA_OPTION_FORCE_PUSH:863_force_push();864break;865case EXTRA_OPTION_CREATE_BRANCH:866branch_create_confirm->popup_centered();867break;868case EXTRA_OPTION_CREATE_REMOTE:869remote_create_confirm->popup_centered();870break;871}872}873874void VersionControlEditorPlugin::_popup_branch_remove_confirm(int p_index) {875branch_to_remove = extra_options_remove_branch_list->get_item_text(p_index);876877branch_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s branch?"), branch_to_remove));878branch_remove_confirm->popup_centered();879}880881void VersionControlEditorPlugin::_popup_remote_remove_confirm(int p_index) {882remote_to_remove = extra_options_remove_remote_list->get_item_text(p_index);883884remote_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s remote?"), branch_to_remove));885remote_remove_confirm->popup_centered();886}887888void VersionControlEditorPlugin::_update_extra_options() {889extra_options_remove_branch_list->clear();890for (int i = 0; i < branch_select->get_item_count(); i++) {891extra_options_remove_branch_list->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("VcsBranches"), EditorStringName(EditorIcons)), branch_select->get_item_text(branch_select->get_item_id(i)));892}893extra_options_remove_branch_list->update_canvas_items();894895extra_options_remove_remote_list->clear();896for (int i = 0; i < remote_select->get_item_count(); i++) {897extra_options_remove_remote_list->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ArrowUp"), EditorStringName(EditorIcons)), remote_select->get_item_text(remote_select->get_item_id(i)));898}899extra_options_remove_remote_list->update_canvas_items();900}901902bool VersionControlEditorPlugin::_is_staging_area_empty() {903return staged_files->get_root()->get_child_count() == 0;904}905906void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) {907if (!commit_message->has_focus()) {908return;909}910if (commit_message->get_text().strip_edges().is_empty()) {911// Do not allow empty commit messages.912return;913}914const Ref<InputEventKey> k = p_event;915916if (k.is_valid() && k->is_pressed()) {917if (ED_IS_SHORTCUT("version_control/commit", p_event)) {918if (_is_staging_area_empty()) {919// Stage all files only when no files were previously staged.920_move_all(unstaged_files);921}922923_commit();924925commit_message->accept_event();926}927}928}929930void VersionControlEditorPlugin::_toggle_vcs_integration(bool p_toggled) {931if (p_toggled) {932_initialize_vcs();933} else {934shut_down();935}936}937938void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() {939available_plugins.clear();940ClassDB::get_direct_inheriters_from_class(EditorVCSInterface::get_class_static(), &available_plugins);941}942943void VersionControlEditorPlugin::register_editor() {944EditorDockManager::get_singleton()->add_dock(version_commit_dock);945EditorDockManager::get_singleton()->add_dock(version_control_dock);946947_set_vcs_ui_state(true);948}949950void VersionControlEditorPlugin::shut_down() {951if (!EditorVCSInterface::get_singleton()) {952return;953}954955if (EditorFileSystem::get_singleton()->is_connected(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) {956EditorFileSystem::get_singleton()->disconnect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));957}958959EditorVCSInterface::get_singleton()->shut_down();960memdelete(EditorVCSInterface::get_singleton());961EditorVCSInterface::set_singleton(nullptr);962963EditorDockManager::get_singleton()->remove_dock(version_commit_dock);964EditorDockManager::get_singleton()->remove_dock(version_control_dock);965966_set_vcs_ui_state(false);967}968969VersionControlEditorPlugin::VersionControlEditorPlugin() {970singleton = this;971972version_control_actions = memnew(PopupMenu);973974metadata_dialog = memnew(ConfirmationDialog);975metadata_dialog->set_title(TTR("Create Version Control Metadata"));976metadata_dialog->set_min_size(Size2(200, 40));977metadata_dialog->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files));978EditorInterface::get_singleton()->get_base_control()->add_child(metadata_dialog);979980VBoxContainer *metadata_vb = memnew(VBoxContainer);981metadata_dialog->add_child(metadata_vb);982983HBoxContainer *metadata_hb = memnew(HBoxContainer);984metadata_hb->set_custom_minimum_size(Size2(200, 20));985metadata_vb->add_child(metadata_hb);986987Label *l = memnew(Label);988l->set_text(TTR("Create VCS metadata files for:"));989metadata_hb->add_child(l);990991metadata_selection = memnew(OptionButton);992metadata_selection->set_custom_minimum_size(Size2(100, 20));993metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);994metadata_selection->select(metadata_selection->get_item_index((int)EditorVCSInterface::VCSMetadata::GIT));995metadata_hb->add_child(metadata_selection);996997l = memnew(Label);998l->set_text(TTR("Existing VCS metadata files will be overwritten."));999metadata_vb->add_child(l);10001001set_up_dialog = memnew(AcceptDialog);1002set_up_dialog->set_title(TTR("Local Settings"));1003set_up_dialog->set_min_size(Size2(600, 100));1004set_up_dialog->add_cancel_button("Cancel");1005set_up_dialog->set_hide_on_ok(true);1006EditorInterface::get_singleton()->get_base_control()->add_child(set_up_dialog);10071008Button *set_up_apply_button = set_up_dialog->get_ok_button();1009set_up_apply_button->set_text(TTR("Apply"));1010set_up_apply_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_set_credentials));10111012set_up_vbc = memnew(VBoxContainer);1013set_up_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);1014set_up_dialog->add_child(set_up_vbc);10151016HBoxContainer *set_up_hbc = memnew(HBoxContainer);1017set_up_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);1018set_up_vbc->add_child(set_up_hbc);10191020Label *set_up_vcs_label = memnew(Label);1021set_up_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1022set_up_vcs_label->set_text(TTR("VCS Provider"));1023set_up_hbc->add_child(set_up_vcs_label);10241025set_up_choice = memnew(OptionButton);1026set_up_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);1027set_up_hbc->add_child(set_up_choice);10281029HBoxContainer *toggle_vcs_hbc = memnew(HBoxContainer);1030toggle_vcs_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);1031set_up_vbc->add_child(toggle_vcs_hbc);10321033Label *toggle_vcs_label = memnew(Label);1034toggle_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1035toggle_vcs_label->set_text(TTR("Connect to VCS"));1036toggle_vcs_hbc->add_child(toggle_vcs_label);10371038toggle_vcs_choice = memnew(CheckButton);1039toggle_vcs_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);1040toggle_vcs_choice->set_pressed_no_signal(false);1041toggle_vcs_choice->connect(SceneStringName(toggled), callable_mp(this, &VersionControlEditorPlugin::_toggle_vcs_integration));1042toggle_vcs_hbc->add_child(toggle_vcs_choice);10431044set_up_vbc->add_child(memnew(HSeparator));10451046set_up_settings_vbc = memnew(VBoxContainer);1047set_up_settings_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);1048set_up_vbc->add_child(set_up_settings_vbc);10491050Label *remote_login = memnew(Label);1051remote_login->set_h_size_flags(Control::SIZE_EXPAND_FILL);1052remote_login->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);1053remote_login->set_text(TTR("Remote Login"));1054set_up_settings_vbc->add_child(remote_login);10551056HBoxContainer *set_up_username_input = memnew(HBoxContainer);1057set_up_username_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1058set_up_settings_vbc->add_child(set_up_username_input);10591060Label *set_up_username_label = memnew(Label);1061set_up_username_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1062set_up_username_label->set_text(TTR("Username"));1063set_up_username_input->add_child(set_up_username_label);10641065set_up_username = memnew(LineEdit);1066set_up_username->set_h_size_flags(Control::SIZE_EXPAND_FILL);1067set_up_username->set_text(EDITOR_GET("version_control/username"));1068set_up_username->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));1069set_up_username_input->add_child(set_up_username);10701071HBoxContainer *set_up_password_input = memnew(HBoxContainer);1072set_up_password_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1073set_up_settings_vbc->add_child(set_up_password_input);10741075Label *set_up_password_label = memnew(Label);1076set_up_password_label->set_text(TTR("Password"));1077set_up_password_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1078set_up_password_input->add_child(set_up_password_label);10791080set_up_password = memnew(LineEdit);1081set_up_password->set_h_size_flags(Control::SIZE_EXPAND_FILL);1082set_up_password->set_secret(true);1083set_up_password->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));1084set_up_password_input->add_child(set_up_password);10851086const String home_dir = OS::get_singleton()->has_environment("HOME") ? OS::get_singleton()->get_environment("HOME") : OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS);10871088HBoxContainer *set_up_ssh_public_key_input = memnew(HBoxContainer);1089set_up_ssh_public_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1090set_up_settings_vbc->add_child(set_up_ssh_public_key_input);10911092Label *set_up_ssh_public_key_label = memnew(Label);1093set_up_ssh_public_key_label->set_text(TTR("SSH Public Key Path"));1094set_up_ssh_public_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1095set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_label);10961097HBoxContainer *set_up_ssh_public_key_input_hbc = memnew(HBoxContainer);1098set_up_ssh_public_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);1099set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_input_hbc);11001101set_up_ssh_public_key_path = memnew(LineEdit);1102set_up_ssh_public_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);1103set_up_ssh_public_key_path->set_accessibility_name(TTRC("SSH Public Key Path"));1104set_up_ssh_public_key_path->set_text(EDITOR_GET("version_control/ssh_public_key_path"));1105set_up_ssh_public_key_path->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));1106set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_path);11071108set_up_ssh_public_key_file_dialog = memnew(EditorFileDialog);1109set_up_ssh_public_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);1110set_up_ssh_public_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);1111set_up_ssh_public_key_file_dialog->set_show_hidden_files(true);1112set_up_ssh_public_key_file_dialog->set_current_dir(home_dir);1113set_up_ssh_public_key_file_dialog->connect(SNAME("file_selected"), callable_mp(this, &VersionControlEditorPlugin::_ssh_public_key_selected));1114set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_file_dialog);11151116select_public_path_button = memnew(Button);1117select_public_path_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_public_key_file_dialog));1118select_public_path_button->set_tooltip_text(TTR("Select SSH public key path"));1119select_public_path_button->set_accessibility_name(TTRC("Select SSH public key path"));1120set_up_ssh_public_key_input_hbc->add_child(select_public_path_button);11211122HBoxContainer *set_up_ssh_private_key_input = memnew(HBoxContainer);1123set_up_ssh_private_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1124set_up_settings_vbc->add_child(set_up_ssh_private_key_input);11251126Label *set_up_ssh_private_key_label = memnew(Label);1127set_up_ssh_private_key_label->set_text(TTR("SSH Private Key Path"));1128set_up_ssh_private_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1129set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_label);11301131HBoxContainer *set_up_ssh_private_key_input_hbc = memnew(HBoxContainer);1132set_up_ssh_private_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);1133set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_input_hbc);11341135set_up_ssh_private_key_path = memnew(LineEdit);1136set_up_ssh_private_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);1137set_up_ssh_private_key_path->set_text(EDITOR_GET("version_control/ssh_private_key_path"));1138set_up_ssh_private_key_path->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));1139set_up_ssh_private_key_path->set_accessibility_name(TTRC("SSH Private Key Path"));1140set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_path);11411142set_up_ssh_private_key_file_dialog = memnew(EditorFileDialog);1143set_up_ssh_private_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);1144set_up_ssh_private_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);1145set_up_ssh_private_key_file_dialog->set_show_hidden_files(true);1146set_up_ssh_private_key_file_dialog->set_current_dir(home_dir);1147set_up_ssh_private_key_file_dialog->connect("file_selected", callable_mp(this, &VersionControlEditorPlugin::_ssh_private_key_selected));1148set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_file_dialog);11491150select_private_path_button = memnew(Button);1151select_private_path_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_private_key_file_dialog));1152select_private_path_button->set_tooltip_text(TTR("Select SSH private key path"));1153set_up_ssh_private_key_input_hbc->add_child(select_private_path_button);11541155HBoxContainer *set_up_ssh_passphrase_input = memnew(HBoxContainer);1156set_up_ssh_passphrase_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1157set_up_settings_vbc->add_child(set_up_ssh_passphrase_input);11581159Label *set_up_ssh_passphrase_label = memnew(Label);1160set_up_ssh_passphrase_label->set_text(TTR("SSH Passphrase"));1161set_up_ssh_passphrase_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1162set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase_label);11631164set_up_ssh_passphrase = memnew(LineEdit);1165set_up_ssh_passphrase->set_h_size_flags(Control::SIZE_EXPAND_FILL);1166set_up_ssh_passphrase->set_secret(true);1167set_up_ssh_passphrase->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));1168set_up_ssh_passphrase->set_accessibility_name(TTRC("SSH Passphrase"));1169set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase);11701171set_up_warning_text = memnew(Label);1172set_up_warning_text->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1173set_up_warning_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);1174set_up_warning_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);1175set_up_settings_vbc->add_child(set_up_warning_text);11761177version_commit_dock = memnew(EditorDock);1178version_commit_dock->set_visible(false);1179version_commit_dock->set_name(TTRC("Commit"));1180version_commit_dock->set_layout_key("VersionCommit");1181version_commit_dock->set_icon_name("VCSCommit");1182version_commit_dock->set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_version_control", TTRC("Open Version Control Dock")));1183version_commit_dock->set_default_slot(EditorDock::DOCK_SLOT_RIGHT_UL);11841185VBoxContainer *dock_vb = memnew(VBoxContainer);1186version_commit_dock->add_child(dock_vb);11871188VBoxContainer *unstage_area = memnew(VBoxContainer);1189unstage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL);1190unstage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL);1191dock_vb->add_child(unstage_area);11921193HBoxContainer *unstage_title = memnew(HBoxContainer);1194unstage_area->add_child(unstage_title);11951196Label *unstage_label = memnew(Label);1197unstage_label->set_text(TTR("Unstaged Changes"));1198unstage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1199unstage_title->add_child(unstage_label);12001201refresh_button = memnew(Button);1202refresh_button->set_tooltip_text(TTR("Detect new changes"));1203refresh_button->set_theme_type_variation(SceneStringName(FlatButton));1204refresh_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));1205refresh_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_commit_list));1206refresh_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));1207refresh_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));1208unstage_title->add_child(refresh_button);12091210discard_all_confirm = memnew(AcceptDialog);1211discard_all_confirm->set_title(TTR("Discard all changes"));1212discard_all_confirm->set_min_size(Size2i(400, 50));1213discard_all_confirm->set_text(TTR("This operation is IRREVERSIBLE. Your changes will be deleted FOREVER."));1214discard_all_confirm->set_hide_on_ok(true);1215discard_all_confirm->set_ok_button_text(TTR("Permanentally delete my changes"));1216discard_all_confirm->add_cancel_button();1217dock_vb->add_child(discard_all_confirm);12181219discard_all_confirm->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_discard_all));12201221discard_all_button = memnew(Button);1222discard_all_button->set_tooltip_text(TTR("Discard all changes"));1223discard_all_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_confirm_discard_all));1224discard_all_button->set_theme_type_variation(SceneStringName(FlatButton));1225unstage_title->add_child(discard_all_button);12261227stage_all_button = memnew(Button);1228stage_all_button->set_accessibility_name(TTRC("Stage all changes"));1229stage_all_button->set_theme_type_variation(SceneStringName(FlatButton));1230stage_all_button->set_tooltip_text(TTR("Stage all changes"));1231unstage_title->add_child(stage_all_button);12321233MarginContainer *mc = memnew(MarginContainer);1234mc->set_v_size_flags(Tree::SIZE_EXPAND_FILL);1235mc->set_theme_type_variation("NoBorderHorizontal");1236unstage_area->add_child(mc);12371238unstaged_files = memnew(Tree);1239unstaged_files->set_select_mode(Tree::SELECT_ROW);1240unstaged_files->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(unstaged_files));1241unstaged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(unstaged_files));1242unstaged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed));1243unstaged_files->create_item();1244unstaged_files->set_hide_root(true);1245unstaged_files->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH);1246mc->add_child(unstaged_files);12471248VBoxContainer *stage_area = memnew(VBoxContainer);1249stage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL);1250stage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL);1251dock_vb->add_child(stage_area);12521253HBoxContainer *stage_title = memnew(HBoxContainer);1254stage_area->add_child(stage_title);12551256Label *stage_label = memnew(Label);1257stage_label->set_text(TTR("Staged Changes"));1258stage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1259stage_title->add_child(stage_label);12601261unstage_all_button = memnew(Button);1262unstage_all_button->set_accessibility_name(TTRC("Unstage all changes"));1263unstage_all_button->set_theme_type_variation(SceneStringName(FlatButton));1264unstage_all_button->set_tooltip_text(TTR("Unstage all changes"));1265stage_title->add_child(unstage_all_button);12661267mc = memnew(MarginContainer);1268mc->set_v_size_flags(Tree::SIZE_EXPAND_FILL);1269mc->set_theme_type_variation("NoBorderHorizontal");1270stage_area->add_child(mc);12711272staged_files = memnew(Tree);1273staged_files->set_select_mode(Tree::SELECT_ROW);1274staged_files->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(staged_files));1275staged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed));1276staged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(staged_files));1277staged_files->create_item();1278staged_files->set_hide_root(true);1279staged_files->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH);1280mc->add_child(staged_files);12811282// Editor crashes if bind is null1283unstage_all_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(staged_files));1284stage_all_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(unstaged_files));12851286VBoxContainer *commit_area = memnew(VBoxContainer);1287dock_vb->add_child(commit_area);12881289Label *commit_label = memnew(Label);1290commit_label->set_text(TTR("Commit Message"));1291commit_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1292commit_area->add_child(commit_label);12931294commit_message = memnew(TextEdit);1295commit_message->set_accessibility_name(TTRC("Commit Message"));1296commit_message->set_h_size_flags(Control::SIZE_EXPAND_FILL);1297commit_message->set_h_grow_direction(Control::GrowDirection::GROW_DIRECTION_BEGIN);1298commit_message->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END);1299commit_message->set_custom_minimum_size(Size2(200, 100));1300commit_message->set_line_wrapping_mode(TextEdit::LINE_WRAPPING_BOUNDARY);1301commit_message->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_commit_button));1302commit_message->connect(SceneStringName(gui_input), callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input));1303commit_area->add_child(commit_message);13041305ED_SHORTCUT("version_control/commit", TTRC("Commit"), KeyModifierMask::CMD_OR_CTRL | Key::ENTER);13061307commit_button = memnew(Button);1308commit_button->set_text(TTR("Commit Changes"));1309commit_button->set_disabled(true);1310commit_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_commit));1311commit_area->add_child(commit_button);13121313dock_vb->add_child(memnew(HSeparator));13141315HBoxContainer *commit_list_hbc = memnew(HBoxContainer);1316dock_vb->add_child(commit_list_hbc);13171318Label *commit_list_label = memnew(Label);1319commit_list_label->set_text(TTR("Commit List"));1320commit_list_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1321commit_list_hbc->add_child(commit_list_label);13221323commit_list_size_button = memnew(OptionButton);1324commit_list_size_button->set_tooltip_text(TTR("Commit list size"));1325commit_list_size_button->add_item("10");1326commit_list_size_button->set_item_metadata(0, 10);1327commit_list_size_button->add_item("20");1328commit_list_size_button->set_item_metadata(1, 20);1329commit_list_size_button->add_item("30");1330commit_list_size_button->set_item_metadata(2, 30);1331commit_list_size_button->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_set_commit_list_size));1332commit_list_hbc->add_child(commit_list_size_button);13331334mc = memnew(MarginContainer);1335mc->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END);1336mc->set_theme_type_variation("NoBorderHorizontal");1337dock_vb->add_child(mc);13381339commit_list = memnew(Tree);1340commit_list->set_custom_minimum_size(Size2(200, 160));1341commit_list->create_item();1342commit_list->set_hide_root(true);1343commit_list->set_select_mode(Tree::SELECT_ROW);1344commit_list->set_columns(2); // Commit message and author.1345commit_list->set_column_custom_minimum_width(0, 40);1346commit_list->set_column_custom_minimum_width(1, 20);1347commit_list->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH);1348commit_list->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(commit_list));1349mc->add_child(commit_list);13501351HFlowContainer *menu_bar = memnew(HFlowContainer);1352menu_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);1353menu_bar->set_v_size_flags(Control::SIZE_FILL);1354dock_vb->add_child(menu_bar);13551356branch_select = memnew(OptionButton);1357branch_select->set_tooltip_text(TTR("Branches"));1358branch_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);1359branch_select->set_clip_text(true);1360branch_select->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_branch_item_selected));1361branch_select->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));1362menu_bar->add_child(branch_select);13631364branch_create_confirm = memnew(AcceptDialog);1365branch_create_confirm->set_title(TTR("Create New Branch"));1366branch_create_confirm->set_min_size(Size2(400, 100));1367branch_create_confirm->set_hide_on_ok(true);1368version_commit_dock->add_child(branch_create_confirm);13691370branch_create_ok = branch_create_confirm->get_ok_button();1371branch_create_ok->set_text(TTR("Create"));1372branch_create_ok->set_disabled(true);1373branch_create_ok->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_create_branch));13741375branch_remove_confirm = memnew(AcceptDialog);1376branch_remove_confirm->set_title(TTR("Remove Branch"));1377branch_remove_confirm->add_cancel_button();1378version_commit_dock->add_child(branch_remove_confirm);13791380Button *branch_remove_ok = branch_remove_confirm->get_ok_button();1381branch_remove_ok->set_text(TTR("Remove"));1382branch_remove_ok->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_remove_branch));13831384VBoxContainer *branch_create_vbc = memnew(VBoxContainer);1385branch_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);1386branch_create_confirm->add_child(branch_create_vbc);13871388HBoxContainer *branch_create_hbc = memnew(HBoxContainer);1389branch_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);1390branch_create_vbc->add_child(branch_create_hbc);13911392Label *branch_create_name_label = memnew(Label);1393branch_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1394branch_create_name_label->set_text(TTR("Branch Name"));1395branch_create_hbc->add_child(branch_create_name_label);13961397branch_create_name_input = memnew(LineEdit);1398branch_create_name_input->set_accessibility_name(TTRC("Branch Name"));1399branch_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1400branch_create_name_input->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_branch_create_button));1401branch_create_hbc->add_child(branch_create_name_input);14021403remote_select = memnew(OptionButton);1404remote_select->set_tooltip_text(TTR("Remotes"));1405remote_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);1406remote_select->set_clip_text(true);1407remote_select->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_remote_selected));1408remote_select->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));1409menu_bar->add_child(remote_select);14101411remote_create_confirm = memnew(AcceptDialog);1412remote_create_confirm->set_title(TTR("Create New Remote"));1413remote_create_confirm->set_min_size(Size2(400, 100));1414remote_create_confirm->set_hide_on_ok(true);1415version_commit_dock->add_child(remote_create_confirm);14161417remote_create_ok = remote_create_confirm->get_ok_button();1418remote_create_ok->set_text(TTR("Create"));1419remote_create_ok->set_disabled(true);1420remote_create_ok->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_create_remote));14211422remote_remove_confirm = memnew(AcceptDialog);1423remote_remove_confirm->set_title(TTR("Remove Remote"));1424remote_remove_confirm->add_cancel_button();1425version_commit_dock->add_child(remote_remove_confirm);14261427Button *remote_remove_ok = remote_remove_confirm->get_ok_button();1428remote_remove_ok->set_text(TTR("Remove"));1429remote_remove_ok->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_remove_remote));14301431VBoxContainer *remote_create_vbc = memnew(VBoxContainer);1432remote_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);1433remote_create_confirm->add_child(remote_create_vbc);14341435HBoxContainer *remote_create_name_hbc = memnew(HBoxContainer);1436remote_create_name_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);1437remote_create_vbc->add_child(remote_create_name_hbc);14381439Label *remote_create_name_label = memnew(Label);1440remote_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1441remote_create_name_label->set_text(TTR("Remote Name"));1442remote_create_name_hbc->add_child(remote_create_name_label);14431444remote_create_name_input = memnew(LineEdit);1445remote_create_name_input->set_accessibility_name(TTRC("Remote Name"));1446remote_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1447remote_create_name_input->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button));1448remote_create_name_hbc->add_child(remote_create_name_input);14491450HBoxContainer *remote_create_hbc = memnew(HBoxContainer);1451remote_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);1452remote_create_vbc->add_child(remote_create_hbc);14531454Label *remote_create_url_label = memnew(Label);1455remote_create_url_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1456remote_create_url_label->set_text(TTR("Remote URL"));1457remote_create_hbc->add_child(remote_create_url_label);14581459remote_create_url_input = memnew(LineEdit);1460remote_create_url_input->set_accessibility_name(TTRC("Remote URL"));1461remote_create_url_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);1462remote_create_url_input->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button));1463remote_create_hbc->add_child(remote_create_url_input);14641465fetch_button = memnew(Button);1466fetch_button->set_theme_type_variation(SceneStringName(FlatButton));1467fetch_button->set_tooltip_text(TTR("Fetch"));1468fetch_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_fetch));1469menu_bar->add_child(fetch_button);14701471pull_button = memnew(Button);1472pull_button->set_theme_type_variation(SceneStringName(FlatButton));1473pull_button->set_tooltip_text(TTR("Pull"));1474pull_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_pull));1475menu_bar->add_child(pull_button);14761477push_button = memnew(Button);1478push_button->set_theme_type_variation(SceneStringName(FlatButton));1479push_button->set_tooltip_text(TTR("Push"));1480push_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_push));1481menu_bar->add_child(push_button);14821483extra_options = memnew(MenuButton);1484extra_options->set_accessibility_name(TTRC("Extra options"));1485extra_options->get_popup()->connect(SNAME("about_to_popup"), callable_mp(this, &VersionControlEditorPlugin::_update_extra_options));1486extra_options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected));1487menu_bar->add_child(extra_options);14881489extra_options->get_popup()->add_item(TTR("Force Push"), EXTRA_OPTION_FORCE_PUSH);1490extra_options->get_popup()->add_separator();1491extra_options->get_popup()->add_item(TTR("Create New Branch"), EXTRA_OPTION_CREATE_BRANCH);14921493extra_options_remove_branch_list = memnew(PopupMenu);1494extra_options_remove_branch_list->connect(SceneStringName(id_pressed), callable_mp(this, &VersionControlEditorPlugin::_popup_branch_remove_confirm));1495extra_options->get_popup()->add_submenu_node_item(TTR("Remove Branch"), extra_options_remove_branch_list);14961497extra_options->get_popup()->add_separator();1498extra_options->get_popup()->add_item(TTR("Create New Remote"), EXTRA_OPTION_CREATE_REMOTE);14991500extra_options_remove_remote_list = memnew(PopupMenu);1501extra_options_remove_remote_list->connect(SceneStringName(id_pressed), callable_mp(this, &VersionControlEditorPlugin::_popup_remote_remove_confirm));1502extra_options->get_popup()->add_submenu_node_item(TTR("Remove Remote"), extra_options_remove_remote_list);15031504change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_NEW] = TTR("New");1505change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = TTR("Modified");1506change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_RENAMED] = TTR("Renamed");1507change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_DELETED] = TTR("Deleted");1508change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = TTR("Typechange");1509change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = TTR("Unmerged");15101511version_control_dock = memnew(EditorDock);1512version_control_dock->set_name(TTRC("Version Control"));1513version_control_dock->set_icon_name("VcsBranches");1514version_control_dock->set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_version_control_bottom_panel", TTRC("Toggle Version Control Dock")));1515version_control_dock->set_default_slot(EditorDock::DOCK_SLOT_BOTTOM);1516version_control_dock->set_available_layouts(EditorDock::DOCK_LAYOUT_HORIZONTAL | EditorDock::DOCK_LAYOUT_FLOATING);1517version_control_dock->set_global(false);1518version_control_dock->set_transient(true);1519version_control_dock->set_custom_minimum_size(Size2(0, 300) * EDSCALE);1520version_commit_dock->connect("opened", callable_mp(EditorDockManager::get_singleton(), &EditorDockManager::open_dock).bind(version_control_dock, false));1521version_commit_dock->connect("closed", callable_mp(EditorDockManager::get_singleton(), &EditorDockManager::close_dock).bind(version_control_dock));15221523VBoxContainer *vbc = memnew(VBoxContainer);1524version_control_dock->add_child(vbc);15251526HBoxContainer *diff_heading = memnew(HBoxContainer);1527diff_heading->set_h_size_flags(Control::SIZE_EXPAND_FILL);1528diff_heading->set_tooltip_text(TTR("View file diffs before committing them to the latest version"));1529vbc->add_child(diff_heading);15301531diff_title = memnew(Label);1532diff_title->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1533diff_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);1534diff_heading->add_child(diff_title);15351536Label *view = memnew(Label);1537view->set_text(TTR("View:"));1538diff_heading->add_child(view);15391540diff_view_type_select = memnew(OptionButton);1541diff_view_type_select->set_accessibility_name(TTRC("View:"));1542diff_view_type_select->add_item(TTR("Split"), DIFF_VIEW_TYPE_SPLIT);1543diff_view_type_select->add_item(TTR("Unified"), DIFF_VIEW_TYPE_UNIFIED);1544diff_view_type_select->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_display_diff));1545diff_heading->add_child(diff_view_type_select);15461547diff = memnew(RichTextLabel);1548diff->set_h_size_flags(TextEdit::SIZE_EXPAND_FILL);1549diff->set_v_size_flags(TextEdit::SIZE_EXPAND_FILL);1550diff->set_use_bbcode(true);1551diff->set_selection_enabled(true);1552diff->set_context_menu_enabled(true);1553vbc->add_child(diff);15541555_update_set_up_warning("");1556EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &VersionControlEditorPlugin::_update_theme));1557}15581559VersionControlEditorPlugin::~VersionControlEditorPlugin() {1560shut_down();1561memdelete(version_commit_dock);1562memdelete(version_control_dock);1563memdelete(version_control_actions);1564}156515661567