dropdown
This commit is contained in:
File diff suppressed because it is too large
Load Diff
43
operators.py
43
operators.py
@@ -108,8 +108,27 @@ class DYNAMICLINK_OT_scan_linked_assets(Operator):
|
|||||||
return "Unknown"
|
return "Unknown"
|
||||||
return os.path.basename(filepath)
|
return os.path.basename(filepath)
|
||||||
|
|
||||||
|
# Function to detect indirect links by parsing .blend files safely
|
||||||
|
def get_indirect_libraries(filepath):
|
||||||
|
"""Get libraries that are linked from within a .blend file"""
|
||||||
|
indirect_libs = set()
|
||||||
|
if not filepath or not os.path.exists(filepath):
|
||||||
|
return indirect_libs
|
||||||
|
|
||||||
|
try:
|
||||||
|
# For now, return empty set to prevent data loss
|
||||||
|
# TODO: Implement safe indirect link detection without modifying scene
|
||||||
|
# The previous approach was dangerous and caused data deletion
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error detecting indirect links in {filepath}: {e}")
|
||||||
|
|
||||||
|
return indirect_libs
|
||||||
|
|
||||||
# Scan all data collections for linked items
|
# Scan all data collections for linked items
|
||||||
all_libraries = set()
|
all_libraries = set()
|
||||||
|
library_info = {} # Store additional info about each library
|
||||||
|
|
||||||
# Check bpy.data.objects
|
# Check bpy.data.objects
|
||||||
for obj in bpy.data.objects:
|
for obj in bpy.data.objects:
|
||||||
@@ -148,12 +167,17 @@ class DYNAMICLINK_OT_scan_linked_assets(Operator):
|
|||||||
if hasattr(node_group, 'library') and node_group.library:
|
if hasattr(node_group, 'library') and node_group.library:
|
||||||
all_libraries.add(node_group.library.filepath)
|
all_libraries.add(node_group.library.filepath)
|
||||||
|
|
||||||
# Now try to detect indirect links by parsing the linked files
|
# Analyze each library for indirect links
|
||||||
# This is a simplified approach - in practice, you'd need to parse .blend files
|
for filepath in all_libraries:
|
||||||
indirect_libraries = set()
|
if filepath:
|
||||||
|
indirect_libs = get_indirect_libraries(filepath)
|
||||||
|
missing_indirect_count = sum(1 for lib in indirect_libs if is_file_missing(lib))
|
||||||
|
|
||||||
# For now, we'll just note that some libraries might have indirect links
|
library_info[filepath] = {
|
||||||
# In a full implementation, you'd parse each .blend file to find its linked libraries
|
'indirect_libraries': indirect_libs,
|
||||||
|
'missing_indirect_count': missing_indirect_count,
|
||||||
|
'has_indirect_missing': missing_indirect_count > 0
|
||||||
|
}
|
||||||
|
|
||||||
# Store results in scene properties
|
# Store results in scene properties
|
||||||
context.scene.dynamic_link_manager.linked_assets_count = len(all_libraries)
|
context.scene.dynamic_link_manager.linked_assets_count = len(all_libraries)
|
||||||
@@ -166,6 +190,15 @@ class DYNAMICLINK_OT_scan_linked_assets(Operator):
|
|||||||
lib_item.name = get_library_name(filepath)
|
lib_item.name = get_library_name(filepath)
|
||||||
lib_item.is_missing = is_file_missing(filepath)
|
lib_item.is_missing = is_file_missing(filepath)
|
||||||
|
|
||||||
|
# Set indirect link information
|
||||||
|
if filepath in library_info:
|
||||||
|
info = library_info[filepath]
|
||||||
|
lib_item.has_indirect_missing = info['has_indirect_missing']
|
||||||
|
lib_item.indirect_missing_count = info['missing_indirect_count']
|
||||||
|
else:
|
||||||
|
lib_item.has_indirect_missing = False
|
||||||
|
lib_item.indirect_missing_count = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Show detailed info
|
# Show detailed info
|
||||||
|
|||||||
86
ui.py
86
ui.py
@@ -12,6 +12,9 @@ class LinkedLibraryItem(PropertyGroup):
|
|||||||
filepath: StringProperty(name="File Path", description="Path to the linked .blend file")
|
filepath: StringProperty(name="File Path", description="Path to the linked .blend file")
|
||||||
name: StringProperty(name="Name", description="Name of the linked .blend file")
|
name: StringProperty(name="Name", description="Name of the linked .blend file")
|
||||||
is_missing: BoolProperty(name="Missing", description="True if the linked file is not found")
|
is_missing: BoolProperty(name="Missing", description="True if the linked file is not found")
|
||||||
|
has_indirect_missing: BoolProperty(name="Has Indirect Missing", description="True if an indirectly linked blend is missing")
|
||||||
|
indirect_missing_count: IntProperty(name="Indirect Missing Count", description="Number of indirectly linked blends that are missing")
|
||||||
|
is_expanded: BoolProperty(name="Expanded", description="Whether this library item is expanded in the UI", default=True)
|
||||||
linked_datablocks: CollectionProperty(type=LinkedDatablockItem, name="Linked Datablocks")
|
linked_datablocks: CollectionProperty(type=LinkedDatablockItem, name="Linked Datablocks")
|
||||||
|
|
||||||
class DynamicLinkManagerProperties(PropertyGroup):
|
class DynamicLinkManagerProperties(PropertyGroup):
|
||||||
@@ -22,6 +25,12 @@ class DynamicLinkManagerProperties(PropertyGroup):
|
|||||||
default=0
|
default=0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
linked_libraries_expanded: BoolProperty(
|
||||||
|
name="Linked Libraries Expanded",
|
||||||
|
description="Whether the linked libraries section is expanded",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
selected_asset_path: StringProperty(
|
selected_asset_path: StringProperty(
|
||||||
name="Selected Asset Path",
|
name="Selected Asset Path",
|
||||||
description="Path to the currently selected asset",
|
description="Path to the currently selected asset",
|
||||||
@@ -47,37 +56,60 @@ class DYNAMICLINK_PT_main_panel(Panel):
|
|||||||
|
|
||||||
# Show more detailed info if we have results
|
# Show more detailed info if we have results
|
||||||
if props.linked_assets_count > 0:
|
if props.linked_assets_count > 0:
|
||||||
box.label(text="Note: Counts unique library files, not individual objects")
|
# Linked Libraries section with single dropdown
|
||||||
|
row = box.row(align=True)
|
||||||
|
|
||||||
# List of linked libraries
|
# Dropdown arrow for the entire section
|
||||||
box.label(text="Linked Libraries:")
|
icon = 'DISCLOSURE_TRI_DOWN' if props.linked_libraries_expanded else 'DISCLOSURE_TRI_RIGHT'
|
||||||
for lib_item in props.linked_libraries:
|
row.prop(props, "linked_libraries_expanded", text="", icon=icon, icon_only=True)
|
||||||
# Create different box styles for missing vs existing libraries
|
|
||||||
if lib_item.is_missing:
|
|
||||||
# Use a red-tinted box for missing libraries
|
|
||||||
sub_box = box.box()
|
|
||||||
sub_box.alert = True # This makes the box have a red tint
|
|
||||||
else:
|
|
||||||
sub_box = box.box()
|
|
||||||
|
|
||||||
# First row: Library name and status
|
# Section header
|
||||||
row1 = sub_box.row(align=True)
|
row.label(text="Linked Libraries:")
|
||||||
if lib_item.is_missing:
|
row.label(text=f"({props.linked_assets_count} libraries)")
|
||||||
row1.label(text=f"MISSING: {lib_item.name}", icon='ERROR')
|
|
||||||
else:
|
|
||||||
row1.label(text=lib_item.name, icon='FILE_BLEND')
|
|
||||||
|
|
||||||
# Second row: File path (full width)
|
# Only show library details if section is expanded
|
||||||
row2 = sub_box.row()
|
if props.linked_libraries_expanded:
|
||||||
row2.label(text=lib_item.filepath, icon='FILE_FOLDER')
|
# List all libraries
|
||||||
|
for i, lib_item in enumerate(props.linked_libraries):
|
||||||
|
# Create a box for each library
|
||||||
|
if lib_item.is_missing or lib_item.has_indirect_missing:
|
||||||
|
sub_box = box.box()
|
||||||
|
sub_box.alert = True # Red tint for missing/indirect missing
|
||||||
|
else:
|
||||||
|
sub_box = box.box()
|
||||||
|
|
||||||
# Third row: Open button
|
# Library name and status
|
||||||
row3 = sub_box.row()
|
row1 = sub_box.row(align=True)
|
||||||
if lib_item.is_missing:
|
row1.label(text=lib_item.name, icon='FILE_BLEND')
|
||||||
open_op = row3.operator("dynamiclink.open_linked_file", text="Open", icon='ERROR')
|
|
||||||
else:
|
# Status indicator
|
||||||
open_op = row3.operator("dynamiclink.open_linked_file", text="Open", icon='FILE_BLEND')
|
if lib_item.is_missing:
|
||||||
open_op.filepath = lib_item.filepath
|
row1.label(text="MISSING", icon='ERROR')
|
||||||
|
elif lib_item.has_indirect_missing:
|
||||||
|
row1.label(text="INDIRECT MISSING", icon='ERROR')
|
||||||
|
|
||||||
|
# File path (truncated for space)
|
||||||
|
row2 = sub_box.row()
|
||||||
|
path_text = lib_item.filepath
|
||||||
|
if len(path_text) > 50:
|
||||||
|
path_text = "..." + path_text[-47:]
|
||||||
|
row2.label(text=path_text, icon='FILE_FOLDER')
|
||||||
|
|
||||||
|
# Warning message for indirect missing
|
||||||
|
if lib_item.has_indirect_missing and not lib_item.is_missing:
|
||||||
|
row3 = sub_box.row()
|
||||||
|
row3.label(text=f"⚠️ {lib_item.indirect_missing_count} indirectly linked blend(s) missing", icon='ERROR')
|
||||||
|
row3.label(text="Open this blend to relink", icon='INFO')
|
||||||
|
|
||||||
|
# Action buttons row
|
||||||
|
row4 = sub_box.row(align=True)
|
||||||
|
|
||||||
|
# Open button
|
||||||
|
if lib_item.is_missing or lib_item.has_indirect_missing:
|
||||||
|
open_op = row4.operator("dynamiclink.open_linked_file", text="Open", icon='ERROR')
|
||||||
|
else:
|
||||||
|
open_op = row4.operator("dynamiclink.open_linked_file", text="Open", icon='FILE_BLEND')
|
||||||
|
open_op.filepath = lib_item.filepath
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user