From e59a634881ecef6f68d3a17bea4639d5f424bfa5 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Fri, 22 Sep 2023 16:36:49 +0200 Subject: [PATCH 01/16] [plugin|licenses] Stop export if license file does not exist --- addons/licenses/export_plugin.gd | 4 +++- addons/licenses/plugin.cfg | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/licenses/export_plugin.gd b/addons/licenses/export_plugin.gd index fe7c14f..2d2e60c 100644 --- a/addons/licenses/export_plugin.gd +++ b/addons/licenses/export_plugin.gd @@ -6,11 +6,13 @@ func _get_name() -> String: return "kenyoni_licenses_exporter" func _export_begin(features: PackedStringArray, is_debug: bool, path: String, flags: int) -> void: + if not FileAccess.file_exists(Licenses.get_license_data_filepath()): + return + self._add_file(Licenses.get_license_data_filepath()) var res = Licenses.load(Licenses.get_license_data_filepath()) if res.err_msg != "": push_error("Failed to export license files: " + res.err_msg) return - self._add_file(Licenses.get_license_data_filepath()) for component in res.components: for license in component.licenses: if license.file != "": diff --git a/addons/licenses/plugin.cfg b/addons/licenses/plugin.cfg index 9f760be..4467ad1 100644 --- a/addons/licenses/plugin.cfg +++ b/addons/licenses/plugin.cfg @@ -3,5 +3,5 @@ name="Licenses" description="MIT License" author="Iceflower S" -version="1.4.1" +version="1.4.2" script="plugin.gd" From 11ebeb2e6e5f2ade1afe5b6a2d5c6707d939bb56 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Fri, 22 Sep 2023 16:37:27 +0200 Subject: [PATCH 02/16] [plugin|licenses] Use integer function instead of float --- addons/licenses/internal/handler/string_multiline.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/licenses/internal/handler/string_multiline.gd b/addons/licenses/internal/handler/string_multiline.gd index eb3a679..cc9b299 100644 --- a/addons/licenses/internal/handler/string_multiline.gd +++ b/addons/licenses/internal/handler/string_multiline.gd @@ -6,7 +6,7 @@ func _init(tree_: Tree, item_: TreeItem, value_: Variant, property_: Dictionary) super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_text(1, self.value) - self.item.set_tooltip_text(1, self.value.substr(0, min(len(self.value), 512)) + "...") + self.item.set_tooltip_text(1, self.value.substr(0, mini(self.value.length(), 512)) + "...") self._update_reset_button() self.item.add_button(1, self.tree.get_theme_icon("DistractionFree", "EditorIcons"), 1) From 7f096258ec3d6f2340dc07b700ab696655203d61 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Sun, 24 Sep 2023 21:29:36 +0200 Subject: [PATCH 03/16] [plugin|licenses] Do not override engine methods Fixes: #5 --- addons/licenses/component.gd | 52 +++++++++++++--------- addons/licenses/internal/handler/object.gd | 7 ++- addons/licenses/internal/utils.gd | 10 +++++ 3 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 addons/licenses/internal/utils.gd diff --git a/addons/licenses/component.gd b/addons/licenses/component.gd index bcfecf5..4da52b6 100644 --- a/addons/licenses/component.gd +++ b/addons/licenses/component.gd @@ -16,14 +16,19 @@ class License: ## Web present of the license var web: String - func get_property_list() -> Array: - var properties: Array = super.get_property_list() - for property in properties: - if property["name"] == "text": - property["hint"] = PROPERTY_HINT_MULTILINE_TEXT - if property["name"] == "file": - property["hint"] = PROPERTY_HINT_FILE - return properties + func _get_property_list() -> Array[Dictionary]: + return [ + { + "name": "text", + "type": TYPE_STRING, + "hint": PROPERTY_HINT_MULTILINE_TEXT, + }, + { + "name": "file", + "type": TYPE_STRING, + "hint": PROPERTY_HINT_FILE, + } + ] ## Either returns the license text or loads the text from file or a message that the text could not be loaded. func get_license_text() -> String: @@ -75,18 +80,25 @@ var web: String var paths: PackedStringArray = [] var licenses: Array[License] = [] -func get_property_list() -> Array: - var properties: Array = super.get_property_list() - for property in properties: - if property["name"] == "paths": - property["hint"] = PROPERTY_HINT_FILE - # allow files too (inofficial) - property["hint_text"] = "*" - if property["name"] == "description": - property["hint"] = PROPERTY_HINT_MULTILINE_TEXT - if property["name"] == "licenses": - property["constructor"] = License.new - return properties +func _get_property_list() -> Array: + return [ + { + "name": "paths", + "type": TYPE_PACKED_STRING_ARRAY, + "hint": PROPERTY_HINT_FILE, + "hint_text": "*", + }, + { + "name": "description", + "type": TYPE_STRING, + "hint": PROPERTY_HINT_MULTILINE_TEXT, + }, + { + "name": "licenses", + "type": TYPE_ARRAY, + "constructor": License.new, + }, + ] func serialize() -> Dictionary: var licenses: Array[Dictionary] = [] diff --git a/addons/licenses/internal/handler/object.gd b/addons/licenses/internal/handler/object.gd index 18158af..4eec2da 100644 --- a/addons/licenses/internal/handler/object.gd +++ b/addons/licenses/internal/handler/object.gd @@ -1,11 +1,14 @@ extends "base.gd" +const Utils := preload("../utils.gd") + func _init(tree_: Tree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_selectable(1, false) - for prop in self.value.get_property_list(): - # ignore private variables and ignore non supported types + + for prop in Utils.get_updated_property_list(self.value): + # ignore private variables and ignore non supported types and already added items if prop["name"].begins_with("_"): continue self.tree._add_item(self.item, self.value.get(prop["name"]), prop) diff --git a/addons/licenses/internal/utils.gd b/addons/licenses/internal/utils.gd new file mode 100644 index 0000000..4dabfff --- /dev/null +++ b/addons/licenses/internal/utils.gd @@ -0,0 +1,10 @@ +static func get_updated_property_list(object: Object) -> Array: + var properties: Array = object.get_property_list() + var patched_properties: Array = object._get_property_list() + properties = properties.slice(0, properties.size() - patched_properties.size()) + for p_prop_idx in range(patched_properties.size()): + for prop_idx in range(properties.size()): + if properties[prop_idx]["name"] == patched_properties[p_prop_idx]["name"]: + properties[prop_idx] = patched_properties[p_prop_idx] + break + return properties From bd606838d6bffdf606c2053c388da31514a75a6e Mon Sep 17 00:00:00 2001 From: Iceflower Date: Sun, 24 Sep 2023 21:30:36 +0200 Subject: [PATCH 04/16] [plugin|licenses] Remove call to not existent function --- addons/licenses/internal/components_tree.gd | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index f96d7c2..10d5a82 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -138,7 +138,6 @@ func _drop_data(at_position: Vector2, data: Variant) -> void: if cur_component.category == category: return cur_component.category = category - Licenses.sort_components() self.licenses.sort_custom(Licenses.new().compare_components_ascending) self.reload(cur_component) From af69621296d5b39236f725d0d191b45b8a42458c Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 12:34:44 +0200 Subject: [PATCH 05/16] [plugin|licenses] Add plugin path to paths --- addons/licenses/internal/toolbar.gd | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/licenses/internal/toolbar.gd b/addons/licenses/internal/toolbar.gd index df1513d..3b7efcb 100644 --- a/addons/licenses/internal/toolbar.gd +++ b/addons/licenses/internal/toolbar.gd @@ -123,6 +123,7 @@ func _on_plugin_add_id_pressed(id: int) -> void: component.description = cfg["plugin"].get("description", "") component.copyright.append(cfg["plugin"].get("author", "")) component.version = cfg["plugin"].get("version", "") + component.paths.append(self._add_plugin_menu.get_item_metadata(id).get_base_dir()) self._components_tree.licenses.append(component) self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) self._components_tree.reload(component) From de14cc67d5cb6bc5b565ebc2e228f7d03ee82aa9 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 13:25:03 +0200 Subject: [PATCH 06/16] [plugin|licenses] Fix several bugs and refactor --- addons/licenses/internal/component_detail_tree.gd | 6 ++++-- addons/licenses/internal/components_tree.gd | 2 ++ addons/licenses/internal/handler/array.gd | 2 +- addons/licenses/internal/handler/base.gd | 1 + addons/licenses/internal/handler/object.gd | 2 +- addons/licenses/internal/handler/string.gd | 2 +- addons/licenses/internal/handler/string_file.gd | 2 +- addons/licenses/internal/handler/string_multiline.gd | 2 +- addons/licenses/internal/toolbar.gd | 4 ++-- 9 files changed, 14 insertions(+), 9 deletions(-) diff --git a/addons/licenses/internal/component_detail_tree.gd b/addons/licenses/internal/component_detail_tree.gd index 766a64a..4afb1cc 100644 --- a/addons/licenses/internal/component_detail_tree.gd +++ b/addons/licenses/internal/component_detail_tree.gd @@ -11,7 +11,9 @@ enum BUTTON_ID { FILE_DIALOG = 3 } -var _component: Component : get = get_component, set = set_component +var _component: Component : + set = set_component, + get = get_component var handlers: Array = [] var _selected_item: TreeItem = null @@ -67,7 +69,7 @@ func _on_item_edited(item: TreeItem = null) -> void: if parent != null: parent.get_meta("handler").child_edited(item) - self.emit_signal("component_edited", self._component) + self.component_edited.emit(self._component) func _get_handler(property: Dictionary) -> GDScript: for handler in self.handlers: diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index 10d5a82..6be6b27 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -112,6 +112,8 @@ func _can_drop_data(at_position: Vector2, data: Variant) -> bool: func _get_drag_data(at_position: Vector2) -> Variant: var item: TreeItem = self.get_item_at_position(at_position) + if item == null: + return null if not item.has_meta("idx") or item.get_meta("readonly"): return null diff --git a/addons/licenses/internal/handler/array.gd b/addons/licenses/internal/handler/array.gd index a87f758..d2d7a9d 100644 --- a/addons/licenses/internal/handler/array.gd +++ b/addons/licenses/internal/handler/array.gd @@ -2,7 +2,7 @@ extends "base.gd" var _constructor: Callable -func _init(tree_: Tree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: +func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_text(1, "[ " + str(len(self.value)) + " ]") diff --git a/addons/licenses/internal/handler/base.gd b/addons/licenses/internal/handler/base.gd index c456c06..dc07ac1 100644 --- a/addons/licenses/internal/handler/base.gd +++ b/addons/licenses/internal/handler/base.gd @@ -8,6 +8,7 @@ var property: Dictionary var value: Variant func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: + assert(item_ != null, "item must not null") self.tree = tree_ self.item = item_ self.property = property_ diff --git a/addons/licenses/internal/handler/object.gd b/addons/licenses/internal/handler/object.gd index 4eec2da..30db819 100644 --- a/addons/licenses/internal/handler/object.gd +++ b/addons/licenses/internal/handler/object.gd @@ -2,7 +2,7 @@ extends "base.gd" const Utils := preload("../utils.gd") -func _init(tree_: Tree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: +func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_selectable(1, false) diff --git a/addons/licenses/internal/handler/string.gd b/addons/licenses/internal/handler/string.gd index 48759aa..5b62727 100644 --- a/addons/licenses/internal/handler/string.gd +++ b/addons/licenses/internal/handler/string.gd @@ -1,6 +1,6 @@ extends "base.gd" -func _init(tree_: Tree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: +func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_text(1, value_) diff --git a/addons/licenses/internal/handler/string_file.gd b/addons/licenses/internal/handler/string_file.gd index b9b389b..a8a9619 100644 --- a/addons/licenses/internal/handler/string_file.gd +++ b/addons/licenses/internal/handler/string_file.gd @@ -1,6 +1,6 @@ extends "base.gd" -func _init(tree_: Tree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: +func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_text(1, self.value) diff --git a/addons/licenses/internal/handler/string_multiline.gd b/addons/licenses/internal/handler/string_multiline.gd index cc9b299..44d9995 100644 --- a/addons/licenses/internal/handler/string_multiline.gd +++ b/addons/licenses/internal/handler/string_multiline.gd @@ -2,7 +2,7 @@ extends "base.gd" var _dialog: AcceptDialog -func _init(tree_: Tree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: +func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, property_: Dictionary) -> void: super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_text(1, self.value) diff --git a/addons/licenses/internal/toolbar.gd b/addons/licenses/internal/toolbar.gd index 3b7efcb..bfa3ae1 100644 --- a/addons/licenses/internal/toolbar.gd +++ b/addons/licenses/internal/toolbar.gd @@ -86,7 +86,7 @@ func _create_plugin_menu_items() -> void: var idx: int = 0 while (not elem.is_empty()): if dir.current_is_dir(): - var path: String = "res://addons/" + elem + "/plugin.cfg" + var path: String = "res://addons/".path_join(elem).path_join("/plugin.cfg") var cfg: Dictionary = self._get_plugin_config(path) var name: String = cfg.get("plugin", {}).get("name", "") if name != "": @@ -115,7 +115,7 @@ func _on_engine_add_id_pressed(id: int) -> void: self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) self._components_tree.reload(component) -# add license entry based on plugin cfg +# add component entry based on plugin cfg func _on_plugin_add_id_pressed(id: int) -> void: var cfg: Dictionary = self._get_plugin_config(self._add_plugin_menu.get_item_metadata(id)) var component: Component = Component.new() From dbb1b11d1fe4c8bd51508ef4649ea5f9150b98c0 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 13:27:28 +0200 Subject: [PATCH 07/16] [plugin|licenses] Do not reload the tree while blocked --- .../internal/component_detail_tree.gd | 16 +++++----- addons/licenses/internal/components_tree.gd | 31 +++++++++++++------ addons/licenses/internal/toolbar.gd | 8 ++--- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/addons/licenses/internal/component_detail_tree.gd b/addons/licenses/internal/component_detail_tree.gd index 4afb1cc..bbae259 100644 --- a/addons/licenses/internal/component_detail_tree.gd +++ b/addons/licenses/internal/component_detail_tree.gd @@ -17,19 +17,21 @@ var _component: Component : var handlers: Array = [] var _selected_item: TreeItem = null -func _init() -> void: - self.set_column_custom_minimum_width(0, 152) - self.set_column_expand(0, false) - self.set_column_clip_content(1, true) - func set_component(new_component: Component) -> void: + if _component == new_component: + return _component = new_component - self._update_items() + self.reload() func get_component() -> Component: return _component -func _update_items() -> void: +func _init() -> void: + self.set_column_custom_minimum_width(0, 152) + self.set_column_expand(0, false) + self.set_column_clip_content(1, true) + +func reload() -> void: self._selected_item = null self.clear() if self._component == null: diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index 6be6b27..0f9f195 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -32,6 +32,12 @@ func _ready() -> void: self._component_detail.component_edited.connect(self._on_component_edited) self._component_detail.handlers = [ObjectHandler, StringFileHandler, StringMultiLineHandler, StringHandler, ArrayHandler] +# also reloads the view +# do not use internally +func select_component(component: Component) -> void: + self._component_detail.set_component(component) + self.reload() + func get_selected_component() -> Component: return self._component_detail.get_component() @@ -69,8 +75,10 @@ func _add_component(component: Component, category_cache: Dictionary, root: Tree var parent: TreeItem = self._create_category_item(category_cache, component.category, root) return self._add_tree_item(component, idx, parent) -func reload(select_component: Component = null) -> void: +func reload() -> void: self.clear() + if self.get_root() != null: + push_error("could not clear") var category_cache: Dictionary = {} var root: TreeItem = self.create_item(null) @@ -98,13 +106,10 @@ func reload(select_component: Component = null) -> void: readonly_idx = readonly_idx + 1 var item: TreeItem = self._add_component(component, category_cache, root, cur_idx) - if component == select_component: + if component == self._component_detail.get_component(): component_selected = true self.scroll_to_item(item) item.select(0) - self._component_detail.set_component(select_component) - if not component_selected: - self._component_detail.set_component(null) func _can_drop_data(at_position: Vector2, data: Variant) -> bool: var item: TreeItem = self.get_item_at_position(at_position) @@ -141,7 +146,8 @@ func _drop_data(at_position: Vector2, data: Variant) -> void: return cur_component.category = category self.licenses.sort_custom(Licenses.new().compare_components_ascending) - self.reload(cur_component) + self.reload() + self._component_detail.reload() func _on_item_selected() -> void: var item: TreeItem = self.get_selected() @@ -157,15 +163,20 @@ func _on_item_selected() -> void: func _on_button_clicked(item: TreeItem, column: int, id: int, mouse_button_idx: int) -> void: match id: _BTN_ID_REMOVE: + var comp: Component = self.licenses[item.get_meta("idx")] self.licenses.remove_at(item.get_meta("idx")) self.licenses.sort_custom(Licenses.new().compare_components_ascending) Licenses.save(self.licenses, Licenses.get_license_data_filepath()) - self.reload(self._component_detail.get_component()) + # refresh detail view if the current component was removed + if comp == self._component_detail.get_component(): + self._component_detail.set_component(null) + self.reload() +# callback from commponent detail tree func _on_component_edited(component: Component) -> void: self.licenses.sort_custom(Licenses.new().compare_components_ascending) Licenses.save(self.licenses, Licenses.get_license_data_filepath()) - self.reload(component) + self.reload() func _on_item_edited() -> void: var category_item: TreeItem = self.get_edited() @@ -178,4 +189,6 @@ func _on_item_edited() -> void: self.licenses.sort_custom(Licenses.new().compare_components_ascending) Licenses.save(self.licenses, Licenses.get_license_data_filepath()) - self.reload(self._component_detail.get_component()) + call_deferred("reload") + # reload detail view as the category can be changed + self._component_detail.reload() diff --git a/addons/licenses/internal/toolbar.gd b/addons/licenses/internal/toolbar.gd index bfa3ae1..95e9586 100644 --- a/addons/licenses/internal/toolbar.gd +++ b/addons/licenses/internal/toolbar.gd @@ -113,7 +113,7 @@ func _on_engine_add_id_pressed(id: int) -> void: component.readonly = false self._components_tree.licenses.append(component) self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) - self._components_tree.reload(component) + self._components_tree.select_component(component) # add component entry based on plugin cfg func _on_plugin_add_id_pressed(id: int) -> void: @@ -126,14 +126,14 @@ func _on_plugin_add_id_pressed(id: int) -> void: component.paths.append(self._add_plugin_menu.get_item_metadata(id).get_base_dir()) self._components_tree.licenses.append(component) self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) - self._components_tree.reload(component) + self._components_tree.select_component(component) func _on_menu_id_pressed(id: int) -> void: match id: 0: self._menu.toggle_item_checked(0) self._components_tree.show_readonly_components = self._menu.is_item_checked(0) - self._components_tree.reload(self._components_tree.get_selected_component()) + self._components_tree.reload() func _on_add_id_pressed(id: int) -> void: match id: @@ -141,4 +141,4 @@ func _on_add_id_pressed(id: int) -> void: var component: Component = Component.new() self._components_tree.licenses.append(component) self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) - self._components_tree.reload(component) + self._components_tree.select_component(component) From 21fc918a0eac66ea97423c98390984f050fd1098 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 14:27:42 +0200 Subject: [PATCH 08/16] [plugin|licenses] Fix overriding the project license file if another license file was loaded and edited --- addons/licenses/internal/components_tree.gd | 51 +++++++++++++-------- addons/licenses/internal/licenses.gd | 9 ++-- addons/licenses/internal/licenses.tscn | 1 + 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index 0f9f195..ef3290c 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -13,11 +13,13 @@ const Licenses := preload("../licenses.gd") const _BTN_ID_REMOVE: int = 2 +signal components_changed() + @export_node_path("Tree") var _component_detail_path; @onready var _component_detail: ComponentDetailTree = self.get_node(_component_detail_path) var show_readonly_components: bool = false: set = set_show_readonly_components -var licenses: Array[Component] = [] +var _components: Array[Component] = [] ## cached value var _readonly_components: Array[Component] = [] @@ -32,6 +34,14 @@ func _ready() -> void: self._component_detail.component_edited.connect(self._on_component_edited) self._component_detail.handlers = [ObjectHandler, StringFileHandler, StringMultiLineHandler, StringHandler, ArrayHandler] +# will not emit components_changed signal +func set_components(components_: Array[Component]) -> void: + self._components = components_ + self.reload() + +func get_components() -> Array[Component]: + return self._components + # also reloads the view # do not use internally func select_component(component: Component) -> void: @@ -89,18 +99,18 @@ func reload() -> void: var idx: int = 0 var component_selected: bool = false - while idx < len(self.licenses) or readonly_idx < len(self._readonly_components): + while idx < len(self._components) or readonly_idx < len(self._readonly_components): var component: Component = null var cur_idx: int = 0 var cmp: bool = false - if idx < len(self.licenses) and readonly_idx < len(self._readonly_components): + if idx < len(self._components) and readonly_idx < len(self._readonly_components): # TODO: will be static later on - cmp = Licenses.new().compare_components_ascending(self.licenses[idx], self._readonly_components[readonly_idx]) + cmp = Licenses.new().compare_components_ascending(self._components[idx], self._readonly_components[readonly_idx]) if readonly_idx >= len(self._readonly_components) or cmp: - component = self.licenses[idx] + component = self._components[idx] cur_idx = idx idx = idx + 1 - elif idx >= len(self.licenses) or not cmp: + elif idx >= len(self._components) or not cmp: component = self._readonly_components[readonly_idx] cur_idx = readonly_idx readonly_idx = readonly_idx + 1 @@ -137,15 +147,16 @@ func _drop_data(at_position: Vector2, data: Variant) -> void: var category: String = "" # below or above item with category if to_item.has_meta("idx"): - category = self.licenses[to_item.get_meta("idx")].category + category = self._components[to_item.get_meta("idx")].category # below category node elif shift == 1: category = to_item.get_text(0) - var cur_component: Component = self.licenses[data.get_meta("idx")] + var cur_component: Component = self._components[data.get_meta("idx")] if cur_component.category == category: return cur_component.category = category - self.licenses.sort_custom(Licenses.new().compare_components_ascending) + self._components.sort_custom(Licenses.new().compare_components_ascending) + self.components_changed.emit() self.reload() self._component_detail.reload() @@ -157,16 +168,16 @@ func _on_item_selected() -> void: if item.get_meta("readonly"): component = self._readonly_components[item.get_meta("idx")] else: - component = self.licenses[item.get_meta("idx")] + component = self._components[item.get_meta("idx")] self._component_detail.set_component(component) func _on_button_clicked(item: TreeItem, column: int, id: int, mouse_button_idx: int) -> void: match id: _BTN_ID_REMOVE: - var comp: Component = self.licenses[item.get_meta("idx")] - self.licenses.remove_at(item.get_meta("idx")) - self.licenses.sort_custom(Licenses.new().compare_components_ascending) - Licenses.save(self.licenses, Licenses.get_license_data_filepath()) + var comp: Component = self._components[item.get_meta("idx")] + self._components.remove_at(item.get_meta("idx")) + self._components.sort_custom(Licenses.new().compare_components_ascending) + self.components_changed.emit() # refresh detail view if the current component was removed if comp == self._component_detail.get_component(): self._component_detail.set_component(null) @@ -174,8 +185,8 @@ func _on_button_clicked(item: TreeItem, column: int, id: int, mouse_button_idx: # callback from commponent detail tree func _on_component_edited(component: Component) -> void: - self.licenses.sort_custom(Licenses.new().compare_components_ascending) - Licenses.save(self.licenses, Licenses.get_license_data_filepath()) + self._components.sort_custom(Licenses.new().compare_components_ascending) + self.components_changed.emit() self.reload() func _on_item_edited() -> void: @@ -183,12 +194,14 @@ func _on_item_edited() -> void: var old_category: String = category_item.get_meta("category") var new_category: String = category_item.get_text(0) category_item.set_meta("category", new_category) - for component in self.licenses: + for component in self._components: if component.category == old_category: component.category = new_category - self.licenses.sort_custom(Licenses.new().compare_components_ascending) - Licenses.save(self.licenses, Licenses.get_license_data_filepath()) + self._components.sort_custom(Licenses.new().compare_components_ascending) + self.components_changed.emit() + # we cannot reload the tree while it is processing any kind of input/signals + # https://github.com/godotengine/godot/issues/50084 call_deferred("reload") # reload detail view as the category can be changed self._component_detail.reload() diff --git a/addons/licenses/internal/licenses.gd b/addons/licenses/internal/licenses.gd index 71fd162..47559e9 100644 --- a/addons/licenses/internal/licenses.gd +++ b/addons/licenses/internal/licenses.gd @@ -27,9 +27,8 @@ func reload() -> void: else: self._license_file_edit.right_icon = self.get_theme_icon("NodeWarning", "EditorIcons") self._license_file_edit.tooltip_text = res.err_msg - self._components_tree.licenses = res.components - self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) - self._components_tree.reload() + res.components.sort_custom(Licenses.new().compare_components_ascending) + self._components_tree.set_components(res.components) func _update_set_license_filepath_button(): if Licenses.get_license_data_filepath() == self._license_file_edit.text: @@ -60,4 +59,6 @@ func _on_data_file_selected(path: String) -> void: func _on_set_license_filepath_clicked() -> void: Licenses.set_license_data_filepath(self._license_file_edit.text) self._update_set_license_filepath_button() - \ No newline at end of file + +func _on_components_changed() -> void: + Licenses.save(self._components_tree.get_components(), self._license_file_edit.text) diff --git a/addons/licenses/internal/licenses.tscn b/addons/licenses/internal/licenses.tscn index 613571c..883304b 100644 --- a/addons/licenses/internal/licenses.tscn +++ b/addons/licenses/internal/licenses.tscn @@ -99,6 +99,7 @@ hide_root = true script = ExtResource("1") [connection signal="button_clicked" from="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components" to="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components" method="_on_button_clicked"] +[connection signal="components_changed" from="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components" to="." method="_on_components_changed"] [connection signal="item_edited" from="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components" to="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components" method="_on_item_edited"] [connection signal="item_selected" from="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components" to="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components" method="_on_item_selected"] [connection signal="button_clicked" from="VBoxContainer/HSplitContainer/component_detail" to="VBoxContainer/HSplitContainer/component_detail" method="_on_button_clicked"] From aeb03e4a70f4ee7127f02e206f7f7522f9f80067 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 14:28:08 +0200 Subject: [PATCH 09/16] [plugin|licenses] Remove export_node_path if possible --- addons/licenses/internal/licenses.gd | 6 +++--- addons/licenses/internal/licenses.tscn | 14 +++++++------- addons/licenses/internal/toolbar.gd | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/addons/licenses/internal/licenses.gd b/addons/licenses/internal/licenses.gd index 47559e9..9460619 100644 --- a/addons/licenses/internal/licenses.gd +++ b/addons/licenses/internal/licenses.gd @@ -5,9 +5,9 @@ const Licenses := preload("../licenses.gd") const ComponentsTree := preload("components_tree.gd") @export_node_path("Tree") var _components_tree_path; @onready var _components_tree: ComponentsTree = self.get_node(self._components_tree_path) -@export_node_path("LineEdit") var _license_file_edit_path; @onready var _license_file_edit: LineEdit = self.get_node(self._license_file_edit_path) -@export_node_path("Button") var _license_file_load_button_path; @onready var _license_file_load_button: Button = self.get_node(self._license_file_load_button_path) -@export_node_path("Button") var _set_license_filepath_button_path; @onready var _set_license_filepath_button: Button = self.get_node(self._set_license_filepath_button_path) +@export var _license_file_edit: LineEdit = null +@export var _license_file_load_button: Button = null +@export var _set_license_filepath_button: Button = null func _ready() -> void: self._license_file_load_button.icon = self.get_theme_icon("Load", "EditorIcons") diff --git a/addons/licenses/internal/licenses.tscn b/addons/licenses/internal/licenses.tscn index 883304b..b625bbf 100644 --- a/addons/licenses/internal/licenses.tscn +++ b/addons/licenses/internal/licenses.tscn @@ -7,7 +7,7 @@ [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_5cx7n"] -[node name="licenses" type="MarginContainer"] +[node name="licenses" type="MarginContainer" node_paths=PackedStringArray("_license_file_edit", "_license_file_load_button", "_set_license_filepath_button")] anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 @@ -21,9 +21,9 @@ theme_override_constants/margin_right = 4 theme_override_constants/margin_bottom = 4 script = ExtResource("3") _components_tree_path = NodePath("VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/components") -_license_file_edit_path = NodePath("VBoxContainer/license_file_config/edit") -_license_file_load_button_path = NodePath("VBoxContainer/license_file_config/file_button") -_set_license_filepath_button_path = NodePath("VBoxContainer/license_file_config/set_license_filepath_button") +_license_file_edit = NodePath("VBoxContainer/license_file_config/edit") +_license_file_load_button = NodePath("VBoxContainer/license_file_config/file_button") +_set_license_filepath_button = NodePath("VBoxContainer/license_file_config/set_license_filepath_button") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 2 @@ -58,11 +58,11 @@ layout_mode = 2 size_flags_horizontal = 3 theme_override_constants/separation = 0 -[node name="toolbar" type="HBoxContainer" parent="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer"] +[node name="toolbar" type="HBoxContainer" parent="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer" node_paths=PackedStringArray("_menu_button", "_add_button")] layout_mode = 2 script = ExtResource("2_a8iu8") -_menu_button_path = NodePath("menu") -_add_button_path = NodePath("add") +_menu_button = NodePath("menu") +_add_button = NodePath("add") _components_tree_path = NodePath("../components") [node name="menu" type="Button" parent="VBoxContainer/HSplitContainer/PanelContainer/VBoxContainer/toolbar"] diff --git a/addons/licenses/internal/toolbar.gd b/addons/licenses/internal/toolbar.gd index 95e9586..89d537d 100644 --- a/addons/licenses/internal/toolbar.gd +++ b/addons/licenses/internal/toolbar.gd @@ -5,8 +5,8 @@ const Licenses := preload("../licenses.gd") const Component := preload("../component.gd") const ComponentTree := preload("components_tree.gd") -@export_node_path("Button") var _menu_button_path; @onready var _menu_button: Button = self.get_node(_menu_button_path) -@export_node_path("Button") var _add_button_path; @onready var _add_button: Button = self.get_node(_add_button_path) +@export var _menu_button: Button = null +@export var _add_button: Button = null @export_node_path("Tree") var _components_tree_path; @onready var _components_tree: ComponentTree = self.get_node(_components_tree_path) var _menu: PopupMenu From 5a315d144bf40d7a2df0534ff465ce06e68a6e5a Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 14:41:12 +0200 Subject: [PATCH 10/16] [plugin|licenses] Add hint if a referenced path does not exist --- addons/licenses/internal/components_tree.gd | 9 +++++++++ examples/licenses/licenses.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index ef3290c..c8d1878 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -76,6 +76,15 @@ func _add_tree_item(component: Component, idx: int, parent: TreeItem) -> TreeIte tooltip += "\n- no license" if component.copyright.is_empty(): tooltip += "\n- no copyright" + var path_missing: bool = false + for path in component.paths: + if FileAccess.file_exists(path) || DirAccess.dir_exists_absolute(path): + continue + if !path_missing: + tooltip += "\n- referenced path do not exist" + tooltip += "\n - " + path + path_missing = true + if tooltip != component.name: item.set_icon(0, self.get_theme_icon("NodeWarning", "EditorIcons")) item.set_tooltip_text(0, tooltip) diff --git a/examples/licenses/licenses.json b/examples/licenses/licenses.json index 8ff572c..034426d 100644 --- a/examples/licenses/licenses.json +++ b/examples/licenses/licenses.json @@ -1 +1 @@ -{"components":[{"category":"Fonts","contact":"","copyright":["2012, Google Inc."],"description":"","id":"noto_sans_font","licenses":[{"file":"","identifier":"","name":"OFL-1.1","text":"PREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded,\nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE.\n","web":""}],"name":"Noto Sans font","paths":[],"version":"","web":""},{"category":"Textures","contact":"","copyright":["2017, Andrea CalabrĂ³"],"description":"","id":"godot_engine_logo","licenses":[{"file":"","identifier":"","name":"CC-BY-4.0","text":"Creative Commons Attribution 4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution 4.0 International Public License (\"Public\nLicense\"). To the extent this Public License may be interpreted as a\ncontract, You are granted the Licensed Rights in consideration of Your\nacceptance of these terms and conditions, and the Licensor grants You\nsuch rights in consideration of benefits the Licensor receives from\nmaking the Licensed Material available under these terms and\nconditions.\n\nSection 1 -- Definitions.\n\na. Adapted Material means material subject to Copyright and Similar\nRights that is derived from or based upon the Licensed Material\nand in which the Licensed Material is translated, altered,\narranged, transformed, or otherwise modified in a manner requiring\npermission under the Copyright and Similar Rights held by the\nLicensor. For purposes of this Public License, where the Licensed\nMaterial is a musical work, performance, or sound recording,\nAdapted Material is always produced where the Licensed Material is\nsynched in timed relation with a moving image.\n\nb. Adapter's License means the license You apply to Your Copyright\nand Similar Rights in Your contributions to Adapted Material in\naccordance with the terms and conditions of this Public License.\n\nc. Copyright and Similar Rights means copyright and/or similar rights\nclosely related to copyright including, without limitation,\nperformance, broadcast, sound recording, and Sui Generis Database\nRights, without regard to how the rights are labeled or\ncategorized. For purposes of this Public License, the rights\nspecified in Section 2(b)(1)-(2) are not Copyright and Similar\nRights.\n\nd. Effective Technological Measures means those measures that, in the\nabsence of proper authority, may not be circumvented under laws\nfulfilling obligations under Article 11 of the WIPO Copyright\nTreaty adopted on December 20, 1996, and/or similar international\nagreements.\n\ne. Exceptions and Limitations means fair use, fair dealing, and/or\nany other exception or limitation to Copyright and Similar Rights\nthat applies to Your use of the Licensed Material.\n\nf. Licensed Material means the artistic or literary work, database,\nor other material to which the Licensor applied this Public\nLicense.\n\ng. Licensed Rights means the rights granted to You subject to the\nterms and conditions of this Public License, which are limited to\nall Copyright and Similar Rights that apply to Your use of the\nLicensed Material and that the Licensor has authority to license.\n\nh. Licensor means the individual(s) or entity(ies) granting rights\nunder this Public License.\n\ni. Share means to provide material to the public by any means or\nprocess that requires permission under the Licensed Rights, such\nas reproduction, public display, public performance, distribution,\ndissemination, communication, or importation, and to make material\navailable to the public including in ways that members of the\npublic may access the material from a place and at a time\nindividually chosen by them.\n\nj. Sui Generis Database Rights means rights other than copyright\nresulting from Directive 96/9/EC of the European Parliament and of\nthe Council of 11 March 1996 on the legal protection of databases,\nas amended and/or succeeded, as well as other essentially\nequivalent rights anywhere in the world.\n\nk. You means the individual or entity exercising the Licensed Rights\nunder this Public License. Your has a corresponding meaning.\n\nSection 2 -- Scope.\n\na. License grant.\n\n1. Subject to the terms and conditions of this Public License,\nthe Licensor hereby grants You a worldwide, royalty-free,\nnon-sublicensable, non-exclusive, irrevocable license to\nexercise the Licensed Rights in the Licensed Material to:\n\na. reproduce and Share the Licensed Material, in whole or\nin part; and\n\nb. produce, reproduce, and Share Adapted Material.\n\n2. Exceptions and Limitations. For the avoidance of doubt, where\nExceptions and Limitations apply to Your use, this Public\nLicense does not apply, and You do not need to comply with\nits terms and conditions.\n\n3. Term. The term of this Public License is specified in Section\n6(a).\n\n4. Media and formats; technical modifications allowed. The\nLicensor authorizes You to exercise the Licensed Rights in\nall media and formats whether now known or hereafter created,\nand to make technical modifications necessary to do so. The\nLicensor waives and/or agrees not to assert any right or\nauthority to forbid You from making technical modifications\nnecessary to exercise the Licensed Rights, including\ntechnical modifications necessary to circumvent Effective\nTechnological Measures. For purposes of this Public License,\nsimply making modifications authorized by this Section 2(a)\n(4) never produces Adapted Material.\n\n5. Downstream recipients.\n\na. Offer from the Licensor -- Licensed Material. Every\nrecipient of the Licensed Material automatically\nreceives an offer from the Licensor to exercise the\nLicensed Rights under the terms and conditions of this\nPublic License.\n\nb. No downstream restrictions. You may not offer or impose\nany additional or different terms or conditions on, or\napply any Effective Technological Measures to, the\nLicensed Material if doing so restricts exercise of the\nLicensed Rights by any recipient of the Licensed\nMaterial.\n\n6. No endorsement. Nothing in this Public License constitutes or\nmay be construed as permission to assert or imply that You\nare, or that Your use of the Licensed Material is, connected\nwith, or sponsored, endorsed, or granted official status by,\nthe Licensor or others designated to receive attribution as\nprovided in Section 3(a)(1)(A)(i).\n\nb. Other rights.\n\n1. Moral rights, such as the right of integrity, are not\nlicensed under this Public License, nor are publicity,\nprivacy, and/or other similar personality rights; however, to\nthe extent possible, the Licensor waives and/or agrees not to\nassert any such rights held by the Licensor to the limited\nextent necessary to allow You to exercise the Licensed\nRights, but not otherwise.\n\n2. Patent and trademark rights are not licensed under this\nPublic License.\n\n3. To the extent possible, the Licensor waives any right to\ncollect royalties from You for the exercise of the Licensed\nRights, whether directly or through a collecting society\nunder any voluntary or waivable statutory or compulsory\nlicensing scheme. In all other cases the Licensor expressly\nreserves any right to collect such royalties.\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\na. Attribution.\n\n1. If You Share the Licensed Material (including in modified\nform), You must:\n\na. retain the following if it is supplied by the Licensor\nwith the Licensed Material:\n\ni. identification of the creator(s) of the Licensed\nMaterial and any others designated to receive\nattribution, in any reasonable manner requested by\nthe Licensor (including by pseudonym if\ndesignated);\n\nii. a copyright notice;\n\niii. a notice that refers to this Public License;\n\niv. a notice that refers to the disclaimer of\nwarranties;\n\nv. a URI or hyperlink to the Licensed Material to the\nextent reasonably practicable;\n\nb. indicate if You modified the Licensed Material and\nretain an indication of any previous modifications; and\n\nc. indicate the Licensed Material is licensed under this\nPublic License, and include the text of, or the URI or\nhyperlink to, this Public License.\n\n2. You may satisfy the conditions in Section 3(a)(1) in any\nreasonable manner based on the medium, means, and context in\nwhich You Share the Licensed Material. For example, it may be\nreasonable to satisfy the conditions by providing a URI or\nhyperlink to a resource that includes the required\ninformation.\n\n3. If requested by the Licensor, You must remove any of the\ninformation required by Section 3(a)(1)(A) to the extent\nreasonably practicable.\n\n4. If You Share Adapted Material You produce, the Adapter's\nLicense You apply must not prevent recipients of the Adapted\nMaterial from complying with this Public License.\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\na. for the avoidance of doubt, Section 2(a)(1) grants You the right\nto extract, reuse, reproduce, and Share all or a substantial\nportion of the contents of the database;\n\nb. if You include all or a substantial portion of the database\ncontents in a database in which You have Sui Generis Database\nRights, then the database in which You have Sui Generis Database\nRights (but not its individual contents) is Adapted Material; and\n\nc. You must comply with the conditions in Section 3(a) if You Share\nall or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\na. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\nEXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\nAND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\nANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\nIMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\nWARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\nPURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\nACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\nKNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\nALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\nb. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\nTO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\nNEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\nINCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\nCOSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\nUSE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\nADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\nDAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\nIN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\nc. The disclaimer of warranties and limitation of liability provided\nabove shall be interpreted in a manner that, to the extent\npossible, most closely approximates an absolute disclaimer and\nwaiver of all liability.\n\nSection 6 -- Term and Termination.\n\na. This Public License applies for the term of the Copyright and\nSimilar Rights licensed here. However, if You fail to comply with\nthis Public License, then Your rights under this Public License\nterminate automatically.\n\nb. Where Your right to use the Licensed Material has terminated under\nSection 6(a), it reinstates:\n\n1. automatically as of the date the violation is cured, provided\nit is cured within 30 days of Your discovery of the\nviolation; or\n\n2. upon express reinstatement by the Licensor.\n\nFor the avoidance of doubt, this Section 6(b) does not affect any\nright the Licensor may have to seek remedies for Your violations\nof this Public License.\n\nc. For the avoidance of doubt, the Licensor may also offer the\nLicensed Material under separate terms or conditions or stop\ndistributing the Licensed Material at any time; however, doing so\nwill not terminate this Public License.\n\nd. Sections 1, 5, 6, 7, and 8 survive termination of this Public\nLicense.\n\nSection 7 -- Other Terms and Conditions.\n\na. The Licensor shall not be bound by any additional or different\nterms or conditions communicated by You unless expressly agreed.\n\nb. Any arrangements, understandings, or agreements regarding the\nLicensed Material not stated herein are separate from and\nindependent of the terms and conditions of this Public License.\n\nSection 8 -- Interpretation.\n\na. For the avoidance of doubt, this Public License does not, and\nshall not be interpreted to, reduce, limit, restrict, or impose\nconditions on any use of the Licensed Material that could lawfully\nbe made without permission under this Public License.\n\nb. To the extent possible, if any provision of this Public License is\ndeemed unenforceable, it shall be automatically reformed to the\nminimum extent necessary to make it enforceable. If the provision\ncannot be reformed, it shall be severed from this Public License\nwithout affecting the enforceability of the remaining terms and\nconditions.\n\nc. No term or condition of this Public License will be waived and no\nfailure to comply consented to unless expressly agreed to by the\nLicensor.\n\nd. Nothing in this Public License constitutes or may be interpreted\nas a limitation upon, or waiver of, any privileges and immunities\nthat apply to the Licensor or You, including from the legal\nprocesses of any jurisdiction or authority.\n","web":""}],"name":"Godot Engine logo","paths":["res://icon.svg"],"version":"","web":""}]} +{"components":[{"category":"Fonts","contact":"","copyright":["2012, Google Inc."],"description":"","id":"noto_sans_font","licenses":[{"file":"","identifier":"","name":"OFL-1.1","text":"PREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded,\nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE.\n","web":""}],"name":"Noto Sans font","paths":["res://assets/fonts/noto_sans"],"version":"","web":""},{"category":"Textures","contact":"","copyright":["2017, Andrea CalabrĂ³"],"description":"","id":"godot_engine_logo","licenses":[{"file":"","identifier":"","name":"CC-BY-4.0","text":"Creative Commons Attribution 4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution 4.0 International Public License (\"Public\nLicense\"). To the extent this Public License may be interpreted as a\ncontract, You are granted the Licensed Rights in consideration of Your\nacceptance of these terms and conditions, and the Licensor grants You\nsuch rights in consideration of benefits the Licensor receives from\nmaking the Licensed Material available under these terms and\nconditions.\n\nSection 1 -- Definitions.\n\na. Adapted Material means material subject to Copyright and Similar\nRights that is derived from or based upon the Licensed Material\nand in which the Licensed Material is translated, altered,\narranged, transformed, or otherwise modified in a manner requiring\npermission under the Copyright and Similar Rights held by the\nLicensor. For purposes of this Public License, where the Licensed\nMaterial is a musical work, performance, or sound recording,\nAdapted Material is always produced where the Licensed Material is\nsynched in timed relation with a moving image.\n\nb. Adapter's License means the license You apply to Your Copyright\nand Similar Rights in Your contributions to Adapted Material in\naccordance with the terms and conditions of this Public License.\n\nc. Copyright and Similar Rights means copyright and/or similar rights\nclosely related to copyright including, without limitation,\nperformance, broadcast, sound recording, and Sui Generis Database\nRights, without regard to how the rights are labeled or\ncategorized. For purposes of this Public License, the rights\nspecified in Section 2(b)(1)-(2) are not Copyright and Similar\nRights.\n\nd. Effective Technological Measures means those measures that, in the\nabsence of proper authority, may not be circumvented under laws\nfulfilling obligations under Article 11 of the WIPO Copyright\nTreaty adopted on December 20, 1996, and/or similar international\nagreements.\n\ne. Exceptions and Limitations means fair use, fair dealing, and/or\nany other exception or limitation to Copyright and Similar Rights\nthat applies to Your use of the Licensed Material.\n\nf. Licensed Material means the artistic or literary work, database,\nor other material to which the Licensor applied this Public\nLicense.\n\ng. Licensed Rights means the rights granted to You subject to the\nterms and conditions of this Public License, which are limited to\nall Copyright and Similar Rights that apply to Your use of the\nLicensed Material and that the Licensor has authority to license.\n\nh. Licensor means the individual(s) or entity(ies) granting rights\nunder this Public License.\n\ni. Share means to provide material to the public by any means or\nprocess that requires permission under the Licensed Rights, such\nas reproduction, public display, public performance, distribution,\ndissemination, communication, or importation, and to make material\navailable to the public including in ways that members of the\npublic may access the material from a place and at a time\nindividually chosen by them.\n\nj. Sui Generis Database Rights means rights other than copyright\nresulting from Directive 96/9/EC of the European Parliament and of\nthe Council of 11 March 1996 on the legal protection of databases,\nas amended and/or succeeded, as well as other essentially\nequivalent rights anywhere in the world.\n\nk. You means the individual or entity exercising the Licensed Rights\nunder this Public License. Your has a corresponding meaning.\n\nSection 2 -- Scope.\n\na. License grant.\n\n1. Subject to the terms and conditions of this Public License,\nthe Licensor hereby grants You a worldwide, royalty-free,\nnon-sublicensable, non-exclusive, irrevocable license to\nexercise the Licensed Rights in the Licensed Material to:\n\na. reproduce and Share the Licensed Material, in whole or\nin part; and\n\nb. produce, reproduce, and Share Adapted Material.\n\n2. Exceptions and Limitations. For the avoidance of doubt, where\nExceptions and Limitations apply to Your use, this Public\nLicense does not apply, and You do not need to comply with\nits terms and conditions.\n\n3. Term. The term of this Public License is specified in Section\n6(a).\n\n4. Media and formats; technical modifications allowed. The\nLicensor authorizes You to exercise the Licensed Rights in\nall media and formats whether now known or hereafter created,\nand to make technical modifications necessary to do so. The\nLicensor waives and/or agrees not to assert any right or\nauthority to forbid You from making technical modifications\nnecessary to exercise the Licensed Rights, including\ntechnical modifications necessary to circumvent Effective\nTechnological Measures. For purposes of this Public License,\nsimply making modifications authorized by this Section 2(a)\n(4) never produces Adapted Material.\n\n5. Downstream recipients.\n\na. Offer from the Licensor -- Licensed Material. Every\nrecipient of the Licensed Material automatically\nreceives an offer from the Licensor to exercise the\nLicensed Rights under the terms and conditions of this\nPublic License.\n\nb. No downstream restrictions. You may not offer or impose\nany additional or different terms or conditions on, or\napply any Effective Technological Measures to, the\nLicensed Material if doing so restricts exercise of the\nLicensed Rights by any recipient of the Licensed\nMaterial.\n\n6. No endorsement. Nothing in this Public License constitutes or\nmay be construed as permission to assert or imply that You\nare, or that Your use of the Licensed Material is, connected\nwith, or sponsored, endorsed, or granted official status by,\nthe Licensor or others designated to receive attribution as\nprovided in Section 3(a)(1)(A)(i).\n\nb. Other rights.\n\n1. Moral rights, such as the right of integrity, are not\nlicensed under this Public License, nor are publicity,\nprivacy, and/or other similar personality rights; however, to\nthe extent possible, the Licensor waives and/or agrees not to\nassert any such rights held by the Licensor to the limited\nextent necessary to allow You to exercise the Licensed\nRights, but not otherwise.\n\n2. Patent and trademark rights are not licensed under this\nPublic License.\n\n3. To the extent possible, the Licensor waives any right to\ncollect royalties from You for the exercise of the Licensed\nRights, whether directly or through a collecting society\nunder any voluntary or waivable statutory or compulsory\nlicensing scheme. In all other cases the Licensor expressly\nreserves any right to collect such royalties.\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\na. Attribution.\n\n1. If You Share the Licensed Material (including in modified\nform), You must:\n\na. retain the following if it is supplied by the Licensor\nwith the Licensed Material:\n\ni. identification of the creator(s) of the Licensed\nMaterial and any others designated to receive\nattribution, in any reasonable manner requested by\nthe Licensor (including by pseudonym if\ndesignated);\n\nii. a copyright notice;\n\niii. a notice that refers to this Public License;\n\niv. a notice that refers to the disclaimer of\nwarranties;\n\nv. a URI or hyperlink to the Licensed Material to the\nextent reasonably practicable;\n\nb. indicate if You modified the Licensed Material and\nretain an indication of any previous modifications; and\n\nc. indicate the Licensed Material is licensed under this\nPublic License, and include the text of, or the URI or\nhyperlink to, this Public License.\n\n2. You may satisfy the conditions in Section 3(a)(1) in any\nreasonable manner based on the medium, means, and context in\nwhich You Share the Licensed Material. For example, it may be\nreasonable to satisfy the conditions by providing a URI or\nhyperlink to a resource that includes the required\ninformation.\n\n3. If requested by the Licensor, You must remove any of the\ninformation required by Section 3(a)(1)(A) to the extent\nreasonably practicable.\n\n4. If You Share Adapted Material You produce, the Adapter's\nLicense You apply must not prevent recipients of the Adapted\nMaterial from complying with this Public License.\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\na. for the avoidance of doubt, Section 2(a)(1) grants You the right\nto extract, reuse, reproduce, and Share all or a substantial\nportion of the contents of the database;\n\nb. if You include all or a substantial portion of the database\ncontents in a database in which You have Sui Generis Database\nRights, then the database in which You have Sui Generis Database\nRights (but not its individual contents) is Adapted Material; and\n\nc. You must comply with the conditions in Section 3(a) if You Share\nall or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\na. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\nEXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\nAND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\nANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\nIMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\nWARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\nPURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\nACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\nKNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\nALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\nb. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\nTO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\nNEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\nINCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\nCOSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\nUSE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\nADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\nDAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\nIN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\nc. The disclaimer of warranties and limitation of liability provided\nabove shall be interpreted in a manner that, to the extent\npossible, most closely approximates an absolute disclaimer and\nwaiver of all liability.\n\nSection 6 -- Term and Termination.\n\na. This Public License applies for the term of the Copyright and\nSimilar Rights licensed here. However, if You fail to comply with\nthis Public License, then Your rights under this Public License\nterminate automatically.\n\nb. Where Your right to use the Licensed Material has terminated under\nSection 6(a), it reinstates:\n\n1. automatically as of the date the violation is cured, provided\nit is cured within 30 days of Your discovery of the\nviolation; or\n\n2. upon express reinstatement by the Licensor.\n\nFor the avoidance of doubt, this Section 6(b) does not affect any\nright the Licensor may have to seek remedies for Your violations\nof this Public License.\n\nc. For the avoidance of doubt, the Licensor may also offer the\nLicensed Material under separate terms or conditions or stop\ndistributing the Licensed Material at any time; however, doing so\nwill not terminate this Public License.\n\nd. Sections 1, 5, 6, 7, and 8 survive termination of this Public\nLicense.\n\nSection 7 -- Other Terms and Conditions.\n\na. The Licensor shall not be bound by any additional or different\nterms or conditions communicated by You unless expressly agreed.\n\nb. Any arrangements, understandings, or agreements regarding the\nLicensed Material not stated herein are separate from and\nindependent of the terms and conditions of this Public License.\n\nSection 8 -- Interpretation.\n\na. For the avoidance of doubt, this Public License does not, and\nshall not be interpreted to, reduce, limit, restrict, or impose\nconditions on any use of the Licensed Material that could lawfully\nbe made without permission under this Public License.\n\nb. To the extent possible, if any provision of this Public License is\ndeemed unenforceable, it shall be automatically reformed to the\nminimum extent necessary to make it enforceable. If the provision\ncannot be reformed, it shall be severed from this Public License\nwithout affecting the enforceability of the remaining terms and\nconditions.\n\nc. No term or condition of this Public License will be waived and no\nfailure to comply consented to unless expressly agreed to by the\nLicensor.\n\nd. Nothing in this Public License constitutes or may be interpreted\nas a limitation upon, or waiver of, any privileges and immunities\nthat apply to the Licensor or You, including from the legal\nprocesses of any jurisdiction or authority.\n","web":""}],"name":"Godot Engine logo","paths":["res://icon.svg"],"version":"","web":""}]} From cd4cfb3b128b4c299e2b861236b31696dcc1c1b6 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 14:41:57 +0200 Subject: [PATCH 11/16] [plugin|licenses] Bump version --- addons/licenses/plugin.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/licenses/plugin.cfg b/addons/licenses/plugin.cfg index 4467ad1..8a57b55 100644 --- a/addons/licenses/plugin.cfg +++ b/addons/licenses/plugin.cfg @@ -3,5 +3,5 @@ name="Licenses" description="MIT License" author="Iceflower S" -version="1.4.2" +version="1.5.0" script="plugin.gd" From 191ff8f7a5cf165322eaa3204cc1b4b53c4f4a1d Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 15:15:53 +0200 Subject: [PATCH 12/16] [plugin|licenses] Simplify component warnings --- addons/licenses/component.gd | 15 +++++++++++++++ addons/licenses/internal/components_tree.gd | 19 +++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/addons/licenses/component.gd b/addons/licenses/component.gd index 4da52b6..9ada304 100644 --- a/addons/licenses/component.gd +++ b/addons/licenses/component.gd @@ -100,6 +100,21 @@ func _get_property_list() -> Array: }, ] +func get_warnings() -> PackedStringArray: + var res: PackedStringArray = [] + if self.name == "": + res.append("no name") + if self.licenses.is_empty(): + res.append("no license") + if self.copyright.is_empty(): + res.append("no copyright") + var path_missing: bool = false + for path in self.paths: + if FileAccess.file_exists(path) || DirAccess.dir_exists_absolute(path): + continue + res.append("path '" + path + "' does not exst") + return res + func serialize() -> Dictionary: var licenses: Array[Dictionary] = [] for license in self.licenses: diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index c8d1878..db1b055 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -70,22 +70,9 @@ func _add_tree_item(component: Component, idx: int, parent: TreeItem) -> TreeIte if not component.readonly: item.add_button(0, self.get_theme_icon("Remove", "EditorIcons"), _BTN_ID_REMOVE) var tooltip = component.name - if component.name == "": - tooltip += "\n- no name" - if component.licenses.is_empty(): - tooltip += "\n- no license" - if component.copyright.is_empty(): - tooltip += "\n- no copyright" - var path_missing: bool = false - for path in component.paths: - if FileAccess.file_exists(path) || DirAccess.dir_exists_absolute(path): - continue - if !path_missing: - tooltip += "\n- referenced path do not exist" - tooltip += "\n - " + path - path_missing = true - - if tooltip != component.name: + var comp_warnings: PackedStringArray = component.get_warnings() + if comp_warnings.size() != 0: + tooltip += "\n- " + "\n - ".join(comp_warnings) item.set_icon(0, self.get_theme_icon("NodeWarning", "EditorIcons")) item.set_tooltip_text(0, tooltip) return item From 69b3569e18e533d3a26692bf87079528669721de Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 15:34:19 +0200 Subject: [PATCH 13/16] [plugin|licenses] No tooltip on multiline string if empty --- addons/licenses/internal/handler/string_multiline.gd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/licenses/internal/handler/string_multiline.gd b/addons/licenses/internal/handler/string_multiline.gd index 44d9995..b5505ea 100644 --- a/addons/licenses/internal/handler/string_multiline.gd +++ b/addons/licenses/internal/handler/string_multiline.gd @@ -6,7 +6,10 @@ func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, propert super._init(tree_, item_, value_, property_) self.item.set_text(0, self.property["name"].capitalize()) self.item.set_text(1, self.value) - self.item.set_tooltip_text(1, self.value.substr(0, mini(self.value.length(), 512)) + "...") + var tooltip_text: String = self.value.substr(0, mini(self.value.length(), 512)) + if self.value.length() > 512: + tooltip_text += "..." + self.item.set_tooltip_text(1, tooltip_text) self._update_reset_button() self.item.add_button(1, self.tree.get_theme_icon("DistractionFree", "EditorIcons"), 1) From 873e4778b8a0ae43caab6713e720593f8792317e Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 19:55:57 +0200 Subject: [PATCH 14/16] [plugin|licenses] Fix toolbar buttons --- addons/licenses/internal/components_tree.gd | 5 +++++ addons/licenses/internal/toolbar.gd | 10 ++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index db1b055..e602bf8 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -34,6 +34,11 @@ func _ready() -> void: self._component_detail.component_edited.connect(self._on_component_edited) self._component_detail.handlers = [ObjectHandler, StringFileHandler, StringMultiLineHandler, StringHandler, ArrayHandler] +func add_component(component: Component) -> void: + self._components.append(component) + self._components.sort_custom(Licenses.new().compare_components_ascending) + self.reload() + # will not emit components_changed signal func set_components(components_: Array[Component]) -> void: self._components = components_ diff --git a/addons/licenses/internal/toolbar.gd b/addons/licenses/internal/toolbar.gd index 89d537d..2592d8d 100644 --- a/addons/licenses/internal/toolbar.gd +++ b/addons/licenses/internal/toolbar.gd @@ -111,8 +111,7 @@ func _on_menu_pressed() -> void: func _on_engine_add_id_pressed(id: int) -> void: var component: Component = Licenses.get_engine_component(self._add_engine_menu.get_item_metadata(id)) component.readonly = false - self._components_tree.licenses.append(component) - self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) + self._components_tree.add_component(component) self._components_tree.select_component(component) # add component entry based on plugin cfg @@ -124,8 +123,7 @@ func _on_plugin_add_id_pressed(id: int) -> void: component.copyright.append(cfg["plugin"].get("author", "")) component.version = cfg["plugin"].get("version", "") component.paths.append(self._add_plugin_menu.get_item_metadata(id).get_base_dir()) - self._components_tree.licenses.append(component) - self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) + self._components_tree.add_component(component) self._components_tree.select_component(component) func _on_menu_id_pressed(id: int) -> void: @@ -139,6 +137,6 @@ func _on_add_id_pressed(id: int) -> void: match id: 0: var component: Component = Component.new() - self._components_tree.licenses.append(component) - self._components_tree.licenses.sort_custom(Licenses.new().compare_components_ascending) + self._components_tree.add_component(component) + self._components_tree.select_component(component) self._components_tree.select_component(component) From 21f33f25158417d49637e6f5ec5bf5a0bf3366b9 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 19:59:11 +0200 Subject: [PATCH 15/16] [plugin|licenses] Fix code style --- addons/licenses/internal/components_tree.gd | 4 +--- addons/licenses/internal/handler/object.gd | 4 ++-- addons/licenses/internal/licenses.gd | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/addons/licenses/internal/components_tree.gd b/addons/licenses/internal/components_tree.gd index e602bf8..497f53c 100644 --- a/addons/licenses/internal/components_tree.gd +++ b/addons/licenses/internal/components_tree.gd @@ -77,7 +77,7 @@ func _add_tree_item(component: Component, idx: int, parent: TreeItem) -> TreeIte var tooltip = component.name var comp_warnings: PackedStringArray = component.get_warnings() if comp_warnings.size() != 0: - tooltip += "\n- " + "\n - ".join(comp_warnings) + tooltip += "\n- " + "\n- ".join(comp_warnings) item.set_icon(0, self.get_theme_icon("NodeWarning", "EditorIcons")) item.set_tooltip_text(0, tooltip) return item @@ -98,7 +98,6 @@ func reload() -> void: var readonly_idx: int = 0 # count current added custom components var idx: int = 0 - var component_selected: bool = false while idx < len(self._components) or readonly_idx < len(self._readonly_components): var component: Component = null @@ -118,7 +117,6 @@ func reload() -> void: var item: TreeItem = self._add_component(component, category_cache, root, cur_idx) if component == self._component_detail.get_component(): - component_selected = true self.scroll_to_item(item) item.select(0) diff --git a/addons/licenses/internal/handler/object.gd b/addons/licenses/internal/handler/object.gd index 30db819..320f51b 100644 --- a/addons/licenses/internal/handler/object.gd +++ b/addons/licenses/internal/handler/object.gd @@ -11,12 +11,12 @@ func _init(tree_: ComponentDetailTree, item_: TreeItem, value_: Variant, propert # ignore private variables and ignore non supported types and already added items if prop["name"].begins_with("_"): continue - self.tree._add_item(self.item, self.value.get(prop["name"]), prop) + self.tree._add_item(self.item, (self.value as Object).get(prop["name"]), prop) static func can_handle(property: Dictionary) -> bool: return property["type"] == TYPE_OBJECT and property.get("class_name", "") != "Script" func child_edited(item: TreeItem) -> void: var child = item.get_meta("handler") - self.value.set(child.property["name"], child.value) + (self.value as Object).set(child.property["name"], child.value) self.tree._on_item_edited(self.item) diff --git a/addons/licenses/internal/licenses.gd b/addons/licenses/internal/licenses.gd index 9460619..c82be8c 100644 --- a/addons/licenses/internal/licenses.gd +++ b/addons/licenses/internal/licenses.gd @@ -30,7 +30,7 @@ func reload() -> void: res.components.sort_custom(Licenses.new().compare_components_ascending) self._components_tree.set_components(res.components) -func _update_set_license_filepath_button(): +func _update_set_license_filepath_button() -> void: if Licenses.get_license_data_filepath() == self._license_file_edit.text: self._set_license_filepath_button.icon = self.get_theme_icon("ImportCheck", "EditorIcons") self._set_license_filepath_button.tooltip_text = "Selected file is set as the project license file." From 25d7ed62069431e661d6e77cda44f420044ee549 Mon Sep 17 00:00:00 2001 From: Iceflower Date: Mon, 25 Sep 2023 20:04:07 +0200 Subject: [PATCH 16/16] [plugin|licenses|doc] Update changelog --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9927844..6e4103c 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ Then use `Project` -> `Tools` -> `Icons Patcher` to patch the icons. Manage license and copyright for third party graphics, software or libraries. Group them into categories, add descriptions or web links. -The data is stored inside a json file. This file is automatically added to the export, you do not need to add it yourself. +The data is stored inside a json file. This file is automatically added to the export, you do not need to add it yourself. If you provide license files instead of a text, they are also exported. You can change the project license file either with a button at the upper right, in the license menu. Or inside the project settings under the menu `Plugins` -> `Licenses`. @@ -210,6 +210,16 @@ Component class, data wrapper for all information regarding one license item. License class. +### Changelog + +#### 1.5.0 + +- Removed overriden engine methods +- Creating a plugin component will now add the plugin path to paths +- Fix dragging/ double click crash +- Fix overriding project license file if another license file is loaded +- Add warning tooltip if a plugin paths does not exist + --- ## Logging