continue implement FMT UI
This commit is contained in:
@@ -7150,3 +7150,450 @@ The UI now follows FMT's proven design patterns while maintaining our focus on l
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
_**User**_
|
||||||
|
|
||||||
|
excellent! Let's emulate FMT's search paths function and UI directly below that. @c:\Users\Nathan\Downloads\FMT-V3\panels_fmt.py @c:\Users\Nathan\Downloads\FMT-V3\ops_fmt.py @c:\Users\Nathan\Downloads\FMT-V3\__init__.py
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**Assistant**_
|
||||||
|
|
||||||
|
Excellent idea! Let me examine FMT's search paths implementation and adapt it directly for our Dynamic Link Manager. Looking at FMT's code, I can see the key patterns:
|
||||||
|
|
||||||
|
## <20><> **FMT Search Paths Features to Emulate:**
|
||||||
|
|
||||||
|
1. **Search path management** with add/remove functionality
|
||||||
|
2. **Extension replacement** option for different file extensions
|
||||||
|
3. **Folder finding** with recursive search
|
||||||
|
4. **Clean UI layout** with proper button sizing
|
||||||
|
|
||||||
|
Let me update our implementation to match FMT's approach exactly:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The model made no changes to the file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Let me check what the current content looks like and then implement the FMT-style search paths:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Read file: ui.py
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now let me implement the exact FMT-style search paths UI. I'll replace the current search paths section with FMT's approach:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The model made no changes to the file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Let me implement the FMT-style search paths by replacing the entire section with the exact FMT approach:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The model made no changes to the file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I see the issue - the content is identical. Let me implement the FMT-style search paths by adding it as a new section below the current one:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details><summary>Edit file: ui.py</summary>
|
||||||
|
|
||||||
|
undefined
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 31, lines removed: undefined
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -239,4 +239,35 @@
|
||||||
|
row.operator("dynamiclink.attempt_relink", text="Attempt to relink found libraries", icon='FILE_REFRESH')
|
||||||
|
|
||||||
|
+ # FMT-Style Search Paths Management (Direct Copy)
|
||||||
|
+ box = layout.box()
|
||||||
|
+ box.label(text="FMT-Style Search Paths")
|
||||||
|
+
|
||||||
|
+ # Get preferences
|
||||||
|
+ prefs = context.preferences.addons.get(__package__)
|
||||||
|
+ if prefs:
|
||||||
|
+ # Extension replacement option (FMT-style)
|
||||||
|
+ if len(prefs.preferences.search_paths) > 0:
|
||||||
|
+ row = box.row()
|
||||||
|
+ row.prop(props, "search_different_extensions", text="Search for libraries with different extensions")
|
||||||
|
+
|
||||||
|
+ # Search paths list (FMT-style)
|
||||||
|
+ if prefs.preferences.search_paths:
|
||||||
|
+ for i, path_item in enumerate(prefs.preferences.search_paths):
|
||||||
|
+ row = box.row()
|
||||||
|
+ row.prop(path_item, "path", text=f"Search path {i+1}")
|
||||||
|
+ row.operator("dynamiclink.remove_search_path", text="", icon='REMOVE').index = i
|
||||||
|
+
|
||||||
|
+ # Add/remove buttons (FMT-style)
|
||||||
|
+ row = box.row()
|
||||||
|
+ row.operator("dynamiclink.add_search_path", text="Add Search Path", icon='ADD')
|
||||||
|
+ row.operator("dynamiclink.remove_search_path", text="Remove Selected", icon='REMOVE')
|
||||||
|
+
|
||||||
|
+ # Main action button (FMT-style)
|
||||||
|
+ if props.linked_assets_count > 0:
|
||||||
|
+ missing_count = sum(1 for lib in props.linked_libraries if lib.is_missing)
|
||||||
|
+ if missing_count > 0:
|
||||||
|
+ row = box.row()
|
||||||
|
+ row.operator("dynamiclink.find_in_folders", text="Find libraries in these folders", icon='VIEWZOOM')
|
||||||
|
+
|
||||||
|
# Settings section (FMT-style)
|
||||||
|
box = layout.box()
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now let me update the operators to match FMT's approach exactly. Let me update the `find_in_folders` operator to use FMT's logic:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details><summary>Edit file: operators.py</summary>
|
||||||
|
|
||||||
|
undefined
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 1, lines removed: 1
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -371,5 +371,5 @@
|
||||||
|
self.report({'INFO'}, f"Searching for {len(missing_libs)} missing libraries...")
|
||||||
|
|
||||||
|
- # Scan search paths for missing libraries (FMT-inspired approach)
|
||||||
|
+ # FMT-style directory scanning
|
||||||
|
files_dir_list = []
|
||||||
|
try:
|
||||||
|
```
|
||||||
|
|
||||||
|
**Chunk 2**
|
||||||
|
Lines added: 2, lines removed: 1
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -382,9 +382,10 @@
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
- # Try to find each missing library
|
||||||
|
+ # Try to find each missing library (FMT-style)
|
||||||
|
found_count = 0
|
||||||
|
|
||||||
|
for lib_item in missing_libs:
|
||||||
|
lib_filename = os.path.basename(lib_item.filepath)
|
||||||
|
+ found = False
|
||||||
|
|
||||||
|
# Search through all directories
|
||||||
|
```
|
||||||
|
|
||||||
|
**Chunk 3**
|
||||||
|
Lines added: 18, lines removed: undefined
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -397,5 +398,23 @@
|
||||||
|
self.report({'INFO'}, f"Found {lib_filename} at: {new_path}")
|
||||||
|
found_count += 1
|
||||||
|
+ found = True
|
||||||
|
+ break
|
||||||
|
+
|
||||||
|
+ # FMT-style extension replacement
|
||||||
|
+ if context.scene.dynamic_link_manager.search_different_extensions:
|
||||||
|
+ base_name = os.path.splitext(lib_filename)[0]
|
||||||
|
+ for filename in filenames:
|
||||||
|
+ if base_name == os.path.splitext(filename)[0]:
|
||||||
|
+ new_path = os.path.join(dirpath, filename)
|
||||||
|
+ self.report({'INFO'}, f"Found {lib_filename} (as {filename}) at: {new_path}")
|
||||||
|
+ found_count += 1
|
||||||
|
+ found = True
|
||||||
|
+ break
|
||||||
|
+
|
||||||
|
+ if found:
|
||||||
|
break
|
||||||
|
+
|
||||||
|
+ if not found:
|
||||||
|
+ self.report({'WARNING'}, f"Could not find {lib_filename} in search paths")
|
||||||
|
|
||||||
|
if found_count > 0:
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now let me also update the `attempt_relink` operator to use FMT's approach:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details><summary>Edit file: operators.py</summary>
|
||||||
|
|
||||||
|
undefined
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 1, lines removed: 1
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -306,5 +306,5 @@
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
- # Try to find and relink each missing library
|
||||||
|
+ # Try to find and relink each missing library (FMT-style)
|
||||||
|
relinked_count = 0
|
||||||
|
indirect_errors = []
|
||||||
|
```
|
||||||
|
|
||||||
|
**Chunk 2**
|
||||||
|
Lines added: 22, lines removed: undefined
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -335,4 +335,26 @@
|
||||||
|
else:
|
||||||
|
print(f"Error relinking {lib_item.filepath}: {e}")
|
||||||
|
+
|
||||||
|
+ # FMT-style extension replacement
|
||||||
|
+ if not found and context.scene.dynamic_link_manager.search_different_extensions:
|
||||||
|
+ base_name = os.path.splitext(lib_filename)[0]
|
||||||
|
+ for filename in filenames:
|
||||||
|
+ if base_name == os.path.splitext(filename)[0]:
|
||||||
|
+ new_path = os.path.join(dirpath, filename)
|
||||||
|
+ try:
|
||||||
|
+ bpy.ops.file.find_missing_files()
|
||||||
|
+ found = True
|
||||||
|
+ relinked_count += 1
|
||||||
|
+ break
|
||||||
|
+ except Exception as e:
|
||||||
|
+ error_msg = str(e)
|
||||||
|
+ if "unable to relocate indirectly linked library" in error_msg:
|
||||||
|
+ indirect_errors.append(lib_item.filepath)
|
||||||
|
+ print(f"Indirect link detected for: {lib_item.filepath}")
|
||||||
|
+ else:
|
||||||
|
+ print(f"Error relinking {lib_item.filepath}: {e}")
|
||||||
|
+
|
||||||
|
+ if found:
|
||||||
|
+ break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now let me add a new operator inspired by FMT's `TEXTURE_OT_find_in_folder` to provide a more direct FMT experience:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details><summary>Edit file: operators.py</summary>
|
||||||
|
|
||||||
|
undefined
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 65, lines removed: undefined
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -197,4 +197,69 @@
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
+ class DYNAMICLINK_OT_fmt_style_find(Operator):
|
||||||
|
+ """Find missing libraries in search folders using FMT-style approach"""
|
||||||
|
+ bl_idname = "dynamiclink.fmt_style_find"
|
||||||
|
+ bl_label = "FMT-Style Find"
|
||||||
|
+ bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
+
|
||||||
|
+ def execute(self, context):
|
||||||
|
+ prefs = context.preferences.addons.get(__package__)
|
||||||
|
+ if not prefs or not prefs.preferences.search_paths:
|
||||||
|
+ self.report({'ERROR'}, "No search paths configured. Add search paths in addon preferences.")
|
||||||
|
+ return {'CANCELLED'}
|
||||||
|
+
|
||||||
|
+ # Get missing libraries
|
||||||
|
+ missing_libs = [lib for lib in context.scene.dynamic_link_manager.linked_libraries if lib.is_missing]
|
||||||
|
+ if not missing_libs:
|
||||||
|
+ self.report({'INFO'}, "No missing libraries to find")
|
||||||
|
+ return {'FINISHED'}
|
||||||
|
+
|
||||||
|
+ self.report({'INFO'}, f"FMT-style search for {len(missing_libs)} missing libraries...")
|
||||||
|
+
|
||||||
|
+ # FMT-style directory scanning (exact copy of FMT logic)
|
||||||
|
+ files_dir_list = []
|
||||||
|
+ try:
|
||||||
|
+ for search_path in prefs.preferences.search_paths:
|
||||||
|
+ if search_path.path:
|
||||||
|
+ for dirpath, dirnames, filenames in os.walk(bpy.path.abspath(search_path.path)):
|
||||||
|
+ files_dir_list.append([dirpath, filenames])
|
||||||
|
+ except FileNotFoundError:
|
||||||
|
+ self.report({'ERROR'}, f"Error - Bad file path in search paths")
|
||||||
|
+ return {'CANCELLED'}
|
||||||
|
+
|
||||||
|
+ # FMT-style library finding
|
||||||
|
+ found_count = 0
|
||||||
|
+
|
||||||
|
+ for lib_item in missing_libs:
|
||||||
|
+ lib_filename = os.path.basename(lib_item.filepath)
|
||||||
|
+
|
||||||
|
+ for dir_info in files_dir_list:
|
||||||
|
+ dirpath, filenames = dir_info
|
||||||
|
+
|
||||||
|
+ # Exact filename match
|
||||||
|
+ if lib_filename in filenames:
|
||||||
|
+ new_path = os.path.join(dirpath, lib_filename)
|
||||||
|
+ self.report({'INFO'}, f"Found {lib_filename} at: {new_path}")
|
||||||
|
+ found_count += 1
|
||||||
|
+ break
|
||||||
|
+
|
||||||
|
+ # Extension replacement (FMT-style)
|
||||||
|
+ elif context.scene.dynamic_link_manager.search_different_extensions:
|
||||||
|
+ base_name = os.path.splitext(lib_filename)[0]
|
||||||
|
+ for filename in filenames:
|
||||||
|
+ if base_name == os.path.splitext(filename)[0]:
|
||||||
|
+ new_path = os.path.join(dirpath, filename)
|
||||||
|
+ self.report({'INFO'}, f"Found {lib_filename} (as {filename}) at: {new_path}")
|
||||||
|
+ found_count += 1
|
||||||
|
+ break
|
||||||
|
+
|
||||||
|
+ # FMT-style reporting
|
||||||
|
+ if found_count > 0:
|
||||||
|
+ self.report({'INFO'}, f"FMT-style search complete: Found {found_count} libraries")
|
||||||
|
+ else:
|
||||||
|
+ self.report({'WARNING'}, "FMT-style search: No libraries found in search paths")
|
||||||
|
+
|
||||||
|
+ return {'FINISHED'}
|
||||||
|
+
|
||||||
|
def register():
|
||||||
|
bpy.utils.register_class(DYNAMICLINK_OT_replace_linked_asset)
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now let me register this new operator:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details><summary>Edit file: operators.py</summary>
|
||||||
|
|
||||||
|
undefined
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 1, lines removed: undefined
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -520,4 +520,5 @@
|
||||||
|
bpy.utils.register_class(DYNAMICLINK_OT_attempt_relink)
|
||||||
|
bpy.utils.register_class(DYNAMICLINK_OT_find_in_folders)
|
||||||
|
+ bpy.utils.register_class(DYNAMICLINK_OT_fmt_style_find)
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
And add it to the unregister function:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details><summary>Edit file: operators.py</summary>
|
||||||
|
|
||||||
|
undefined
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 1, lines removed: undefined
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -523,4 +523,5 @@
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
+ bpy.utils.unregister_class(DYNAMICLINK_OT_fmt_style_find)
|
||||||
|
bpy.utils.unregister_class(DYNAMICLINK_OT_find_in_folders)
|
||||||
|
bpy.utils.unregister_class(DYNAMICLINK_OT_attempt_relink)
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now let me update the UI to use the new FMT-style find operator:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details><summary>Edit file: ui.py</summary>
|
||||||
|
|
||||||
|
undefined
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 1, lines removed: 1
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -268,5 +268,5 @@
|
||||||
|
if missing_count > 0:
|
||||||
|
row = box.row()
|
||||||
|
- row.operator("dynamiclink.find_in_folders", text="Find libraries in these folders", icon='VIEWZOOM')
|
||||||
|
+ row.operator("dynamiclink.fmt_style_find", text="Find libraries in these folders", icon='VIEWZOOM')
|
||||||
|
|
||||||
|
# Settings section (FMT-style)
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Perfect! Now I've successfully implemented FMT's search paths functionality and UI directly in our Dynamic Link Manager. Here's what we've accomplished:
|
||||||
|
|
||||||
|
## <20><> **FMT-Style Search Paths Implementation:**
|
||||||
|
|
||||||
|
### **1. Direct FMT UI Copy:**
|
||||||
|
- **"FMT-Style Search Paths"** section - Exact replica of FMT's approach
|
||||||
|
- **Extension replacement checkbox** - "Search for libraries with different extensions"
|
||||||
|
- **Search path management** - Add/remove with proper icons
|
||||||
|
- **Main action button** - "Find libraries in these folders" with magnifying glass icon
|
||||||
|
|
||||||
|
### **2. FMT-Style Operators:**
|
||||||
|
- **`DYNAMICLINK_OT_fmt_style_find`** - Direct copy of FMT's folder finding logic
|
||||||
|
- **Extension replacement** - Looks for files with same base name but different extensions
|
||||||
|
- **Recursive directory scanning** - Uses `os.walk()` like FMT
|
||||||
|
- **FMT-style reporting** - Clear success/warning messages
|
||||||
|
|
||||||
|
### **3. Enhanced Search Logic:**
|
||||||
|
- **Exact filename matching** - Primary search method
|
||||||
|
- **Extension flexibility** - Finds `.blend1`, `.blend2`, etc. when enabled
|
||||||
|
- **Comprehensive scanning** - Searches all subdirectories in search paths
|
||||||
|
- **Smart reporting** - Shows exactly what was found and where
|
||||||
|
|
||||||
|
### **4. UI Layout (FMT-Style):**
|
||||||
|
- **Clean section organization** - Boxed sections with clear labels
|
||||||
|
- **Proper button sizing** - Uses FMT's approach to button layout
|
||||||
|
- **Icon integration** - Meaningful icons for different actions
|
||||||
|
- **Status feedback** - Clear indication of search results
|
||||||
|
|
||||||
|
## 🔄 **New FMT-Style Workflow:**
|
||||||
|
|
||||||
|
1. **Configure Search Paths** - Add directories to search in
|
||||||
|
2. **Enable Extension Search** - Check "Search for libraries with different extensions"
|
||||||
|
3. **Scan Libraries** - Find missing linked libraries
|
||||||
|
4. **FMT-Style Search** - Click "Find libraries in these folders"
|
||||||
|
5. **View Results** - See exactly what was found and where
|
||||||
|
6. **Attempt Relinking** - Use found libraries to fix missing links
|
||||||
|
|
||||||
|
The addon now provides both the original functionality and a direct FMT-style experience for search path management and library finding. Users can choose between the comprehensive approach and the familiar FMT workflow they're used to!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|||||||
114
operators.py
114
operators.py
@@ -196,6 +196,71 @@ class DYNAMICLINK_OT_scan_linked_assets(Operator):
|
|||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class DYNAMICLINK_OT_fmt_style_find(Operator):
|
||||||
|
"""Find missing libraries in search folders using FMT-style approach"""
|
||||||
|
bl_idname = "dynamiclink.fmt_style_find"
|
||||||
|
bl_label = "FMT-Style Find"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
prefs = context.preferences.addons.get(__package__)
|
||||||
|
if not prefs or not prefs.preferences.search_paths:
|
||||||
|
self.report({'ERROR'}, "No search paths configured. Add search paths in addon preferences.")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
# Get missing libraries
|
||||||
|
missing_libs = [lib for lib in context.scene.dynamic_link_manager.linked_libraries if lib.is_missing]
|
||||||
|
if not missing_libs:
|
||||||
|
self.report({'INFO'}, "No missing libraries to find")
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
self.report({'INFO'}, f"FMT-style search for {len(missing_libs)} missing libraries...")
|
||||||
|
|
||||||
|
# FMT-style directory scanning (exact copy of FMT logic)
|
||||||
|
files_dir_list = []
|
||||||
|
try:
|
||||||
|
for search_path in prefs.preferences.search_paths:
|
||||||
|
if search_path.path:
|
||||||
|
for dirpath, dirnames, filenames in os.walk(bpy.path.abspath(search_path.path)):
|
||||||
|
files_dir_list.append([dirpath, filenames])
|
||||||
|
except FileNotFoundError:
|
||||||
|
self.report({'ERROR'}, f"Error - Bad file path in search paths")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
# FMT-style library finding
|
||||||
|
found_count = 0
|
||||||
|
|
||||||
|
for lib_item in missing_libs:
|
||||||
|
lib_filename = os.path.basename(lib_item.filepath)
|
||||||
|
|
||||||
|
for dir_info in files_dir_list:
|
||||||
|
dirpath, filenames = dir_info
|
||||||
|
|
||||||
|
# Exact filename match
|
||||||
|
if lib_filename in filenames:
|
||||||
|
new_path = os.path.join(dirpath, lib_filename)
|
||||||
|
self.report({'INFO'}, f"Found {lib_filename} at: {new_path}")
|
||||||
|
found_count += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# Extension replacement (FMT-style)
|
||||||
|
elif context.scene.dynamic_link_manager.search_different_extensions:
|
||||||
|
base_name = os.path.splitext(lib_filename)[0]
|
||||||
|
for filename in filenames:
|
||||||
|
if base_name == os.path.splitext(filename)[0]:
|
||||||
|
new_path = os.path.join(dirpath, filename)
|
||||||
|
self.report({'INFO'}, f"Found {lib_filename} (as {filename}) at: {new_path}")
|
||||||
|
found_count += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# FMT-style reporting
|
||||||
|
if found_count > 0:
|
||||||
|
self.report({'INFO'}, f"FMT-style search complete: Found {found_count} libraries")
|
||||||
|
else:
|
||||||
|
self.report({'WARNING'}, "FMT-style search: No libraries found in search paths")
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
bpy.utils.register_class(DYNAMICLINK_OT_replace_linked_asset)
|
bpy.utils.register_class(DYNAMICLINK_OT_replace_linked_asset)
|
||||||
bpy.utils.register_class(DYNAMICLINK_OT_scan_linked_assets)
|
bpy.utils.register_class(DYNAMICLINK_OT_scan_linked_assets)
|
||||||
@@ -305,7 +370,7 @@ class DYNAMICLINK_OT_attempt_relink(Operator):
|
|||||||
self.report({'ERROR'}, f"Error - Bad file path in search paths")
|
self.report({'ERROR'}, f"Error - Bad file path in search paths")
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
# Try to find and relink each missing library
|
# Try to find and relink each missing library (FMT-style)
|
||||||
relinked_count = 0
|
relinked_count = 0
|
||||||
indirect_errors = []
|
indirect_errors = []
|
||||||
|
|
||||||
@@ -335,6 +400,28 @@ class DYNAMICLINK_OT_attempt_relink(Operator):
|
|||||||
else:
|
else:
|
||||||
print(f"Error relinking {lib_item.filepath}: {e}")
|
print(f"Error relinking {lib_item.filepath}: {e}")
|
||||||
|
|
||||||
|
# FMT-style extension replacement
|
||||||
|
if not found and context.scene.dynamic_link_manager.search_different_extensions:
|
||||||
|
base_name = os.path.splitext(lib_filename)[0]
|
||||||
|
for filename in filenames:
|
||||||
|
if base_name == os.path.splitext(filename)[0]:
|
||||||
|
new_path = os.path.join(dirpath, filename)
|
||||||
|
try:
|
||||||
|
bpy.ops.file.find_missing_files()
|
||||||
|
found = True
|
||||||
|
relinked_count += 1
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = str(e)
|
||||||
|
if "unable to relocate indirectly linked library" in error_msg:
|
||||||
|
indirect_errors.append(lib_item.filepath)
|
||||||
|
print(f"Indirect link detected for: {lib_item.filepath}")
|
||||||
|
else:
|
||||||
|
print(f"Error relinking {lib_item.filepath}: {e}")
|
||||||
|
|
||||||
|
if found:
|
||||||
|
break
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
print(f"Could not find {lib_filename} in search paths")
|
print(f"Could not find {lib_filename} in search paths")
|
||||||
|
|
||||||
@@ -370,7 +457,7 @@ class DYNAMICLINK_OT_find_in_folders(Operator):
|
|||||||
|
|
||||||
self.report({'INFO'}, f"Searching for {len(missing_libs)} missing libraries...")
|
self.report({'INFO'}, f"Searching for {len(missing_libs)} missing libraries...")
|
||||||
|
|
||||||
# Scan search paths for missing libraries (FMT-inspired approach)
|
# FMT-style directory scanning
|
||||||
files_dir_list = []
|
files_dir_list = []
|
||||||
try:
|
try:
|
||||||
for search_path in prefs.preferences.search_paths:
|
for search_path in prefs.preferences.search_paths:
|
||||||
@@ -381,11 +468,12 @@ class DYNAMICLINK_OT_find_in_folders(Operator):
|
|||||||
self.report({'ERROR'}, f"Error - Bad file path in search paths")
|
self.report({'ERROR'}, f"Error - Bad file path in search paths")
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
# Try to find each missing library
|
# Try to find each missing library (FMT-style)
|
||||||
found_count = 0
|
found_count = 0
|
||||||
|
|
||||||
for lib_item in missing_libs:
|
for lib_item in missing_libs:
|
||||||
lib_filename = os.path.basename(lib_item.filepath)
|
lib_filename = os.path.basename(lib_item.filepath)
|
||||||
|
found = False
|
||||||
|
|
||||||
# Search through all directories
|
# Search through all directories
|
||||||
for dir_info in files_dir_list:
|
for dir_info in files_dir_list:
|
||||||
@@ -396,8 +484,26 @@ class DYNAMICLINK_OT_find_in_folders(Operator):
|
|||||||
new_path = os.path.join(dirpath, lib_filename)
|
new_path = os.path.join(dirpath, lib_filename)
|
||||||
self.report({'INFO'}, f"Found {lib_filename} at: {new_path}")
|
self.report({'INFO'}, f"Found {lib_filename} at: {new_path}")
|
||||||
found_count += 1
|
found_count += 1
|
||||||
|
found = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# FMT-style extension replacement
|
||||||
|
if context.scene.dynamic_link_manager.search_different_extensions:
|
||||||
|
base_name = os.path.splitext(lib_filename)[0]
|
||||||
|
for filename in filenames:
|
||||||
|
if base_name == os.path.splitext(filename)[0]:
|
||||||
|
new_path = os.path.join(dirpath, filename)
|
||||||
|
self.report({'INFO'}, f"Found {lib_filename} (as {filename}) at: {new_path}")
|
||||||
|
found_count += 1
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if found:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
self.report({'WARNING'}, f"Could not find {lib_filename} in search paths")
|
||||||
|
|
||||||
if found_count > 0:
|
if found_count > 0:
|
||||||
self.report({'INFO'}, f"Found {found_count} libraries in search paths")
|
self.report({'INFO'}, f"Found {found_count} libraries in search paths")
|
||||||
else:
|
else:
|
||||||
@@ -413,8 +519,10 @@ def register():
|
|||||||
bpy.utils.register_class(DYNAMICLINK_OT_remove_search_path)
|
bpy.utils.register_class(DYNAMICLINK_OT_remove_search_path)
|
||||||
bpy.utils.register_class(DYNAMICLINK_OT_attempt_relink)
|
bpy.utils.register_class(DYNAMICLINK_OT_attempt_relink)
|
||||||
bpy.utils.register_class(DYNAMICLINK_OT_find_in_folders)
|
bpy.utils.register_class(DYNAMICLINK_OT_find_in_folders)
|
||||||
|
bpy.utils.register_class(DYNAMICLINK_OT_fmt_style_find)
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
|
bpy.utils.unregister_class(DYNAMICLINK_OT_fmt_style_find)
|
||||||
bpy.utils.unregister_class(DYNAMICLINK_OT_find_in_folders)
|
bpy.utils.unregister_class(DYNAMICLINK_OT_find_in_folders)
|
||||||
bpy.utils.unregister_class(DYNAMICLINK_OT_attempt_relink)
|
bpy.utils.unregister_class(DYNAMICLINK_OT_attempt_relink)
|
||||||
bpy.utils.unregister_class(DYNAMICLINK_OT_remove_search_path)
|
bpy.utils.unregister_class(DYNAMICLINK_OT_remove_search_path)
|
||||||
|
|||||||
31
ui.py
31
ui.py
@@ -238,6 +238,37 @@ class DYNAMICLINK_PT_main_panel(Panel):
|
|||||||
row = box.row()
|
row = box.row()
|
||||||
row.operator("dynamiclink.attempt_relink", text="Attempt to relink found libraries", icon='FILE_REFRESH')
|
row.operator("dynamiclink.attempt_relink", text="Attempt to relink found libraries", icon='FILE_REFRESH')
|
||||||
|
|
||||||
|
# FMT-Style Search Paths Management (Direct Copy)
|
||||||
|
box = layout.box()
|
||||||
|
box.label(text="FMT-Style Search Paths")
|
||||||
|
|
||||||
|
# Get preferences
|
||||||
|
prefs = context.preferences.addons.get(__package__)
|
||||||
|
if prefs:
|
||||||
|
# Extension replacement option (FMT-style)
|
||||||
|
if len(prefs.preferences.search_paths) > 0:
|
||||||
|
row = box.row()
|
||||||
|
row.prop(props, "search_different_extensions", text="Search for libraries with different extensions")
|
||||||
|
|
||||||
|
# Search paths list (FMT-style)
|
||||||
|
if prefs.preferences.search_paths:
|
||||||
|
for i, path_item in enumerate(prefs.preferences.search_paths):
|
||||||
|
row = box.row()
|
||||||
|
row.prop(path_item, "path", text=f"Search path {i+1}")
|
||||||
|
row.operator("dynamiclink.remove_search_path", text="", icon='REMOVE').index = i
|
||||||
|
|
||||||
|
# Add/remove buttons (FMT-style)
|
||||||
|
row = box.row()
|
||||||
|
row.operator("dynamiclink.add_search_path", text="Add Search Path", icon='ADD')
|
||||||
|
row.operator("dynamiclink.remove_search_path", text="Remove Selected", icon='REMOVE')
|
||||||
|
|
||||||
|
# Main action button (FMT-style)
|
||||||
|
if props.linked_assets_count > 0:
|
||||||
|
missing_count = sum(1 for lib in props.linked_libraries if lib.is_missing)
|
||||||
|
if missing_count > 0:
|
||||||
|
row = box.row()
|
||||||
|
row.operator("dynamiclink.fmt_style_find", text="Find libraries in these folders", icon='VIEWZOOM')
|
||||||
|
|
||||||
# Settings section (FMT-style)
|
# Settings section (FMT-style)
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
box.label(text="Settings")
|
box.label(text="Settings")
|
||||||
|
|||||||
Reference in New Issue
Block a user