mirror of
https://github.com/Relintai/godot_data_editor.git
synced 2024-11-13 06:27:19 +01:00
406 lines
15 KiB
GDScript
406 lines
15 KiB
GDScript
tool
|
|
extends Control
|
|
|
|
var selected_item = null
|
|
var selected_id = null
|
|
var selected_class = null
|
|
|
|
|
|
onready var item_tree = get_node("VBox/Body/ItemTree")
|
|
onready var id_label = get_node("VBox/Body/Content/VBox/Container/ItemIdLabel")
|
|
|
|
onready var instance_details = get_node("VBox/Body/Content/VBox/InstanceDetails/")
|
|
onready var class_properties = get_node("VBox/Body/Content/VBox/InstanceDetails/HBox/ClassProperties")
|
|
onready var custom_properties = get_node("VBox/Body/Content/VBox/InstanceDetails/HBox/CustomProperties")
|
|
onready var class_overview = get_node("VBox/Body/Content/VBox/ClassOverview")
|
|
onready var no_classes = get_node("VBox/Body/Content/VBox/NoClasses")
|
|
|
|
#onready var last_modified_date = get_node("VBox/Body/Content/VBox/Container/GridContainer/LastModifiedDate")
|
|
#onready var created_date = get_node("VBox/Body/Content/VBox/Container/GridContainer/CreatedDate")
|
|
|
|
|
|
onready var new_custom_property_dialog = get_node("NewCustomPropertyDialog")
|
|
onready var new_custom_property_name = get_node("NewCustomPropertyDialog/LineEdit")
|
|
onready var new_custom_property_type_options = get_node("NewCustomPropertyDialog/TypeOptions")
|
|
|
|
onready var add_button = get_node("VBox/Head/Add")
|
|
onready var delete_button = get_node("VBox/Head/Delete")
|
|
onready var duplicate_button = get_node("VBox/Head/Duplicate")
|
|
onready var change_display_name_button = get_node("VBox/Body/Content/VBox/Container/HBox/DisplayName")
|
|
onready var rename_button = get_node("VBox/Head/Rename")
|
|
onready var save_button = get_node("VBox/Head/Save")
|
|
onready var save_all_button = get_node("VBox/Head/SaveAll")
|
|
|
|
onready var copy_id_button = get_node("VBox/Body/Content/VBox/Container/HBox/CopyId")
|
|
onready var edit_class_button = get_node("VBox/Body/Content/VBox/Container/HBox/EditClass")
|
|
|
|
# Dialogs
|
|
onready var input_dialog = get_node("InputDialog")
|
|
|
|
onready var new_item_class_dialog = get_node("NewClassDialog")
|
|
onready var new_item_class_name = get_node("NewClassDialog/ClassName")
|
|
onready var new_item_class_icon = get_node("NewClassDialog/ClassIconPath")
|
|
onready var new_item_class_icon_dialog = get_node("NewClassDialog/ClassIconFileDialog")
|
|
|
|
|
|
onready var warn_dialog = get_node("WarnDialog")
|
|
onready var options_screen = get_node("OptionsDialog")
|
|
|
|
var item_tree_class = preload("item_tree.tscn")
|
|
#var active_element = null
|
|
var item_manager = null
|
|
|
|
signal class_edit_requested(script)
|
|
signal input_dialog_confirmed(text1, text2)
|
|
|
|
# First initialize the item manager which is used for loading, saving and configs
|
|
func _init():
|
|
item_manager = preload("item_manager.gd").new() # This item_manager will add itself to the globals
|
|
|
|
func _ready():
|
|
Globals.set("debug_is_editor", false)
|
|
# Tree signals
|
|
item_tree.connect("on_new_item_pressed", self, "handle_actions", ["add"])
|
|
item_tree.connect("on_rename_pressed", self, "handle_actions", ["rename"])
|
|
item_tree.connect("on_delete_pressed", self, "handle_actions", ["delete"])
|
|
item_tree.connect("on_duplicate_pressed", self, "handle_actions", ["duplicate"])
|
|
item_tree.connect("on_item_selected", self, "change_item_context", [])
|
|
item_tree.connect("on_open", self, "open_item", [])
|
|
|
|
custom_properties.connect("custom_property_add_requested", self, "handle_actions", ["add_custom_property"])
|
|
custom_properties.connect("new_custom_property_created", self, "handle_actions", ["add_custom_property"])
|
|
custom_properties.connect("custom_property_delete_requested", self, "delete_custom_property", [])
|
|
class_properties.connect("on_item_changed", self, "toggle_item_dirty_state", [])
|
|
|
|
options_screen.connect("extension_changed", item_manager, "rename_extension_of_all_items", [])
|
|
options_screen.connect("encryption_changed", item_manager, "delete_and_resave", [])
|
|
|
|
item_manager.connect("class_insertion_failed", self, "show_warning", [])
|
|
item_manager.connect("item_insertion_failed", self, "show_warning", [])
|
|
item_manager.connect("custom_property_insertion_failed", self, "show_warning", [])
|
|
item_manager.connect("item_duplication_failed", self, "show_warning", [])
|
|
# item_manager.connect("class_is_invalid", self, "show_warning", [])
|
|
|
|
# Add types to the custom property type dropdown
|
|
var type_names = item_manager.type_names.keys()
|
|
type_names.sort()
|
|
new_custom_property_type_options.clear()
|
|
var index = 0
|
|
for type in type_names:
|
|
new_custom_property_type_options.add_item(type)
|
|
new_custom_property_type_options.set_item_metadata(index, item_manager.type_names[type])
|
|
index += 1
|
|
|
|
# No classes available
|
|
var has_no_classes = item_manager.classes.size() == 0
|
|
if has_no_classes:
|
|
change_display_name_button.set_disabled(has_no_classes)
|
|
duplicate_button.set_disabled(true)
|
|
save_button.set_disabled(true)
|
|
save_all_button.set_disabled(true)
|
|
save_all_button.set_disabled(true)
|
|
rename_button.set_disabled(true)
|
|
add_button.set_disabled(true)
|
|
delete_button.set_disabled(true)
|
|
copy_id_button.set_disabled(true)
|
|
edit_class_button.set_disabled(true)
|
|
no_classes.show()
|
|
id_label.set_text("No Classes")
|
|
instance_details.hide()
|
|
class_overview.hide()
|
|
else:
|
|
# Select the first item in the tree when loading the GUI
|
|
var all_classes = item_manager.classes.keys()
|
|
all_classes.sort()
|
|
selected_class = all_classes[0]
|
|
change_item_context(selected_item, selected_class)
|
|
|
|
# TODO: Implement
|
|
func open_item():
|
|
var item_path = item_manager.get_full_path(selected_item)
|
|
var program = ""
|
|
var os_name = OS.get_name()
|
|
if os_name == "Windows":
|
|
program = "explorer"
|
|
item_path = item_path.replace("/", "\\") # ~_~...
|
|
# TODO: Not sure if these work... Probably add the possibility to add a custom editor
|
|
elif os_name == "OSX":
|
|
program = "open"
|
|
else:
|
|
program = "nautilus"
|
|
OS.execute(program, [item_path], false)
|
|
|
|
func change_item_context(selected_item, selected_class):
|
|
|
|
if selected_class:
|
|
self.selected_class = selected_class
|
|
|
|
|
|
|
|
# TODO: Move to method, clean up
|
|
var has_no_classes = item_manager.classes.size() == 0
|
|
if has_no_classes:
|
|
change_display_name_button.set_disabled(has_no_classes)
|
|
duplicate_button.set_disabled(true)
|
|
save_button.set_disabled(true)
|
|
save_all_button.set_disabled(true)
|
|
save_all_button.set_disabled(true)
|
|
rename_button.set_disabled(true)
|
|
add_button.set_disabled(true)
|
|
delete_button.set_disabled(true)
|
|
copy_id_button.set_disabled(true)
|
|
edit_class_button.set_disabled(true)
|
|
no_classes.show()
|
|
instance_details.hide()
|
|
class_overview.hide()
|
|
id_label.set_text("No Classes")
|
|
|
|
|
|
# An item was selected
|
|
if selected_item:
|
|
# Context was lost, e.g. because of changes to the classes. Reload.
|
|
if selected_item and not selected_item.get("_id"):
|
|
self.item_manager.load_manager()
|
|
self.item_tree.load_tree(true)
|
|
selected_item = item_tree.select_first_element()
|
|
|
|
change_display_name_button.set_disabled(false)
|
|
duplicate_button.set_disabled(false)
|
|
save_button.set_disabled(false)
|
|
save_all_button.set_disabled(false)
|
|
rename_button.set_disabled(false)
|
|
add_button.set_disabled(false)
|
|
delete_button.set_disabled(false)
|
|
copy_id_button.set_disabled(false)
|
|
edit_class_button.set_disabled(false)
|
|
|
|
self.selected_item = selected_item
|
|
self.selected_id = selected_item._id
|
|
class_overview.hide()
|
|
no_classes.hide()
|
|
instance_details.show()
|
|
if selected_item._display_name == selected_id:
|
|
id_label.set_text(selected_id)
|
|
else:
|
|
id_label.set_text(selected_item._display_name + " (" + selected_id + ")")
|
|
|
|
class_properties.build_properties(selected_item)
|
|
custom_properties.build_properties(selected_item)
|
|
# A class was selected
|
|
elif selected_class:
|
|
change_display_name_button.set_disabled(true)
|
|
duplicate_button.set_disabled(true)
|
|
save_button.set_disabled(true)
|
|
save_all_button.set_disabled(false)
|
|
rename_button.set_disabled(false)
|
|
add_button.set_disabled(false)
|
|
delete_button.set_disabled(false)
|
|
copy_id_button.set_disabled(false)
|
|
edit_class_button.set_disabled(false)
|
|
self.selected_item = null
|
|
self.selected_id = null
|
|
id_label.set_text(selected_class.capitalize())
|
|
if item_manager.invalid_classes.has(selected_class):
|
|
class_overview.set_label("There is a problem with this class, please check if there are any issues. Press 'Reload' once you are ready.")
|
|
else:
|
|
class_overview.set_label("")
|
|
class_overview.show()
|
|
instance_details.hide()
|
|
no_classes.hide()
|
|
|
|
|
|
|
|
func _on_ItemTree_on_new_item_created(new_item):
|
|
selected_item = new_item
|
|
|
|
|
|
func create_shortcut(keys):
|
|
var short_cut = ShortCut.new()
|
|
var input_event = InputEvent()
|
|
input_event.type = InputEvent.KEY
|
|
input_event.ID = keys
|
|
short_cut.set_shortcut(input_event)
|
|
|
|
# TODO: Implement
|
|
func warn_about_reload():
|
|
if item_manager.has_unsaved_items():
|
|
input_dialog.popup(self, "reload_confirmed", tr("Confirm reload"), tr("Some changes have not been saved. \nThey will be discarded if you proceed. Are you sure you want to perform this action?"))
|
|
|
|
|
|
func reload():
|
|
item_manager.load_manager()
|
|
item_tree.load_tree(true)
|
|
if item_manager.get_item(selected_class, selected_id):
|
|
item_tree.select_item(item_manager.get_item(selected_class, selected_id))
|
|
|
|
|
|
func toggle_item_dirty_state(item):
|
|
item._dirty = true
|
|
item_tree.set_tree_item_label_text(item)
|
|
|
|
|
|
# Validation takes place in the item manager
|
|
func _on_NewCustomPropertyDialog_confirmed():
|
|
var custom_property_id = new_custom_property_name.get_text().strip_edges()
|
|
var custom_property_type = new_custom_property_type_options.get_selected_metadata()
|
|
var success = item_manager.add_custom_property(selected_item, custom_property_id, custom_property_type)
|
|
if success:
|
|
item_tree.set_tree_item_label_text(selected_item)
|
|
toggle_item_dirty_state(selected_item)
|
|
custom_properties.build_properties(selected_item)
|
|
|
|
|
|
# TODO: Show confirmation dialog
|
|
func delete_custom_property(property_name):
|
|
item_manager.delete_custom_property(selected_item, property_name)
|
|
toggle_item_dirty_state(selected_item)
|
|
custom_properties.build_properties(selected_item)
|
|
|
|
|
|
# TODO: New Class Dialog is still a mess
|
|
func _on_AddClassButton_button_down():
|
|
new_item_class_name.set_text("")
|
|
new_item_class_icon.set_text("")
|
|
new_item_class_icon_dialog.set_current_path("")
|
|
new_item_class_dialog.popup_centered()
|
|
new_item_class_name.grab_focus()
|
|
|
|
|
|
func _on_NewClassDialog_confirmed():
|
|
var name = new_item_class_name.get_text().to_lower()
|
|
var icon_path = new_item_class_icon.get_text()
|
|
item_manager.create_class(name, icon_path)
|
|
item_tree.load_tree()
|
|
item_tree.select_class(name)
|
|
reload()
|
|
edit_class()
|
|
|
|
|
|
# New Class Dialog
|
|
func _on_NewClassIconSearchButton_button_down():
|
|
new_item_class_icon_dialog.popup_centered()
|
|
|
|
# Icon for new class was selected
|
|
func _on_NewClassIconFileDialog_file_selected(path):
|
|
new_item_class_icon.set_text(path)
|
|
|
|
# General handler for a lot of actions to centralize the GUI logic a bit
|
|
func handle_actions(action, argument = ""):
|
|
if action == "add":
|
|
input_dialog.popup(self, "_on_add_item_confirmed", tr("New Item"), tr("Please enter an ID for and optionally a display name the new item"), tr("ID"), "", tr("Display Name (optional)"), "")
|
|
elif action == "rename":
|
|
if selected_item:
|
|
input_dialog.popup(self, "_on_rename_item_confirmed", tr("Rename Item"), tr("Please enter a new ID for this item."), "ID", selected_id)
|
|
else:
|
|
input_dialog.popup(self, "_on_rename_class_confirmed", tr("Rename Class"), tr("Please enter a new name for this class. All pending changes will be discarded!"), "ID", selected_class)
|
|
elif action == "duplicate":
|
|
var new_display_name = ""
|
|
if selected_item._dirty:
|
|
input_dialog.popup(self, "item_duplication_failed", tr("Item duplication failed"), tr("Before duplicating this item, please first save it."))
|
|
return
|
|
selected_item._display_name = ""
|
|
input_dialog.popup(self, "_on_duplicate_confirmed", tr("Duplicate Item"), tr("Please enter a new ID for this item"), "ID", selected_id, tr("Display Name (optional)"), new_display_name)
|
|
elif action == "save":
|
|
item_manager.save_item(selected_item)
|
|
item_tree.load_tree()
|
|
#reload()
|
|
elif action == "save_all":
|
|
item_manager.save_all_items()
|
|
item_tree.load_tree()
|
|
#reload()
|
|
elif action == "reload":
|
|
item_manager.load_manager()
|
|
reload()
|
|
elif action == "new_class":
|
|
_on_AddClassButton_button_down() # TODO: Incorporate into dialog handling
|
|
elif action == "delete":
|
|
if selected_item:
|
|
input_dialog.popup(self, "_on_delete_item_confirmed", tr("Delete Item"), tr("Are you sure you want to delete this item?"))
|
|
else:
|
|
input_dialog.popup(self, "_on_delete_class_confirmed", tr("Delete Class"), tr("Are you sure you want to delete class along with all items?"))
|
|
elif action == "options":
|
|
options_screen.popup_centered()
|
|
elif action == "edit_class":
|
|
edit_class()
|
|
elif action == "copy_id":
|
|
copy_id()
|
|
elif action == "change_display_name":
|
|
input_dialog.popup(self, "change_display_name", tr("Change Display Name"), tr("Please enter a display name for this item."), "Display Name", selected_item._display_name)
|
|
elif action == "add_custom_property":
|
|
new_custom_property_name.set_text("")
|
|
new_custom_property_dialog.popup_centered()
|
|
new_custom_property_name.grab_focus()
|
|
|
|
#########################################################################
|
|
# Handlers #
|
|
#########################################################################
|
|
|
|
func _on_add_item_confirmed(id, display_name):
|
|
var new_item = item_manager.create_and_add_new_item(selected_class, id, display_name)
|
|
if new_item:
|
|
item_tree.add_leaf(new_item, true)
|
|
|
|
|
|
func _on_rename_item_confirmed(id):
|
|
item_manager.rename_item(selected_item, id)
|
|
reload()
|
|
|
|
|
|
func _on_rename_class_confirmed(name):
|
|
item_manager.rename_class(selected_class, name)
|
|
reload()
|
|
|
|
|
|
func _on_duplicate_confirmed(id, display_name):
|
|
var duplicated_item = item_manager.duplicate_item(selected_item, id, display_name, false)
|
|
item_tree.add_leaf(duplicated_item, true)
|
|
reload()
|
|
|
|
func _on_delete_item_confirmed():
|
|
item_manager.delete_item(selected_item)
|
|
reload()
|
|
|
|
|
|
func _on_delete_class_confirmed():
|
|
item_manager.delete_class(selected_class)
|
|
if item_manager.classes.size() > 0:
|
|
item_tree.select_class(item_manager.class_names[0])
|
|
else:
|
|
change_item_context(null, null)
|
|
reload()
|
|
|
|
#########################################################################
|
|
# Buttons on the right #
|
|
#########################################################################
|
|
func change_display_name(new_name):
|
|
selected_item._display_name = new_name
|
|
toggle_item_dirty_state(selected_item)
|
|
change_item_context(selected_item, selected_class)
|
|
|
|
func copy_id():
|
|
if selected_item:
|
|
OS.set_clipboard(selected_id)
|
|
else:
|
|
OS.set_clipboard(selected_class)
|
|
|
|
func edit_class():
|
|
var script = item_manager.classes[selected_class]
|
|
emit_signal("class_edit_requested", script)
|
|
|
|
#####################################################
|
|
# OTHERS
|
|
#####################################################
|
|
|
|
func show_warning(title, text):
|
|
warn_dialog.set_title(title)
|
|
warn_dialog.set_text(text)
|
|
warn_dialog.popup_centered()
|
|
|
|
|
|
func log_text(text):
|
|
var file = File.new()
|
|
file.open("res://test.log", File.READ_WRITE)
|
|
var old_text = file.get_as_text()
|
|
var date = str(OS.get_datetime()["hour"]) + ":" + str(OS.get_datetime()["minute"]) + ":" + str(OS.get_datetime()["second"]) + "\t"
|
|
file.store_line(old_text + date + text)
|