You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-20 14:45:44 +00:00
Merge pull request #112187 from timothyqiu/deps-manual-ii
Allow fixing indirect missing dependencies manually
This commit is contained in:
@@ -43,6 +43,7 @@
|
|||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
#include "editor/editor_undo_redo_manager.h"
|
#include "editor/editor_undo_redo_manager.h"
|
||||||
|
#include "editor/file_system/dependency_editor.h"
|
||||||
#include "editor/gui/create_dialog.h"
|
#include "editor/gui/create_dialog.h"
|
||||||
#include "editor/gui/directory_create_dialog.h"
|
#include "editor/gui/directory_create_dialog.h"
|
||||||
#include "editor/gui/editor_dir_dialog.h"
|
#include "editor/gui/editor_dir_dialog.h"
|
||||||
|
|||||||
@@ -39,14 +39,17 @@
|
|||||||
#include "scene/gui/box_container.h"
|
#include "scene/gui/box_container.h"
|
||||||
#include "scene/gui/control.h"
|
#include "scene/gui/control.h"
|
||||||
#include "scene/gui/dialogs.h"
|
#include "scene/gui/dialogs.h"
|
||||||
|
#include "scene/gui/item_list.h"
|
||||||
#include "scene/gui/menu_button.h"
|
#include "scene/gui/menu_button.h"
|
||||||
#include "scene/gui/split_container.h"
|
#include "scene/gui/split_container.h"
|
||||||
#include "scene/gui/tree.h"
|
#include "scene/gui/tree.h"
|
||||||
|
|
||||||
class CreateDialog;
|
class CreateDialog;
|
||||||
|
class DependencyEditor;
|
||||||
|
class DependencyEditorOwners;
|
||||||
|
class DependencyRemoveDialog;
|
||||||
class EditorDirDialog;
|
class EditorDirDialog;
|
||||||
class HBoxContainer;
|
class HBoxContainer;
|
||||||
class ItemList;
|
|
||||||
class LineEdit;
|
class LineEdit;
|
||||||
class ProgressBar;
|
class ProgressBar;
|
||||||
class SceneCreateDialog;
|
class SceneCreateDialog;
|
||||||
|
|||||||
@@ -1576,13 +1576,9 @@ Error EditorNode::load_resource(const String &p_resource, bool p_ignore_broken_d
|
|||||||
}
|
}
|
||||||
ERR_FAIL_COND_V(res.is_null(), ERR_CANT_OPEN);
|
ERR_FAIL_COND_V(res.is_null(), ERR_CANT_OPEN);
|
||||||
|
|
||||||
if (!p_ignore_broken_deps && dependency_errors.has(p_resource)) {
|
if (!p_ignore_broken_deps && !dependency_errors.is_empty()) {
|
||||||
Vector<String> errors;
|
dependency_error->show(p_resource, dependency_errors);
|
||||||
for (const String &E : dependency_errors[p_resource]) {
|
dependency_errors.clear();
|
||||||
errors.push_back(E);
|
|
||||||
}
|
|
||||||
dependency_error->show(p_resource, errors);
|
|
||||||
dependency_errors.erase(p_resource);
|
|
||||||
|
|
||||||
return ERR_FILE_MISSING_DEPENDENCIES;
|
return ERR_FILE_MISSING_DEPENDENCIES;
|
||||||
}
|
}
|
||||||
@@ -4558,10 +4554,6 @@ bool EditorNode::is_multi_window_enabled() const {
|
|||||||
return !SceneTree::get_singleton()->get_root()->is_embedding_subwindows() && !EDITOR_GET("interface/editor/single_window_mode") && EDITOR_GET("interface/multi_window/enable");
|
return !SceneTree::get_singleton()->get_root()->is_embedding_subwindows() && !EDITOR_GET("interface/editor/single_window_mode") && EDITOR_GET("interface/multi_window/enable");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorNode::fix_dependencies(const String &p_for_file) {
|
|
||||||
dependency_fixer->edit(p_for_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
int EditorNode::new_scene() {
|
int EditorNode::new_scene() {
|
||||||
int idx = editor_data.add_edited_scene(-1);
|
int idx = editor_data.add_edited_scene(-1);
|
||||||
_set_current_scene(idx); // Before trying to remove an empty scene, set the current tab index to the newly added tab index.
|
_set_current_scene(idx); // Before trying to remove an empty scene, set the current tab index to the newly added tab index.
|
||||||
@@ -4636,13 +4628,10 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
|
|||||||
Error err;
|
Error err;
|
||||||
Ref<PackedScene> sdata = ResourceLoader::load(lpath, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
|
Ref<PackedScene> sdata = ResourceLoader::load(lpath, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
|
||||||
|
|
||||||
if (!p_ignore_broken_deps && dependency_errors.has(lpath)) {
|
if (!p_ignore_broken_deps && !dependency_errors.is_empty()) {
|
||||||
current_menu_option = -1;
|
current_menu_option = -1;
|
||||||
Vector<String> errors;
|
dependency_error->show(lpath, dependency_errors);
|
||||||
for (const String &E : dependency_errors[lpath]) {
|
dependency_errors.clear();
|
||||||
errors.push_back(E);
|
|
||||||
}
|
|
||||||
dependency_error->show(lpath, errors);
|
|
||||||
|
|
||||||
if (prev != -1 && prev != idx) {
|
if (prev != -1 && prev != idx) {
|
||||||
_set_current_scene(prev);
|
_set_current_scene(prev);
|
||||||
@@ -8318,9 +8307,6 @@ EditorNode::EditorNode() {
|
|||||||
dependency_error = memnew(DependencyErrorDialog);
|
dependency_error = memnew(DependencyErrorDialog);
|
||||||
gui_base->add_child(dependency_error);
|
gui_base->add_child(dependency_error);
|
||||||
|
|
||||||
dependency_fixer = memnew(DependencyEditor);
|
|
||||||
gui_base->add_child(dependency_fixer);
|
|
||||||
|
|
||||||
editor_settings_dialog = memnew(EditorSettingsDialog);
|
editor_settings_dialog = memnew(EditorSettingsDialog);
|
||||||
gui_base->add_child(editor_settings_dialog);
|
gui_base->add_child(editor_settings_dialog);
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ class Window;
|
|||||||
class AudioStreamImportSettingsDialog;
|
class AudioStreamImportSettingsDialog;
|
||||||
class AudioStreamPreviewGenerator;
|
class AudioStreamPreviewGenerator;
|
||||||
class BackgroundProgress;
|
class BackgroundProgress;
|
||||||
class DependencyEditor;
|
|
||||||
class DependencyErrorDialog;
|
class DependencyErrorDialog;
|
||||||
class DockSplitContainer;
|
class DockSplitContainer;
|
||||||
class DynamicFontImportSettingsDialog;
|
class DynamicFontImportSettingsDialog;
|
||||||
@@ -421,7 +420,6 @@ private:
|
|||||||
|
|
||||||
DependencyErrorDialog *dependency_error = nullptr;
|
DependencyErrorDialog *dependency_error = nullptr;
|
||||||
HashMap<String, HashSet<String>> dependency_errors;
|
HashMap<String, HashSet<String>> dependency_errors;
|
||||||
DependencyEditor *dependency_fixer = nullptr;
|
|
||||||
OrphanResourcesDialog *orphan_resources = nullptr;
|
OrphanResourcesDialog *orphan_resources = nullptr;
|
||||||
ConfirmationDialog *open_imported = nullptr;
|
ConfirmationDialog *open_imported = nullptr;
|
||||||
Button *new_inherited_button = nullptr;
|
Button *new_inherited_button = nullptr;
|
||||||
@@ -851,7 +849,6 @@ public:
|
|||||||
String get_preview_locale() const;
|
String get_preview_locale() const;
|
||||||
void set_preview_locale(const String &p_locale);
|
void set_preview_locale(const String &p_locale);
|
||||||
|
|
||||||
void fix_dependencies(const String &p_for_file);
|
|
||||||
int new_scene();
|
int new_scene();
|
||||||
Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_force_open_imported = false, bool p_silent_change_tab = false);
|
Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_force_open_imported = false, bool p_silent_change_tab = false);
|
||||||
Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
|
Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
|
||||||
|
|||||||
@@ -37,10 +37,28 @@
|
|||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
#include "editor/file_system/editor_file_system.h"
|
#include "editor/file_system/editor_file_system.h"
|
||||||
#include "editor/gui/editor_file_dialog.h"
|
#include "editor/gui/editor_file_dialog.h"
|
||||||
|
#include "editor/gui/editor_quick_open_dialog.h"
|
||||||
#include "editor/settings/editor_settings.h"
|
#include "editor/settings/editor_settings.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
|
#include "scene/gui/box_container.h"
|
||||||
|
#include "scene/gui/item_list.h"
|
||||||
#include "scene/gui/margin_container.h"
|
#include "scene/gui/margin_container.h"
|
||||||
#include "scene/gui/popup_menu.h"
|
#include "scene/gui/popup_menu.h"
|
||||||
|
#include "scene/gui/tree.h"
|
||||||
|
|
||||||
|
static void _setup_search_file_dialog(EditorFileDialog *p_dialog, const String &p_file, const String &p_type) {
|
||||||
|
p_dialog->set_title(vformat(TTR("Search Replacement For: %s"), p_file.get_file()));
|
||||||
|
|
||||||
|
// Set directory to closest existing directory.
|
||||||
|
p_dialog->set_current_dir(p_file.get_base_dir());
|
||||||
|
|
||||||
|
p_dialog->clear_filters();
|
||||||
|
List<String> ext;
|
||||||
|
ResourceLoader::get_recognized_extensions_for_type(p_type, &ext);
|
||||||
|
for (const String &E : ext) {
|
||||||
|
p_dialog->add_filter("*." + E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DependencyEditor::_searched(const String &p_path) {
|
void DependencyEditor::_searched(const String &p_path) {
|
||||||
HashMap<String, String> dep_rename;
|
HashMap<String, String> dep_rename;
|
||||||
@@ -59,17 +77,7 @@ void DependencyEditor::_load_pressed(Object *p_item, int p_cell, int p_button, M
|
|||||||
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
|
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
|
||||||
replacing = ti->get_text(1);
|
replacing = ti->get_text(1);
|
||||||
|
|
||||||
search->set_title(TTR("Search Replacement For:") + " " + replacing.get_file());
|
_setup_search_file_dialog(search, replacing, ti->get_metadata(0));
|
||||||
|
|
||||||
// Set directory to closest existing directory.
|
|
||||||
search->set_current_dir(replacing.get_base_dir());
|
|
||||||
|
|
||||||
search->clear_filters();
|
|
||||||
List<String> ext;
|
|
||||||
ResourceLoader::get_recognized_extensions_for_type(ti->get_metadata(0), &ext);
|
|
||||||
for (const String &E : ext) {
|
|
||||||
search->add_filter("*." + E);
|
|
||||||
}
|
|
||||||
search->popup_file_dialog();
|
search->popup_file_dialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +179,30 @@ void DependencyEditor::_notification(int p_what) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String _get_resolved_dep_path(const String &p_dep) {
|
||||||
|
if (p_dep.get_slice_count("::") < 3) {
|
||||||
|
return p_dep.get_slice("::", 0); // No UID, just return the path.
|
||||||
|
}
|
||||||
|
|
||||||
|
const String uid_text = p_dep.get_slice("::", 0);
|
||||||
|
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uid_text);
|
||||||
|
|
||||||
|
// Dependency is in UID format, obtain proper path.
|
||||||
|
if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) {
|
||||||
|
return ResourceUID::get_singleton()->get_id_path(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UID fallback path.
|
||||||
|
return p_dep.get_slice("::", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _get_stored_dep_path(const String &p_dep) {
|
||||||
|
if (p_dep.get_slice_count("::") > 2) {
|
||||||
|
return p_dep.get_slice("::", 2);
|
||||||
|
}
|
||||||
|
return p_dep.get_slice("::", 0);
|
||||||
|
}
|
||||||
|
|
||||||
void DependencyEditor::_update_list() {
|
void DependencyEditor::_update_list() {
|
||||||
List<String> deps;
|
List<String> deps;
|
||||||
ResourceLoader::get_dependencies(editing, &deps, true);
|
ResourceLoader::get_dependencies(editing, &deps, true);
|
||||||
@@ -184,47 +216,27 @@ void DependencyEditor::_update_list() {
|
|||||||
|
|
||||||
bool broken = false;
|
bool broken = false;
|
||||||
|
|
||||||
for (const String &n : deps) {
|
for (const String &dep : deps) {
|
||||||
TreeItem *item = tree->create_item(root);
|
TreeItem *item = tree->create_item(root);
|
||||||
String path;
|
|
||||||
String type;
|
|
||||||
|
|
||||||
if (n.contains("::")) {
|
const String path = _get_resolved_dep_path(dep);
|
||||||
path = n.get_slice("::", 0);
|
if (FileAccess::exists(path)) {
|
||||||
type = n.get_slice("::", 1);
|
item->set_text(0, path.get_file());
|
||||||
} else {
|
|
||||||
path = n;
|
|
||||||
type = "Resource";
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(path);
|
|
||||||
if (uid != ResourceUID::INVALID_ID) {
|
|
||||||
// Dependency is in uid format, obtain proper path.
|
|
||||||
if (ResourceUID::get_singleton()->has_id(uid)) {
|
|
||||||
path = ResourceUID::get_singleton()->get_id_path(uid);
|
|
||||||
} else if (n.get_slice_count("::") >= 3) {
|
|
||||||
// If uid can't be found, try to use fallback path.
|
|
||||||
path = n.get_slice("::", 2);
|
|
||||||
} else {
|
|
||||||
ERR_PRINT("Invalid dependency UID and fallback path.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = path.get_file();
|
|
||||||
|
|
||||||
Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(type);
|
|
||||||
item->set_text(0, name);
|
|
||||||
item->set_icon(0, icon);
|
|
||||||
item->set_metadata(0, type);
|
|
||||||
item->set_text(1, path);
|
item->set_text(1, path);
|
||||||
|
} else {
|
||||||
if (!FileAccess::exists(path)) {
|
const String &stored_path = _get_stored_dep_path(dep);
|
||||||
|
item->set_text(0, stored_path.get_file());
|
||||||
|
item->set_text(1, stored_path);
|
||||||
item->set_custom_color(1, Color(1, 0.4, 0.3));
|
item->set_custom_color(1, Color(1, 0.4, 0.3));
|
||||||
missing.push_back(path);
|
missing.push_back(stored_path);
|
||||||
broken = true;
|
broken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const String type = dep.contains("::") ? dep.get_slice("::", 1) : "Resource";
|
||||||
|
Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(type);
|
||||||
|
item->set_icon(0, icon);
|
||||||
|
item->set_metadata(0, type);
|
||||||
|
|
||||||
item->add_button(1, folder, 0);
|
item->add_button(1, folder, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,10 +272,8 @@ DependencyEditor::DependencyEditor() {
|
|||||||
tree->set_column_titles_visible(true);
|
tree->set_column_titles_visible(true);
|
||||||
tree->set_column_title(0, TTR("Resource"));
|
tree->set_column_title(0, TTR("Resource"));
|
||||||
tree->set_column_clip_content(0, true);
|
tree->set_column_clip_content(0, true);
|
||||||
tree->set_column_expand_ratio(0, 2);
|
|
||||||
tree->set_column_title(1, TTR("Path"));
|
tree->set_column_title(1, TTR("Path"));
|
||||||
tree->set_column_clip_content(1, true);
|
tree->set_column_clip_content(1, true);
|
||||||
tree->set_column_expand_ratio(1, 1);
|
|
||||||
tree->set_hide_root(true);
|
tree->set_hide_root(true);
|
||||||
tree->connect("button_clicked", callable_mp(this, &DependencyEditor::_load_pressed));
|
tree->connect("button_clicked", callable_mp(this, &DependencyEditor::_load_pressed));
|
||||||
|
|
||||||
@@ -293,7 +303,6 @@ DependencyEditor::DependencyEditor() {
|
|||||||
search = memnew(EditorFileDialog);
|
search = memnew(EditorFileDialog);
|
||||||
search->connect("file_selected", callable_mp(this, &DependencyEditor::_searched));
|
search->connect("file_selected", callable_mp(this, &DependencyEditor::_searched));
|
||||||
search->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
search->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
||||||
search->set_title(TTR("Search Replacement Resource:"));
|
|
||||||
add_child(search);
|
add_child(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,61 +737,163 @@ DependencyRemoveDialog::DependencyRemoveDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
|
enum {
|
||||||
|
BUTTON_ID_SEARCH,
|
||||||
|
BUTTON_ID_OPEN_DEPS_EDITOR,
|
||||||
|
};
|
||||||
|
|
||||||
void DependencyErrorDialog::show(const String &p_for_file, const Vector<String> &report) {
|
void DependencyErrorDialog::show(const String &p_for_file, const HashMap<String, HashSet<String>> &p_report) {
|
||||||
for_file = p_for_file;
|
for_file = p_for_file;
|
||||||
set_title(TTR("Error loading:") + " " + p_for_file.get_file());
|
|
||||||
|
// TRANSLATORS: The placeholder is a filename.
|
||||||
|
set_title(vformat(TTR("Error loading: %s"), p_for_file.get_file()));
|
||||||
|
|
||||||
|
HashMap<String, HashSet<String>> missing_to_owners;
|
||||||
|
for (const KeyValue<String, HashSet<String>> &E : p_report) {
|
||||||
|
for (const String &missing : E.value) {
|
||||||
|
missing_to_owners[missing].insert(E.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
files->clear();
|
files->clear();
|
||||||
|
|
||||||
TreeItem *root = files->create_item(nullptr);
|
TreeItem *root = files->create_item(nullptr);
|
||||||
for (int i = 0; i < report.size(); i++) {
|
Ref<Texture2D> folder_icon = get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
|
||||||
String dep;
|
|
||||||
String type = "Object";
|
for (const KeyValue<String, HashSet<String>> &E : missing_to_owners) {
|
||||||
dep = report[i].get_slice("::", 0);
|
const String &missing_path = E.key.get_slice("::", 0);
|
||||||
if (report[i].get_slice_count("::") > 0) {
|
const String &missing_type = E.key.get_slice("::", 1);
|
||||||
type = report[i].get_slice("::", 1);
|
|
||||||
}
|
TreeItem *missing_ti = root->create_child();
|
||||||
|
missing_ti->set_text(0, missing_path);
|
||||||
Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(type);
|
missing_ti->set_metadata(0, E.key);
|
||||||
|
missing_ti->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
|
||||||
TreeItem *ti = files->create_item(root);
|
missing_ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(missing_type));
|
||||||
ti->set_text(0, dep);
|
missing_ti->set_icon(1, get_editor_theme_icon(icon_name_fail));
|
||||||
ti->set_icon(0, icon);
|
missing_ti->add_button(1, folder_icon, BUTTON_ID_SEARCH, false, TTRC("Search"));
|
||||||
|
missing_ti->set_collapsed(true);
|
||||||
|
|
||||||
|
for (const String &owner_path : E.value) {
|
||||||
|
TreeItem *owner_ti = missing_ti->create_child();
|
||||||
|
// TRANSLATORS: The placeholder is a file path.
|
||||||
|
owner_ti->set_text(0, vformat(TTR("Referenced by %s"), owner_path));
|
||||||
|
owner_ti->set_metadata(0, owner_path);
|
||||||
|
owner_ti->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
|
||||||
|
owner_ti->add_button(1, files->get_editor_theme_icon(SNAME("Edit")), BUTTON_ID_OPEN_DEPS_EDITOR, false, TTRC("Fix Dependencies"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_ok_button_text(TTRC("Open Anyway"));
|
||||||
popup_centered();
|
popup_centered();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DependencyErrorDialog::ok_pressed() {
|
void DependencyErrorDialog::ok_pressed() {
|
||||||
EditorNode::get_singleton()->load_scene_or_resource(for_file, true);
|
EditorNode::get_singleton()->load_scene_or_resource(for_file, !errors_fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DependencyErrorDialog::custom_action(const String &) {
|
void DependencyErrorDialog::_on_files_button_clicked(TreeItem *p_item, int p_column, int p_id, MouseButton p_button) {
|
||||||
EditorNode::get_singleton()->fix_dependencies(for_file);
|
switch (p_id) {
|
||||||
|
case BUTTON_ID_SEARCH: {
|
||||||
|
const String &meta = p_item->get_metadata(0);
|
||||||
|
const String &missing_path = meta.get_slice("::", 0);
|
||||||
|
const String &missing_type = meta.get_slice("::", 1);
|
||||||
|
if (replacement_file_dialog == nullptr) {
|
||||||
|
replacement_file_dialog = memnew(EditorFileDialog);
|
||||||
|
replacement_file_dialog->connect("file_selected", callable_mp(this, &DependencyErrorDialog::_on_replacement_file_selected));
|
||||||
|
replacement_file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
||||||
|
add_child(replacement_file_dialog);
|
||||||
|
}
|
||||||
|
replacing_item = p_item;
|
||||||
|
_setup_search_file_dialog(replacement_file_dialog, missing_path, missing_type);
|
||||||
|
replacement_file_dialog->popup_file_dialog();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case BUTTON_ID_OPEN_DEPS_EDITOR: {
|
||||||
|
const String &owner_path = p_item->get_metadata(0);
|
||||||
|
if (deps_editor == nullptr) {
|
||||||
|
deps_editor = memnew(DependencyEditor);
|
||||||
|
deps_editor->connect(SceneStringName(visibility_changed), callable_mp(this, &DependencyErrorDialog::_check_for_resolved));
|
||||||
|
add_child(deps_editor);
|
||||||
|
}
|
||||||
|
deps_editor->edit(owner_path);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DependencyErrorDialog::_on_replacement_file_selected(const String &p_path) {
|
||||||
|
const String &missing_path = String(replacing_item->get_metadata(0)).get_slice("::", 0);
|
||||||
|
|
||||||
|
for (TreeItem *owner_ti = replacing_item->get_first_child(); owner_ti; owner_ti = owner_ti->get_next()) {
|
||||||
|
const String &owner_path = owner_ti->get_metadata(0);
|
||||||
|
ResourceLoader::rename_dependencies(owner_path, { { missing_path, p_path } });
|
||||||
|
}
|
||||||
|
|
||||||
|
_check_for_resolved();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DependencyErrorDialog::_check_for_resolved() {
|
||||||
|
if (deps_editor && deps_editor->is_visible()) {
|
||||||
|
return; // Only update when the dialog is closed.
|
||||||
|
}
|
||||||
|
|
||||||
|
errors_fixed = true;
|
||||||
|
HashMap<String, LocalVector<String>> owner_deps;
|
||||||
|
|
||||||
|
TreeItem *root = files->get_root();
|
||||||
|
for (TreeItem *missing_ti = root->get_first_child(); missing_ti; missing_ti = missing_ti->get_next()) {
|
||||||
|
bool all_owners_fixed = true;
|
||||||
|
|
||||||
|
for (TreeItem *owner_ti = missing_ti->get_first_child(); owner_ti; owner_ti = owner_ti->get_next()) {
|
||||||
|
const String &owner_path = owner_ti->get_metadata(0);
|
||||||
|
|
||||||
|
if (!owner_deps.has(owner_path)) {
|
||||||
|
List<String> deps;
|
||||||
|
ResourceLoader::get_dependencies(owner_path, &deps);
|
||||||
|
|
||||||
|
LocalVector<String> &stored_paths = owner_deps[owner_path];
|
||||||
|
for (const String &dep : deps) {
|
||||||
|
if (!errors_fixed && !FileAccess::exists(_get_resolved_dep_path(dep))) {
|
||||||
|
errors_fixed = false;
|
||||||
|
}
|
||||||
|
stored_paths.push_back(_get_stored_dep_path(dep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const LocalVector<String> &stored_paths = owner_deps[owner_path];
|
||||||
|
const String &missing_path = String(missing_ti->get_metadata(0)).get_slice("::", 0);
|
||||||
|
|
||||||
|
if (stored_paths.has(missing_path)) {
|
||||||
|
all_owners_fixed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
missing_ti->set_icon(1, get_editor_theme_icon(all_owners_fixed ? icon_name_check : icon_name_fail));
|
||||||
|
}
|
||||||
|
|
||||||
|
set_ok_button_text(errors_fixed ? TTRC("Open") : TTRC("Open Anyway"));
|
||||||
}
|
}
|
||||||
|
|
||||||
DependencyErrorDialog::DependencyErrorDialog() {
|
DependencyErrorDialog::DependencyErrorDialog() {
|
||||||
|
icon_name_fail = StringName("ImportFail");
|
||||||
|
icon_name_check = StringName("ImportCheck");
|
||||||
|
|
||||||
VBoxContainer *vb = memnew(VBoxContainer);
|
VBoxContainer *vb = memnew(VBoxContainer);
|
||||||
add_child(vb);
|
add_child(vb);
|
||||||
|
|
||||||
files = memnew(Tree);
|
files = memnew(Tree);
|
||||||
files->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
|
||||||
files->set_hide_root(true);
|
files->set_hide_root(true);
|
||||||
vb->add_margin_child(TTR("Load failed due to missing dependencies:"), files, true);
|
files->set_select_mode(Tree::SELECT_ROW);
|
||||||
|
files->set_columns(2);
|
||||||
|
files->set_column_expand(1, false);
|
||||||
files->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
files->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
|
files->connect("button_clicked", callable_mp(this, &DependencyErrorDialog::_on_files_button_clicked));
|
||||||
|
vb->add_margin_child(TTRC("Load failed due to missing dependencies:"), files, true);
|
||||||
|
|
||||||
set_min_size(Size2(500, 220) * EDSCALE);
|
set_min_size(Size2(500, 320) * EDSCALE);
|
||||||
set_ok_button_text(TTR("Open Anyway"));
|
set_cancel_button_text(TTRC("Close"));
|
||||||
set_cancel_button_text(TTR("Close"));
|
|
||||||
|
|
||||||
text = memnew(Label);
|
Label *text = memnew(Label(TTRC("Which action should be taken?")));
|
||||||
text->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
|
text->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
|
||||||
vb->add_child(text);
|
vb->add_child(text);
|
||||||
text->set_text(TTR("Which action should be taken?"));
|
|
||||||
|
|
||||||
fdep = add_button(TTR("Fix Dependencies"), true, "fixdeps");
|
|
||||||
|
|
||||||
set_title(TTR("Errors loading!"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -30,13 +30,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "scene/gui/box_container.h"
|
|
||||||
#include "scene/gui/dialogs.h"
|
#include "scene/gui/dialogs.h"
|
||||||
#include "scene/gui/item_list.h"
|
|
||||||
#include "scene/gui/tree.h"
|
|
||||||
|
|
||||||
class EditorFileDialog;
|
class EditorFileDialog;
|
||||||
class EditorFileSystemDirectory;
|
class EditorFileSystemDirectory;
|
||||||
|
class ItemList;
|
||||||
|
class PopupMenu;
|
||||||
|
class Tree;
|
||||||
|
class TreeItem;
|
||||||
|
class VBoxContainer;
|
||||||
|
|
||||||
class DependencyEditor : public AcceptDialog {
|
class DependencyEditor : public AcceptDialog {
|
||||||
GDCLASS(DependencyEditor, AcceptDialog);
|
GDCLASS(DependencyEditor, AcceptDialog);
|
||||||
@@ -139,17 +141,28 @@ public:
|
|||||||
class DependencyErrorDialog : public ConfirmationDialog {
|
class DependencyErrorDialog : public ConfirmationDialog {
|
||||||
GDCLASS(DependencyErrorDialog, ConfirmationDialog);
|
GDCLASS(DependencyErrorDialog, ConfirmationDialog);
|
||||||
|
|
||||||
private:
|
StringName icon_name_fail;
|
||||||
|
StringName icon_name_check;
|
||||||
|
|
||||||
String for_file;
|
String for_file;
|
||||||
Mode mode;
|
|
||||||
Button *fdep = nullptr;
|
TreeItem *replacing_item = nullptr;
|
||||||
Label *text = nullptr;
|
bool errors_fixed = false;
|
||||||
|
|
||||||
Tree *files = nullptr;
|
Tree *files = nullptr;
|
||||||
|
|
||||||
|
EditorFileDialog *replacement_file_dialog = nullptr;
|
||||||
|
DependencyEditor *deps_editor = nullptr;
|
||||||
|
|
||||||
void ok_pressed() override;
|
void ok_pressed() override;
|
||||||
void custom_action(const String &) override;
|
|
||||||
|
void _on_files_button_clicked(TreeItem *p_item, int p_column, int p_id, MouseButton p_button);
|
||||||
|
void _on_replacement_file_selected(const String &p_path);
|
||||||
|
void _check_for_resolved();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void show(const String &p_for_file, const Vector<String> &report);
|
void show(const String &p_for_file, const HashMap<String, HashSet<String>> &p_report);
|
||||||
|
|
||||||
DependencyErrorDialog();
|
DependencyErrorDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user