Skip to content

Commit

Permalink
[merge] Update licenses plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
IceflowRE committed Sep 25, 2023
2 parents 56e01f5 + 25d7ed6 commit d58eb72
Show file tree
Hide file tree
Showing 17 changed files with 197 additions and 110 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down Expand Up @@ -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
Expand Down
67 changes: 47 additions & 20 deletions addons/licenses/component.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -75,18 +80,40 @@ 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 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] = []
Expand Down
4 changes: 3 additions & 1 deletion addons/licenses/export_plugin.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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 != "":
Expand Down
22 changes: 13 additions & 9 deletions addons/licenses/internal/component_detail_tree.gd
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,27 @@ 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

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:
Expand Down Expand Up @@ -67,7 +71,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:
Expand Down
102 changes: 64 additions & 38 deletions addons/licenses/internal/components_tree.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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] = []

Expand All @@ -32,6 +34,25 @@ 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_
self.reload()

func get_components() -> Array[Component]:
return self._components

# 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()

Expand All @@ -54,13 +75,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"
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
Expand All @@ -69,8 +86,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)
Expand All @@ -79,39 +98,36 @@ func reload(select_component: Component = null) -> void:
var readonly_idx: int = 0
# count current added custom components
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

var item: TreeItem = self._add_component(component, category_cache, root, cur_idx)
if component == select_component:
component_selected = true
if component == self._component_detail.get_component():
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)
return item != null and data is TreeItem

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

Expand All @@ -130,17 +146,18 @@ 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
Licenses.sort_components()
self.licenses.sort_custom(Licenses.new().compare_components_ascending)
self.reload(cur_component)
self._components.sort_custom(Licenses.new().compare_components_ascending)
self.components_changed.emit()
self.reload()
self._component_detail.reload()

func _on_item_selected() -> void:
var item: TreeItem = self.get_selected()
Expand All @@ -150,31 +167,40 @@ 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:
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())

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)
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._components.sort_custom(Licenses.new().compare_components_ascending)
self.components_changed.emit()
self.reload()

func _on_item_edited() -> void:
var category_item: TreeItem = self.get_edited()
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.reload(self._component_detail.get_component())
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()
2 changes: 1 addition & 1 deletion addons/licenses/internal/handler/array.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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)) + " ]")
Expand Down
1 change: 1 addition & 0 deletions addons/licenses/internal/handler/base.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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_
Expand Down
Loading

0 comments on commit d58eb72

Please sign in to comment.