Hello,
I’have lately been using more linked objects/collections than before, and while one usually knows the directory or can go to/find it pretty easy from memory, its a different story when looking up files from e.g. a network drive or re-opening older files.
I kind of felt the need to more easily acces the source path of the library from within the outliner>File Mode, or other parts in the interface. I came up with and added this operator to the context menu in the Outliner:
It just opens a explorer window and selects the file in question - but does not open the .blend.
import bpy
import os
import subprocess
from bpy.types import (
Collection,
Panel,
Operator,
PropertyGroup)
from bpy.props import (StringProperty, EnumProperty, IntProperty,
FloatProperty, BoolProperty, PointerProperty)
debugging = False
def explorer_on_file(url):
#opens a windows explorer window """
subprocess.Popen(f'explorer /select,"{url}"')
class Open_Directory(Operator):
bl_label = "Open Directory"
bl_idname = "open.directory"
bl_description = "Opens a new explorer window of the source directory"
path: bpy.props.StringProperty(name="Path Argument", default="")
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
# Validate if path exists
if not os.path.exists(self.path):
self.report({'WARNING'}, 'Path/File does not exist anymore')
print(f'path {self.path} does not exist')
return {'FINISHED'}
# check if path is not None and then Open
if self.path != '':
# opens file and selects it
explorer_on_file(self.path)
print ("Opening directory: " + self.path) if debugging else None
self.report({'INFO'}, f' Opened: {self.path}')
return {'FINISHED'}
def draw_open_directory(self, context):
global debugging
selected_item = context.selected_ids[0] if context.selected_ids else None
#print(str(selected_item))
#print(selected_item.name)
def is_linked_library(item):
# Check if the string representation contains the text "Library" ### Rough Workaround
return "Library" in str(item)[:20], bpy.path.abspath(getattr(item, 'filepath', None))
if selected_item:
is_linked = is_linked_library(selected_item)[0]
directory_path = is_linked_library(selected_item)[1]
print(f"Is linked library: {is_linked}") if debugging else None
print (directory_path) if debugging else None
if is_linked == True:
op = self.layout.operator("open.directory", icon='FILE_FOLDER', text='Open Source').path = directory_path
def register():
bpy.utils.register_class(Open_Directory)
bpy.types.OUTLINER_MT_context_menu.prepend(draw_open_directory)
def unregister():
bpy.utils.unregister_class(Open_Directory)
bpy.types.OUTLINER_MT_context_menu.remove(draw_open_directory)
if __name__ == "__main__":
register()
Here is my question, i’m a novice scripter and wasn’t able to somehow get the type of the active item in the outliner, however:
context.selected_ids[0]
Outputs a struct that contains the type as a string, so i’ve used:
# Check if the string representation contains the text "Library" ### Rough Workaround
return "Library" in str(item)[:20]
as a validation to check if the operator should be displayed or not. This works, but is more than likely not the correct way to handle this. What would be a better way to tackle this? Is there already a more accessible solution available?
If i want to take this further than a startup script, would this code be something that needed to be implemented as C++, or could it remain as a python script? If this is not some random edge case i’d get my feet wet and love to help add it to the main branch.
I’ve also made the same functions available from the Object>Instancing Panel together with a simple label that shows the filepath, but cut out the code from here since it differs a bit, also checks if its a linked object or collection etc.